Problem/Motivation

I was testing #2443119: Views preview not working for REST display and noticed that I could not auto-preview the display when adding a new display that requires a path.

Uncaught PHP Exception Symfony\Component\Routing\Exception\RouteNotFoundException: "Route "views.content.page_2" does not exist." at /var/www/html/d8.local/drupal/core/lib/Drupal/Core/Routing/RouteProvider.php line 145

When I applied the patch in #2443119: Views preview not working for REST display the error looks like this:

Uncaught PHP Exception Symfony\Component\Routing\Exception\RouteNotFoundException: "Route "view.content.page_2" does not exist." at /var/www/html/d8.local/drupal/core/lib/Drupal/Core/Routing/RouteProvider.php line 145

Steps to reproduce

  1. Go to Structure -> Views
  2. Edit view Content
  3. Add display (e.g. Page) that needs a path
  4. Provide path to display
  5. (Auto-)Preview

Proposed resolution

Remaining tasks

discuss
write patch
write tests
review

User interface changes

make it possible to preview the newly created display without having to save the display first

API changes

none

CommentFileSizeAuthor
#51 interdiff-40-44.txt687 bytesmpdonadio
#51 views_preview_not-2446783-44.patch4.36 KBmpdonadio
#51 views_preview_not-2446783-test-only.patch2.27 KBmpdonadio
#44 interdiff-40-44.txt687 bytesmpdonadio
#44 views_preview_not-2446783-44.patch4.36 KBmpdonadio
#44 views_preview_not-2446783-test-only.patch2.27 KBmpdonadio
#40 interdiff-38-40.txt1.09 KBmpdonadio
#40 views_preview_not-2446783-40.patch4.81 KBmpdonadio
#40 views_preview_not-2446783-test-only.patch2.27 KBmpdonadio
#38 interdiff-32-38.txt1.59 KBmpdonadio
#38 views_preview_not-2446783-38.patch4.43 KBmpdonadio
#32 interdiff-29-32.txt2.72 KBmpdonadio
#32 views_preview_not-2446783-32.patch4.25 KBmpdonadio
#32 views_preview_not-2446783-test-only.patch1.89 KBmpdonadio
#29 interdiff-24-29.txt499 bytesmpdonadio
#29 views_preview_not-2446783-29.patch4.61 KBmpdonadio
#24 interdiff-21-24.txt2.49 KBmpdonadio
#24 views_preview_not-2446783-24.patch4.71 KBmpdonadio
#24 views_preview_not-2446783-test-only.patch1.5 KBmpdonadio
#21 interdiff-18-21.txt1.04 KBmpdonadio
#21 views_preview_not-2446783-21.patch3.85 KBmpdonadio
#21 views_preview_not-2446783-test-only.patch1.5 KBmpdonadio
#18 interdiff-15-18.txt2.27 KBmpdonadio
#18 views_preview_not-2446783-18.patch4 KBmpdonadio
#18 views_preview_not-2446783-test-only.patch1.65 KBmpdonadio
#15 interdiff-12-15.txt1.72 KBmpdonadio
#15 views_preview_not-2446783-15.patch4.07 KBmpdonadio
#15 2446783-test-only.patch1.72 KBmpdonadio
#12 interdiff-10-12.txt1.09 KBmpdonadio
#12 views_preview_not-2446783-12.patch2.35 KBmpdonadio
#10 views_preview_not-2446783-10.patch1.8 KBmpdonadio
#8 views_preview_not-2446783-8.patch1.83 KBmpdonadio
#5 views_preview_not-2446783-5.patch2.14 KBmpdonadio

Comments

dawehner’s picture

Sent this issue to mpdonadio

mpdonadio’s picture

Assigned: Unassigned » mpdonadio
Status: Active » Needs work

OK, I can reproduce this, but haven't managed to get a full stack trace to see exact where this is barfing (I assume its the getUrl in ViewUI::renderPreview()). I suspect it will also happen when you change the display ID.

I see three options here.

1. Disable preview for unsaved view displays.
2. Autosave the route info when you set the path.
3. Have a special route for unsaved page displays that gets used for previews.

Or maybe we just need to add some try/catch in this method?

I'll play with this.

dawehner’s picture

Thank you!!

mpdonadio’s picture

OK, here is an initial assessment

ViewsForm::buildForm() and ViewsExposedForm::buildForm() both have

$form['#action'] = $view->hasUrl() ? $view->getUrl()->toString() : Url::fromRoute('<current>')->toString();

in them (and ViewsForm.php is missing a use for Url, which causes an additional fatal...) So, I think we need to update ViewExecutable::hasUrl() to check to see if $display_id has actually been saved or not.

Then ViewUI::renderPreview() has a \Drupal::l($path->toString()) in it. So, we need to adjust the logic to see if the $view has been saved or not.

