Problem/Motivation
User error: "current" is an invalid render array key in Drupal\Core\Render\Element::children() (Zeile 98 in /app/web/core/lib/Drupal/Core/Render/Element.php) #0 /app/web/core/includes/bootstrap.inc(164): _drupal_error_handler_real() #1 [internal function]: _drupal_error_handler() #2 /app/web/core/lib/Drupal/Core/Render/Element.php(98): trigger_error() #3 /app/web/core/lib/Drupal/Core/Render/Renderer.php(451): Drupal\Core\Render\Element::children() #4 /app/web/core/lib/Drupal/Core/Render/Renderer.php(493): Drupal\Core\Render\Renderer->doRender() #5 /app/web/core/lib/Drupal/Core/Render/Renderer.php(240): Drupal\Core\Render\Renderer->doRender() #6 /app/web/core/lib/Drupal/Core/Template/TwigExtension.php(475): Drupal\Core\Render\Renderer->render() #7 /app/files/public/php/twig/66c34be9ce8a5_views-ui-view-preview-sec_R4Lu2fL_DwddDSbeJW6zDMV9A/hyDakoD_a3SoCXz-3CZyiTc9EtvBLxEznSweLH5KAJQ.php(53): Drupal\Core\Template\TwigExtension->escapeFilter() #8 /app/vendor/twig/twig/src/Template.php(394): __TwigTemplate_dfebbeee6d7ee9dac90233a7e9bcec36->doDisplay() #9 /app/vendor/twig/twig/src/Template.php(367): Twig\Template->displayWithErrorHandling() #10 /app/vendor/twig/twig/src/Template.php(379): Twig\Template->display() #11 /app/vendor/twig/twig/src/TemplateWrapper.php(38): Twig\Template->render() #12 /app/web/core/themes/engines/twig/twig.engine(39): Twig\TemplateWrapper->render() #13 /app/web/core/lib/Drupal/Core/Theme/ThemeManager.php(348): twig_render_template() #14 /app/web/core/lib/Drupal/Core/Render/Renderer.php(480): Drupal\Core\Theme\ThemeManager->render() #15 /app/web/core/lib/Drupal/Core/Render/Renderer.php(240): Drupal\Core\Render\Renderer->doRender() #16 /app/web/core/lib/Drupal/Core/Template/TwigExtension.php(475): Drupal\Core\Render\Renderer->render() #17 /app/files/public/php/twig/66c34be9ce8a5_views-view.html.twig_2OpeE5BICqayh_oKYRMjemu0J/1XG_hB2O6JDb1wPqx9ui7IbuvUmBXiXrxTPCjZIHvzo.php(110): Drupal\Core\Template\TwigExtension->escapeFilter() #18 /app/vendor/twig/twig/src/Template.php(394): __TwigTemplate_3df5a23c0c1ad5e281e11fbd1090d8fb->doDisplay() #19 /app/vendor/twig/twig/src/Template.php(367): Twig\Template->displayWithErrorHandling() #20 /app/vendor/twig/twig/src/Template.php(379): Twig\Template->display() #21 /app/vendor/twig/twig/src/TemplateWrapper.php(38): Twig\Template->render() #22 /app/web/core/themes/engines/twig/twig.engine(39): Twig\TemplateWrapper->render() #23 /app/web/core/lib/Drupal/Core/Theme/ThemeManager.php(348): twig_render_template() #24 /app/web/core/lib/Drupal/Core/Render/Renderer.php(480): Drupal\Core\Theme\ThemeManager->render() #25 /app/web/core/lib/Drupal/Core/Render/Renderer.php(493): Drupal\Core\Render\Renderer->doRender() #26 /app/web/core/lib/Drupal/Core/Render/Renderer.php(493): Drupal\Core\Render\Renderer->doRender() #27 /app/web/core/lib/Drupal/Core/Render/Renderer.php(493): Drupal\Core\Render\Renderer->doRender() #28 /app/web/core/lib/Drupal/Core/Render/Renderer.php(240): Drupal\Core\Render\Renderer->doRender() #29 /app/web/core/lib/Drupal/Core/Render/Renderer.php(153): Drupal\Core\Render\Renderer->render() #30 /app/web/core/lib/Drupal/Core/Render/Renderer.php(627): Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() #31 /app/web/core/lib/Drupal/Core/Render/Renderer.php(154): Drupal\Core\Render\Renderer->executeInRenderContext() #32 /app/web/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php(66): Drupal\Core\Render\Renderer->renderRoot() #33 /app/web/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php(90): Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse() #34 [internal function]: Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray() #35 /app/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func() #36 /app/vendor/symfony/http-kernel/HttpKernel.php(186): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch() #37 /app/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw() #38 /app/web/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle() #39 /app/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle() #40 /app/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle() #41 /app/web/modules/contrib/lupus_decoupled/modules/lupus_decoupled_ce_api/src/BackendApiRequest.php(107): Drupal\Core\StackMiddleware\ContentLength->handle() #42 /app/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\lupus_decoupled_ce_api\BackendApiRequest->handle() #43 /app/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass() #44 /app/web/modules/drunomics/ldp-core/modules/ldp_cdn/src/FixedBaseUrlMiddleware.php(85): Drupal\page_cache\StackMiddleware\PageCache->handle() #45 /app/vendor/asm89/stack-cors/src/Cors.php(53): Drupal\ldp_cdn\FixedBaseUrlMiddleware->handle() #46 /app/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Asm89\Stack\Cors->handle() #47 /app/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() #48 /app/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() #49 /app/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle() #50 /app/web/core/lib/Drupal/Core/DrupalKernel.php(704): Drupal\Core\StackMiddleware\StackedHttpKernel->handle() #51 /app/web/index.php(19): Drupal\Core\DrupalKernel->handle() #52 {main}.
Steps to reproduce
Edit a custom elements page in views.
Findings and proposed resolution
The Custom Elements row style plugin is creating an invalid render array. (The 'rows' and 'pager' elements are not renderable by 'stock' Drupal.) Its data structure is set up to be only valid for/renderable by the lupus_decoupled controller route.
The Custom Elements row style plugin should be fixed to create a valid Drupal render array, which preview (and 'regular' display plugins) can handle without producing errors.
Then, any extra data that the lupus_decoupled controller route needs, should be added to it in a way that does not make the array invalid. (Update: this seems unnecessary; the controller can pick the data from the render array.)
Bonus: move Custom Elements specific code from the controller route into the CustomElementsPage display plugin. The route is only applied to views with that plugin, so it makes sense.
Issue fork lupus_decoupled-3469398
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:
- 3469398-when-editing-a
changes, plain diff MR !89
- 3469398-remove-controller
changes, plain diff MR !90
Comments
Comment #2
fagoWhich version of core / lupus-decoupeld are affected?
Comment #3
alexpottI'm getting the same issue on Core 10.3.1 and Lupus decoupled 1.0.0-beta6 and custom elements 2.5.0
The problem seems to be occurring because a paragraphs views reference field is causing a view to be rendered on the node edit form (this is the desired behaviour) and the lupus_decoupled_views modules is adding things to the render array that Drupal's renderer cannot process. It's adding things in \Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render() and \Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render() that will cause errors in \Drupal\Core\Render\Element::children()... I would have expected some sort of pre_render callback to process them but I don't know enough about how the custom elements module works at the moment.
Comment #4
alexpottThis has only been causing issues on Drupal 10.3 due to #3427177: Replace calls to ::expectError*() from Drupal\Tests\Core\Render\ElementTest which changed an E_USER_ERROR to an exception in the renderer. I think \Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render() needs changing to use render arrays rather than just dumping stuff into the render array. However this module has always been cause notices like
User error: "total_items" is an invalid render array key in Drupal\Core\Render\Element::children()in the logs.Comment #5
useernamee commentedI was only testing this with custom elements v3.
I'll open a PR with a fix, and hopefully it will work for you as well @alexpott.
Comment #7
useernamee commentedI'm not sure how good this solution is, but the errors are gone and there is a simple preview of what custom element view will show.
Other option would be, to disable the preview or maybe write a nice template to print out the custom elements render array.
Comment #8
fagoNot sure why/how the CustomElement style plugin gets called for a view that - as I understand - is not related to custom elements?
Anyway, as pointed out there are errors produced else as well, so we definitely have an issue here. As it seems, the render() method is supposed to return a render array, and we aren't, what leads to the problem.
At the same time, it's also not completing the rendering atm, we have the code that puts the final touches on it in \Drupal\lupus_decoupled_views\Controller\ViewsController::viewsView. So what about moving that final touches
to the render() method and returning the expected renderable via $element->toRenderArray()? That would solve the code-reusing issue I commented on the MR above as well.
Comment #9
alexpott@fago yes \Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render() is supposed to to return a renderable array - but it doesn't in 2 two ways:
$result['rows'][] = $custom_element;- $custom_element is not a renderable. I think this should be$result['rows'][] = $custom_element->toRenderArray();$result['pager'] = $this->pagination($result['rows']);this also cause issues that are harder to see how to fix because of what \Drupal\lupus_decoupled_views\Controller\ViewsController::viewsView() is expecting.Comment #10
alexpottIn our case the view definitely is supposed to use CustomElements - it's just not using \Drupal\lupus_decoupled_views\Plugin\views\display\CustomElementsPage or \Drupal\lupus_decoupled_views\Controller\ViewsController::viewsView. It's a views reference field in a paragraph.
Comment #11
useernamee commentedI was mostly investigating the view preview (/admin/structure/view/). There is an issue that renderer doesn't know how to render custom element object or #custom_elements render array. That's why I did convert it to #markup render array.
I did investigate the render method, but overriding it, to return render array of #type custom_element did not produce good results.
I'm not sure why we even need the override with ViewsController. Seems like
\Drupal\views\Routing\ViewPageController::handleonly callsbuildResponseandbuildBasicRenderableso I think we should add our logic in these two methods in CustomElementsPage views plugin and there's no need for the ViewsController.and
Comment #13
useernamee commentedI did try to test out the second approach as well by implementing
Drupal\views\Plugin\views\display\ResponseDisplayPluginInterfacesimilar to what Feeds view display does, but I got problems with the early rendering that doesn't seem to easy to resolve:LogicException: The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Ensure you are not rendering content too early. Returned object class: Drupal\Core\Cache\CacheableJsonResponse. in Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (line 154 of core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php).So this PR 90 is non working concept.
---
@fago could you review PR 89?
Comment #14
fago> I'm not sure why we even need the override with ViewsController.
We might need it for the Lupus-CE-Renderer to pickup the responses cleanly. I'm not sure it does so with a custom element render array, we might need to return the CE-object. If it supports the CE-render array also we might be fine without the controller.
Anyway, if the controller does not cause issues in general, let's better keep it and solely focus on fixing the bug.
Comment #15
useernamee commented@alexpott
So, I've ran some tests on custom_elements 3.x and lupus_decoupled_views. Having my PR 89 active, the issue in view preview is resolved. I wasn't able to reproduce the issue in referenced entities while checking the views, but I only tested with view configured in a way to show a Content with viewmode that has custom elements display enabled.
When I'm showing Fields instead of content the preview is broken again due to
TypeError: htmlspecialchars(): Argument #1 ($string) must be of type string, array given in htmlspecialchars() (line 437 of /app/web/core/lib/Drupal/Component/Utility/Html.php).^^ Has own issue #3461874: Custom elements Views: Per-field formatters are not supported/working
To sum up: @alexpott would you consider upgrading custom elements to version 3.x and tell if you're still experiencing the php errors with the patch from this ticket applied. I can't reproduce it anymore (although for me it was only ever coming up on the view preview).
@fago, could you review PR89.
Comment #16
useernamee commentedComment #17
roderik@alexpott / @useernamee
The 'v2 way of rendering' (Processors) is still the same in v3, so there should be no need to test on v3. We should even be able to test these issues (that don't trigger any use of v3-style Custom Elements Displays) by temporarily copying v2 code back over v3.... for the moment at least.
I'm just noting this befause updating to v3 is explicitly non-trivial.
If possible / for the moment, any fix that comes out of this will be applied to the v2 branch also.
Comment #18
alexpottPR89 is not going to solve my problem because
\Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render()adds things to a render array array that are not renderable. As long as the module continues to do that anything that embeds the view is going to have problems. The fix in PR89 is a workaround for this only for preview but there are other cases where this occurs.I far as I can see, if
\Drupal\lupus_decoupled_views\Plugin\views\style\CustomElements::render()continues to return a non-renderable array, you'll continue to have unexpected issues due to the approach.Comment #19
fagoI don't see why this issue is related to the custom elements version, the APIs used did not change at all. So the fix should apply to both just fine.
Anyway, I very much agree with alex pott that we need to fix render() to return a proper render array.
Also added some comments to the MR.
Comment #20
useernamee commentedIf I return render_array of type
#custom_elements, this is returned in preview (browser does not display it):That's why I converted array to string, pretty print it and show it as markup.
I've made view work (in the be) but it comes with a quirk:
\Drupal\custom_elements\CustomElementNormalizer::normalizeSlotsdid not know how to normalize it, so I added another condition to the method:I'm not sure this is a general direction we'd like go into.
Also I'm a bit unsure what to do with the
pager. So far, I translated it into the custom element, and slot on the view, but I guess we could also leave it as attribute.@fago @alexpott - I kind of depend on your feedback here.
Comment #21
fagoThis rendering is good, it's correctly rendering the custom element using markup serialization:
So all seems fine to me. Yes, it's not a frontend rendering, but that's another story.
Why are you dumping the literal object when the above rendering is already good? Imo, we should simply add
<pre>tags around the above custom element rendering (e.g. with #prefix #suffix) to make he markup readable / visible in the browser.Yes, that's not a visual preview rendered in the frontend, but that would be a bit more complex and require iframes to correctly go via the decoupled frontend. There is code doing so in the issue #3338911: Frontend-rendered layout-builder previews, so that would be a great addition, but that is clearly out of scope here. Let's have correctly rendered markup shown in the preview for now. We could open a follow-up for a nicely rendered preview via iframes though!
So far the code did:
$custom_element->setAttribute('pager', $result['#rows']['pager'] ?? []);Changing that would be an API break. Why would we do that? Are there issues with the pager?
Generally speaking, a slot should be used for nested content that may be composed for any kind of content, not for passing data - use attributes for that. So the pager being an attribute is good, so the drupal-view component stays in control of how to render the pager.
Comment #22
useernamee commentedBecause of #9.
I'll try out the proposal.
Comment #23
useernamee commented@fago I've followed your advice, but the pager is now (again) producing errors on pre-view:
Another issue I get now is that markup format is producing an error:
https://admin--example.ldp-project.localdev.space/admin/test-ce?_content...
It works if I don't transform rows in render arrays but leave them as custom elements objects here. The issue is that render transforms render array into markup, but then the value is not string or MakupInterface which it expects.
Comment #24
fagoFrom a quick check the MR looks mostly good, except for my remark related to PluginException being the wrong exception is not yet addressed.
> It works if I don't transform rows in render arrays but leave them as custom elements objects here. The issue is that render transforms render array into markup, but then the value is not string or MakupInterface which it expects.
hm, not sure I get that. You mean custom elements produces an invalid render array, that cannot be correctly rendered? If so, we should open an issue for fixing that and get that fixed. Returning Markup instead of a plain string would make sense to me. Please work with roderik as necessary to get it addressed.
Comment #25
fagoComment #26
roderikI did not know this code yet, and/so could not make out from the discussion, what to do... so I needed to just tinker with it myself.
End conclusion: yes, this solution is already good. (Updated issue summary, with my understanding of what we are doing.) It just needed bugs fixed:
That's because the controller was still doing
$custom_element->setSlotFromNestedElements('rows', VALUE);, while VALUE was changed from$custom_elementto$custom_element->toRenderArray(). The setSlotFromNestedElements() is now fixed.The preexisting code in the row style plugin just put an array of values into $result['pager']. That is not OK / not a valid render array.
I moved the code into the CustomElementsPage display plugin, because it's only needed there. Now we're not setting $result['pager'] anymore -- error is gone.
'custom_elements' format responses (i.e. anything using the "custom_elements_page" display plugin) still produces the same output.
Comment #27
useernamee commentedTested locally, found a small issue when no results are provided and fixed it.
Moving to RTBC.
Comment #28
useernamee commentedI fixed some pipeline cspell errors, but we have more issues with phpstan and phpunit to for next major version.
Comment #29
useernamee commentedI did found another issue with the pager: (Is this normal mini pager behavior?)
/admin/test-ce?_content_format=json&page=0 or without page query param
/admin/test-ce?_content_format=json&page=1
/admin/test-ce?_content_format=json&page=2
/admin/test-ce?_content_format=json&page=3and/admin/test-ce?_content_format=json&page=4page=5 ...
Comment #30
useernamee commentedI guess that this is just the mini pager behavior.
I tested out the full pager and it looked better except that it starts page count with zero ... which means if total pages are 4, the last page is page 3.
Comment #31
fago* The change looks good now and generally ready. However, the MR needs a re-roll and a resulting glitch to be resolved/updated. (see my comment)
* I suppose this pager issues are not new? Let's open dedicated bug reports for each of them please.
* It seems there is no test coverage for that feature at all, we really should add some. Let's add a follow-up for it.
Comment #32
useernamee commented- re-roll done, thus merging.
- creating a followup for tests: #3475738: Add tests for Lupus Decoupled views
- followup for mini pager: #3475740: Investigate view's mini pager inconsistency
Comment #33
useernamee commentedTried to merge MR89 but wasn't able to.
Comment #35
roderikThanks!
I couldn't merge either. (Happened to me more often.) And I seem to lack some git knowledge (about --no-ff and --squash not working together) so I can't really explain.
But I could reproduce a squashed commit locally and compare that it was equal to the branch, so all good.