Problem/Motivation
When working on the Events recipe, I notice that there are consistently errors thrown when importing the provided view. For example:
Warning: Undefined array key "events.page_1" in Drupal\views\Plugin\Derivative\ViewsLocalTask->getDerivativeDefinitions() (line 82 of core/modules/views/src/Plugin/Derivative/ViewsLocalTask.php).
Drupal\views\Plugin\Derivative\ViewsLocalTask->getDerivativeDefinitions(Array) (Line: 101)
Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator->getDerivatives(Array) (Line: 87)
Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator->getDefinitions() (Line: 337)
Drupal\Core\Plugin\DefaultPluginManager->findDefinitions() (Line: 213)
Drupal\Core\Plugin\DefaultPluginManager->getDefinitions() (Line: 181)
Drupal\Core\Menu\LocalTaskManager->getDefinitions() (Line: 206)
Drupal\Core\Menu\LocalTaskManager->getLocalTasksForRoute('view.frontpage.page_1') (Line: 290)
Drupal\Core\Menu\LocalTaskManager->getTasksBuild('view.frontpage.page_1', Object) (Line: 358)
Drupal\Core\Menu\LocalTaskManager->getLocalTasks('view.frontpage.page_1') (Line: 251)
Drupal\navigation\NavigationRenderer->getLocalTasks() (Line: 288)
Drupal\navigation\NavigationRenderer->hasLocalTasks() (Line: 224)
Drupal\navigation\NavigationRenderer->removeLocalTasks(Array, Object) (Line: 162)
navigation_block_build_local_tasks_block_alter(Array, Object, NULL) (Line: 552)
Drupal\Core\Extension\ModuleHandler->alter('block_build', Array, Object) (Line: 65)
Drupal\block\BlockViewBuilder->viewMultiple(Array, 'full', NULL) (Line: 32)
Drupal\block\BlockViewBuilder->view(Object) (Line: 152)
Drupal\block\Plugin\DisplayVariant\BlockPageVariant->build() (Line: 270)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 128)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object) (Line: 246)
Symfony\Component\EventDispatcher\EventDispatcher::Symfony\Component\EventDispatcher\{closure}(Object, 'kernel.view', Object) (Line: 206)
Symfony\Component\EventDispatcher\EventDispatcher->callListeners(Array, 'kernel.view', Object) (Line: 56)
Symfony\Component\EventDispatcher\EventDispatcher->dispatch(Object, 'kernel.view') (Line: 188)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)(the error above is thrown twice, once for each display)
Warning: Undefined array key "events.page_2" in Drupal\views\Plugin\Derivative\ViewsLocalTask->alterLocalTasks() (line 122 of core/modules/views/src/Plugin/Derivative/ViewsLocalTask.php).
Drupal\views\Plugin\Derivative\ViewsLocalTask->alterLocalTasks(Array) (Line: 812)
views_local_tasks_alter(Array, NULL, NULL) (Line: 552)
Drupal\Core\Extension\ModuleHandler->alter('local_tasks', Array) (Line: 386)
Drupal\Core\Plugin\DefaultPluginManager->alterDefinitions(Array) (Line: 341)
Drupal\Core\Plugin\DefaultPluginManager->findDefinitions() (Line: 213)
Drupal\Core\Plugin\DefaultPluginManager->getDefinitions() (Line: 181)
Drupal\Core\Menu\LocalTaskManager->getDefinitions() (Line: 206)
Drupal\Core\Menu\LocalTaskManager->getLocalTasksForRoute('view.frontpage.page_1') (Line: 290)
Drupal\Core\Menu\LocalTaskManager->getTasksBuild('view.frontpage.page_1', Object) (Line: 358)
Drupal\Core\Menu\LocalTaskManager->getLocalTasks('view.frontpage.page_1') (Line: 251)
Drupal\navigation\NavigationRenderer->getLocalTasks() (Line: 288)
Drupal\navigation\NavigationRenderer->hasLocalTasks() (Line: 224)
Drupal\navigation\NavigationRenderer->removeLocalTasks(Array, Object) (Line: 162)
navigation_block_build_local_tasks_block_alter(Array, Object, NULL) (Line: 552)
Drupal\Core\Extension\ModuleHandler->alter('block_build', Array, Object) (Line: 65)
Drupal\block\BlockViewBuilder->viewMultiple(Array, 'full', NULL) (Line: 32)
Drupal\block\BlockViewBuilder->view(Object) (Line: 152)
Drupal\block\Plugin\DisplayVariant\BlockPageVariant->build() (Line: 270)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 128)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object) (Line: 246)
Symfony\Component\EventDispatcher\EventDispatcher::Symfony\Component\EventDispatcher\{closure}(Object, 'kernel.view', Object) (Line: 206)
Symfony\Component\EventDispatcher\EventDispatcher->callListeners(Array, 'kernel.view', Object) (Line: 56)
Symfony\Component\EventDispatcher\EventDispatcher->dispatch(Object, 'kernel.view') (Line: 188)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)Knowing that this recipe is very similar to the Smart Date Starter Kit (which is available as both a module and a recipe), I installed the module and then replaced the supplied view config file with a copy of the view file from the Events recipe (to make sure there would be no differences in the configuration). When I enabled the module, there were no errors.
Steps to reproduce
On a fresh install of Drupal 11, composer require and then apply the Events recipe. Notice that when you visit the website after the recipe is successfully applied, errors are shown like the ones above.
Proposed resolution
I'm not sure why the errors are only created when configuration is imported through the recipes system, so additional investigation is required.
Issue fork drupal-3464160
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Issue fork distributions_recipes-3464160
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3464160-errors-thrown-when
changes, plain diff MR !161
Comments
Comment #2
thejimbirch commentedComment #3
bhuvaneshwar commentedComment #5
mandclu commentedComment #8
mandclu commentedAdding a nullsafe fallback to empty strings resolves the errors that are currently thrown when applying the events recipe. I also verified that the configuration is still imported as expected.
Comment #9
smustgrave commentedDefinitely believe this will need test coverage
Wonder if a configuration is wrong. Only mention as not sure putting a null check is enough or is masking a potentially large/different issue.
Comment #10
mandclu commented@smustgrave I would be happy to write the tests, but would appreciate a little guidance on how to test these. All this change does is allow the code to more gracefully handle the situation where a particular view / display combination isn't found in the array returned by
$this->state->get('views.view_route_names'). In both cases the next line is a check whether a retrieved route name matches a constructed plugin id (which will never be empty), so this check effectively handles the case where the expected route name can't be found. Without the fix here, the same checks catch the mismatch and trigger a return of the function, but throw a PHP warning along the way. I would argue that the proposed fix doesn't alter the logic of either function, it just allows it to more gracefully handle a reproducible use case when creating a view via a recipe.It's possible there is a deeper issue around the order in which the Recipes code handles elements of the provided view configuration, but after applying the recipe and clearing the cache, the provided local tasks work as expected. It's also worth noting that the identical configuration has been previously installable as part of the Start Date Starter Kit, so several hundred sites are using this configuration, and when it is installed as the configuration provided by a module, no errors are thrown.
Comment #11
smustgrave commentedDo we believe this is incorrect config. Should there be a log made when $this->state->get('views.view_route_names') isn't found.
Even more should it be a deprecation that in D12 this will throw an error.
Comment #12
mandclu commentedI think it's worth reiterating that in the situation where I can consistently reproduce these warnings being output, the site still works as expected. Suppressing the warnings requires twelve characters, and the subsequent code still handles the unfound route name.
As to the larger question whether or not an unfound route name should trigger an error, that sounds a valid topic to explore, but I would suggest better handled as a separate issue, particularly since it could have the potential for far-reaching implications.
Comment #13
nicxvan commentedI think this might not need tests according to the new testing guidelines:
https://www.drupal.org/about/core/policies/core-change-policies/core-gat...
Both of these are true:
And the following questions:
4 out of 7 is the majority, I don't think this needs tests.
I'm not sure if we can add the tag that it needs no tests or just core maintainers can so I'm just RTBC and leaving my observations and removing needs tests.
Comment #14
smustgrave commentedWill still mention feels as though we are probably masking another issue.
Comment #15
lendudeI agree with @smustgrave this is most likely just masking an issue. If you have a tab and no route there is something wrong with your install, so why are we suppressing the warning, when it seems to be doing it's job and warning you that there is something wrong?
And yeah it seems most likely a timing issue that $this->state->get('views.view_route_names') is not properly populated yet or something along those lines. But if that is the case we need to fix the timing issue and not just ignore the error.
But I think we need to properly investigate the root cause and then we can make a decision as to the proper fix (which might turn out to be to suppress the error)
Comment #16
nicxvan commentedWould it be acceptable to do that as a followup?
Comment #17
lendudeIn my opinion, no, because we have no idea what we are 'fixing' here. But I'll leave it RTBC for others to look at, happy to be wrong :)
Comment #18
phenaproximaI'm sorry, I agree with @Lendude and @smustgrave here; the fix may well be to suppress the warning, but without knowing why, this patch is incomplete. Test coverage may in fact be needed if there's actually a bug here.
Comment #19
phenaproximaBased on some conversation with @mandclu in Slack, I'm starting to think this is a problem specific to the command-line recipe runner. Tracing through core, what I'm seeing is that the router table should be rebuilt at the end of the request, which would avoid this error. But the thing is that
RecipeCommandnever actually terminates the "request" properly, and therefore the router is never rebuilt (until the next cache clear, at least).I suspect the fix here is to have RecipeCommand do a proper request termination, with all destructable container services notified (which would trigger a router rebuild). Patch attached for folks to test with.
Comment #20
mandclu commentedComment #21
mradcliffeI had a user report this in a contrib. module of mine outside of the recipes work flow. I don't have any additional steps to reproduce yet, but I think it could also occur not just in recipes install but some other fatal error on module install.