If i put in hacks around those three places, the preview renders out.

mpdonadio’s picture

Status: Needs work » Needs review
Issue tags: +Needs tests
StatusFileSize
new2.14 KB

First pass at an ugly fix.

Status: Needs review » Needs work

The last submitted patch, 5: views_preview_not-2446783-5.patch, failed testing.

dawehner’s picture

@mpdonadio
I guess we should add a new field to displays on View, which simply indicates whether the display is new.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new1.83 KB

Having trouble with a version that tracks isNew through the whole process. Also, I am not sure if just tracking isNew is sufficient. If you change the machine name for a display in the UI (ie, the $display_id) and then preview, the old machine name is used in the route name for the live preview (which is what is also currently in the route table). After you save, the new route name gets used. I am not sure if this is a bug, and accident, or by design.

This is a version that uses the undocumented $view->changed and $view->live_preview variables. I am thinking that in DisplayPluginBase::initDisplay(), we could also track whether the display has changed?

(a few min goes by).

OK, I have already uploaded the patch and written this out, but it looks like $view->changed will never be set to TRUE in DisplayPluginBase::initDisplay(), and that whether the view has changed or not is actually tracked by the ViewUI class.

Status: Needs review » Needs work

The last submitted patch, 8: views_preview_not-2446783-8.patch, failed testing.

mpdonadio’s picture

StatusFileSize
new1.8 KB

Straight reroll of #8 so I can post a clean interdiff.

@dawehner, do you think this approach or the one in #5 is good, or should I still pursue adding isNew()?

dawehner’s picture

Its tricky. In general I prefer explicit code over implicit code ... so in this case I would prefer you rapproach in #10.
On top of that though it might be still valuable to not fatal under any circumstances.

mpdonadio’s picture

StatusFileSize
new2.35 KB
new1.09 KB

This fixes the situation in the IS. Still need to cobble together a test. Is an AJAX thing like this testable w/ Simpletest?

mpdonadio’s picture

Status: Needs work » Needs review

Feed the TestBot or it gets cranky when its blood sugar gets low.

The last submitted patch, 10: views_preview_not-2446783-10.patch, failed testing.

mpdonadio’s picture

StatusFileSize
new1.72 KB
new4.07 KB
new1.72 KB

If you run the test-only patch via the UI or run-tests.sh in verbose mode, you see the 500 w/ the exception:

[20-Mar-2015 01:50:55 Europe/Berlin] Uncaught PHP Exception Symfony\Component\Routing\Exception\RouteNotFoundException: "Route "view.content.page_2" does not exist." at /Applications/MAMP/htdocs/drupal-8.0.x/core/lib/Drupal/Core/Routing/RouteProvider.php line 128

The last submitted patch, 15: 2446783-test-only.patch, failed testing.

tim.plunkett’s picture

Issue tags: -Needs tests

