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
- Go to Structure -> Views
- Edit view Content
- Add display (e.g. Page) that needs a path
- Provide path to display
- (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
| Comment | File | Size | Author |
|---|---|---|---|
| #51 | interdiff-40-44.txt | 687 bytes | mpdonadio |
| #51 | views_preview_not-2446783-44.patch | 4.36 KB | mpdonadio |
| #51 | views_preview_not-2446783-test-only.patch | 2.27 KB | mpdonadio |
| #44 | interdiff-40-44.txt | 687 bytes | mpdonadio |
| #44 | views_preview_not-2446783-44.patch | 4.36 KB | mpdonadio |
Comments
Comment #1
dawehnerSent this issue to mpdonadio
Comment #2
mpdonadioOK, 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.
Comment #3
dawehnerThank you!!
Comment #4
mpdonadioOK, here is an initial assessment
ViewsForm::buildForm() and ViewsExposedForm::buildForm() both have
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.
Comment #5
mpdonadioFirst pass at an ugly fix.
Comment #7
dawehner@mpdonadio
I guess we should add a new field to displays on View, which simply indicates whether the display is new.
Comment #8
mpdonadioHaving 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.
Comment #10
mpdonadioStraight 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()?
Comment #11
dawehnerIts 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.
Comment #12
mpdonadioThis fixes the situation in the IS. Still need to cobble together a test. Is an AJAX thing like this testable w/ Simpletest?
Comment #13
mpdonadioFeed the TestBot or it gets cranky when its blood sugar gets low.
Comment #15
mpdonadioIf you run the test-only patch via the UI or run-tests.sh in verbose mode, you see the 500 w/ the exception:
Comment #17
tim.plunkettSince this is a new file, I can nitpick more
Contains \Drupal
Both of these can use {@inheritdoc}
Here and throughout, might as well use []
Once that's done I can manually test and RTBC tomorrow.
@mpdonadio++
Comment #18
mpdonadioAddressed #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...
Comment #20
dawehnerNote: We could extend UiTestBase and save a couple of lines in this file, like creating the admin user
This is redundant ...
Comment #21
mpdonadio#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:
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.
Comment #23
dawehnerThis 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
Comment #24
mpdonadioOK, 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.
Comment #26
dawehnerAt 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
Thank you!
Comment #27
alexpottWhat are we to do? A bit of searching views_ui and you can see this is used. For example:
Comment #28
mpdonadioI'll remove the @todo later today. That example did not turn up when I had searched, only uses limited to a single method.
Comment #29
mpdonadioThe @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.
Comment #30
dawehnerI'd like that we add more and more over time, but sure, we'll never tackle all of them.
Comment #31
alexpottIt would be nice to have a comment here as to why these need to be checked whilst calling the
hasUrl()method.Let's just extend ViewTestBase and then we don't have to make the changes to UITestBase
Can
$path = $executable->getUrl()ever be hit -$executable->live_previewis set toTRUEat the beginning of this method.Comment #32
mpdonadioOK, #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.
Comment #33
mpdonadioBlerg.
Comment #35
alexpott@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?Comment #36
mpdonadio@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.
Comment #37
mpdonadio@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.
Comment #38
mpdonadioMaybe ViewExecutable::hasUrl() should just look up the route name on the display to see if it exists yet?
Comment #39
dawehnerDO you mind saving the view and then check whether the link appears?
Comment #40
mpdonadioAdjusted 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.
Comment #42
dawehnerThank you!
Comment #43
xjmThe new approach seems nice and clean to me, +1. (And thanks for the clear issue report @koence.)
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.
Comment #44
mpdonadioYup. Those are unrelated to the patch now. Gone.
Comment #46
dawehnerFair point!
Let's get the more simple version in.
Comment #51
mpdonadioReposting these patches. Something went wrong, and the retest isn't showing up in the queue anymore.
Comment #54
mpdonadioPer #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.
Comment #56
xjmThis issue addresses a bug and is allowed per https://www.drupal.org/core/beta-changes. Committed and pushed to 8.0.x!
Det er norsk? Uff-da!
U-saved could be the name of a thrift store.
Both typos fixed on commit.