Since this is a new file, I can nitpick more

  1. +++ b/core/modules/views/src/Tests/PreviewTest.php
    @@ -0,0 +1,68 @@
    + * Definition of Drupal\views\Tests\BasicTest.
    

    Contains \Drupal

  2. +++ b/core/modules/views/src/Tests/PreviewTest.php
    @@ -0,0 +1,68 @@
    +  /**
    +   * Modules to enable.
    +   *
    +   * @var array
    +   */
    ...
    +  protected function setUp() {
    

    Both of these can use {@inheritdoc}

  3. +++ b/core/modules/views/src/Tests/PreviewTest.php
    @@ -0,0 +1,68 @@
    +  public static $modules = array('node', 'views_ui');
    ...
    +  public static $testViews = array();
    

    Here and throughout, might as well use []

Once that's done I can manually test and RTBC tomorrow.

@mpdonadio++

mpdonadio’s picture

Assigned: mpdonadio » Unassigned
StatusFileSize
new1.65 KB
new4 KB
new2.27 KB

Addressed #17, made some comments read more better, and brought the test more in line with how the other Views tests work re setup.

The array() habit is going to be a hard one to break...

The last submitted patch, 18: views_preview_not-2446783-test-only.patch, failed testing.

dawehner’s picture

  1. +++ b/core/modules/views/src/Tests/PreviewTest.php
    @@ -0,0 +1,66 @@
    +class PreviewTest extends ViewTestBase {
    

    Note: We could extend UiTestBase and save a couple of lines in this file, like creating the admin user

  2. +++ b/core/modules/views/src/Tests/PreviewTest.php
    @@ -0,0 +1,66 @@
    +  /**
    +   * {@inheritdoc}
    +   */
    +  protected function setUp() {
    +    parent::setUp();
    +  }
    +
    

    This is redundant ...

mpdonadio’s picture

#20-1 yup, missed that when I was cleaning things up. Also got rid of a unneeded use and a permission that isn't needed.

#20-2. The views_test_data module interferes with the test when I use UITestBase:

Argument 1 passed to views_test_data_views_form_substitutions() must be an instance of Drupal\views\ViewExecutable, none given

Not sure what is up with that, but I suspect it has to do with this test using a view from the node module (because that is the view from the original bug report), and not the test views.

The last submitted patch, 21: views_preview_not-2446783-test-only.patch, failed testing.

dawehner’s picture

+++ b/core/modules/views/src/Tests/PreviewTest.php
@@ -0,0 +1,57 @@
+ */
+class PreviewTest extends ViewTestBase {
+
...
+    }
+
+    $admin_user = $this->drupalCreateUser(['administer views']);
+    $this->drupalLogin($admin_user);
+

This is IMHO a clear UI test, isn't it, so I think we should use the UiTestBase and move it to core/modules/views_ui/src/Tests

mpdonadio’s picture

OK, moved the test to views_ui and changed parent class. The hooks in views_test_data.module interfere with this test (see my comment in #21, so I tweaked the parent setUp to add a flag to enable this or not.

The last submitted patch, 24: views_preview_not-2446783-test-only.patch, failed testing.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
  1. +++ b/core/modules/views/src/ViewExecutable.php
    @@ -436,6 +436,23 @@ class ViewExecutable implements \Serializable {
    +   * If the view is currently being used for a live preview from the UI.
    +   *
    +   * @var bool
    +   */
    +  public $live_preview = FALSE;
    +
    +  /**
    +   * If the view has been changed.
    +   *
    +   * @todo It is unclear whether this is actually used, both within the class
    +   *   and outside.
    +   *
    +   * @var bool
    +   */
    +  public $changed = FALSE;
    +
    

    At least we have documented these public variables now ... though, for sure, it would be great if we could get rid of them at some point, maybe in 9.0.x :P

  2. +++ b/core/modules/views_ui/src/Tests/UnsavedPreviewTest.php
    @@ -0,0 +1,56 @@
    + */
    +class UnsavedPreviewTest extends UITestBase {
    +
    

    Thank you!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/src/ViewExecutable.php
@@ -436,6 +436,23 @@ class ViewExecutable implements \Serializable {
+   * @todo It is unclear whether this is actually used, both within the class
+   *   and outside.

What are we to do? A bit of searching views_ui and you can see this is used. For example:

      if (empty($view->changed)) {
        $form['changed']['#attributes']['class'][] = 'js-hide';
      }
mpdonadio’s picture

I'll remove the @todo later today. That example did not turn up when I had searched, only uses limited to a single method.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new4.61 KB
new499 bytes

The @todo is gone. Searching (and not relying just on Find Usages b/c the view isn't always type hinted) turned up several legitimate usages.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

and not relying just on Find Usages b/c the view isn't always type hinted

I'd like that we add more and more over time, but sure, we'll never tackle all of them.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/views/src/ViewExecutable.php
    @@ -1756,6 +1770,14 @@ public function hasUrl($args = NULL, $display_id = NULL) {
    +    if (!empty($this->live_preview)) {
    +      return FALSE;
    +    }
    +
    +    if (!empty($this->changed)) {
    +      return FALSE;
    +    }
    

    It would be nice to have a comment here as to why these need to be checked whilst calling the hasUrl() method.

  2. +++ b/core/modules/views_ui/src/Tests/UITestBase.php
    @@ -35,10 +35,18 @@
    +  /**
    +   * Sets up a Drupal site for running functional and integration tests.
    +   *
    +   * @param boolean $enable_views_test_module
    +   *   Whether views_test_data.module should be enabled or not.
    +   */
    +  protected function setUp($enable_views_test_module = TRUE) {
         parent::setUp();
     
    -    $this->enableViewsTestModule();
    +    if ($enable_views_test_module) {
    +      $this->enableViewsTestModule();
    +    }
    
    +++ b/core/modules/views_ui/src/Tests/UnsavedPreviewTest.php
    @@ -0,0 +1,56 @@
    +class UnsavedPreviewTest extends UITestBase {
    

    Let's just extend ViewTestBase and then we don't have to make the changes to UITestBase

+++ b/core/modules/views_ui/src/ViewUI.php
@@ -598,7 +598,7 @@ public function renderPreview($display_id, $args = array()) {
+      if ($executable->hasUrl() && $executable->display_handler->getOption('path')) {
         $path = $executable->getUrl();
       }

Can $path = $executable->getUrl() ever be hit - $executable->live_preview is set to TRUE at the beginning of this method.

mpdonadio’s picture

OK, #31 should be addressed. Talked to @dawehner in IRC, and we want the test to still live in views_ui.

Yes, `$path = $executable->getUrl()` gets reached. Verified with debug.

I'm still not fully convinced that $view->changed is propagated everywhere it needs to be, but I left it in the code. If the view has changed, one or more displays may not have valid routes yet. We can file a followup for this.

mpdonadio’s picture

Status: Needs work » Needs review

Blerg.

The last submitted patch, 32: views_preview_not-2446783-test-only.patch, failed testing.

alexpott’s picture

@mpdonadio but how is that line being hit we set $executable->live_preview = TRUE; just above so $executable->hasUrl() should be returning FALSE - or am I mad?

mpdonadio’s picture

Status: Needs review » Needs work

@alexpott, my bad. I misread your last comment in #31. You are correct, `$executable->hasUrl()` will always return FALSE in this case because of the `$executable->live_preview = TRUE`, so `$path = $executable->getUrl();` will never be reached, so there is dead code in that function.

Let confer with @dawehner again about how we want to approach this.

mpdonadio’s picture

@dawehner and discussed this in IRC, and decided to reformulate the approach, which will require some more debugging as to why some things aren't happening.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new4.43 KB
new1.59 KB

Maybe ViewExecutable::hasUrl() should just look up the route name on the display to see if it exists yet?

dawehner’s picture

+++ b/core/modules/views_ui/src/Tests/UnsavedPreviewTest.php
@@ -0,0 +1,73 @@
+
+    $this->drupalGet('admin/structure/views/view/content');
+    $this->assertResponse(200);
+
+    $this->drupalPostForm(NULL, [], t('Add Page'));
+    $this->assertResponse(200);
+
+    $this->drupalGet('admin/structure/views/nojs/display/content/page_2/path');
+    $this->assertResponse(200);
+
+    $this->drupalPostForm(NULL, ['path' => 'foo'], t('Apply'));
+    $this->assertResponse(200);
+
+    $this->drupalPostForm(NULL, [], t('Update preview'));
+    $this->assertResponse(200);

DO you mind saving the view and then check whether the link appears?

mpdonadio’s picture

Adjusted test. Added check to make sure the path isn't on the page when it is unsaved, and there when it is saved. Works fine for me locally.

The last submitted patch, 40: views_preview_not-2446783-test-only.patch, failed testing.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you!

xjm’s picture

Status: Reviewed & tested by the community » Needs work

The new approach seems nice and clean to me, +1. (And thanks for the clear issue report @koence.)

+++ b/core/modules/views/src/ViewExecutable.php
@@ -437,6 +438,20 @@ class ViewExecutable implements \Serializable {
+   * If the view is currently being used for a live preview from the UI.
+   *
+   * @var bool
+   */
+  public $live_preview = FALSE;
+
+  /**
+   * If the view has been changed.
+   *
+   * @var bool
+   */
+  public $changed = FALSE;
+
+  /**

So adding this documentation is out of scope now since they aren't used in the patch... can we remove this hunk?

Other than that I think this is ready.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new2.27 KB
new4.36 KB
new687 bytes

Yup. Those are unrelated to the patch now. Gone.

The last submitted patch, 44: views_preview_not-2446783-test-only.patch, failed testing.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Fair point!

Let's get the more simple version in.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 44: views_preview_not-2446783-44.patch, failed testing.

The last submitted patch, 44: views_preview_not-2446783-44.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review
StatusFileSize
new2.27 KB
new4.36 KB
new687 bytes

Reposting these patches. Something went wrong, and the retest isn't showing up in the queue anymore.

The last submitted patch, 44: views_preview_not-2446783-44.patch, failed testing.

The last submitted patch, 51: views_preview_not-2446783-test-only.patch, failed testing.

mpdonadio’s picture

Status: Needs review » Reviewed & tested by the community

Per #46, I am putting this back to RTBC. #51 has a passing patch, and the in-betweens look like the spurious fails we have been encountering the last few days.

  • xjm committed 994f683 on 8.0.x
    Issue #2446783 by mpdonadio, dawehner, koence: Views preview not working...
xjm’s picture

Status: Reviewed & tested by the community » Fixed

This issue addresses a bug and is allowed per https://www.drupal.org/core/beta-changes. Committed and pushed to 8.0.x!

+++ b/core/modules/views_ui/src/Tests/UnsavedPreviewTest.php
@@ -0,0 +1,84 @@
+ * Tests covering Preview uf unsaved Views.

Det er norsk? Uff-da!

+++ b/core/modules/views_ui/src/Tests/UnsavedPreviewTest.php
@@ -0,0 +1,84 @@
+  public function testUsavedPageDisplayPreview() {

U-saved could be the name of a thrift store.

Both typos fixed on commit.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.