Needs work
Project:
Drupal core
Version:
main
Component:
render system
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
27 Oct 2015 at 11:11 UTC
Updated:
1 Dec 2025 at 17:56 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
sam152 commentedComment #3
sam152 commentedSurprisingly simply patch. Lets see what testbot says. 8.0.x is only for the bot.
Comment #4
sam152 commentedComment #6
sam152 commentedComment #7
sam152 commentedComment #8
sam152 commentedOne day I'll learn to create a patch.
Comment #9
wim leers+1 on concept.
But I'm not sure what the wider consequences are. We should enumerate all consequences, so we can at least try to avoid unexpected (DX) regressions.
Comment #10
Crell commentedI believe the intent here is to let any arbitrary object do what Link is now doing. It *shouldn't* impact the rendering engine at all.
The DX implication, though, is that depending on when we process RenderableInterface objects an alter hook may not know if it's getting, say, a #table array or a #table => TableBuilder implements RenderableInterface. That would be the concern.
Comment #11
sam152 commentedI hadn't considered the DX of hooks that alter markup. We kind of already have that with twig and the element attribute object/arrays, but it would be nice to avoid entirely. It might be a step backwards but things transitioning from arrays to objects could implement ArrayAccess to make existing code which relied on them being arrays continue to work.
Comment #12
Crell commentedThat is only sort of the case. ArrayAccess lets [] work, but doesn't support foreach() (for which you need Iterable) or the dozens of array functions available (for which there is no straightforward object equivalent). This is a long-standing known issue with PHP.
On the other hand, we are explicitly excluding most render arrays from our definition of "API", so that we can change them to improve the UI in point releases. Maybe we can get away with using objects in some places, therefore? Either way, it is a concern.
(And I say that as someone who really wants to be using more objects.)
Comment #13
wim leersExactly.
Indeed.
The second quoted bit there made me realize that at worst, those cases can be addressed by those alter hooks creating a new object that inherits all data from the old object, with modifications. If that's not possible, then the object is poorly designed.
This patch really is just enabling experimentation with this. It is not changing anything in core.
Consequently, I'm not sure there actually are any concerns about this? And I think this should even be considered a Contributed project blocker, because it blocks experimenting with improvements in contrib?
Comment #14
Crell commentedI agree. Let's make sure that core supports arbitrary RenderableInterface objects in render arrays. Anything else that gets done with that is up to contrib to figure out.
Strictly speaking, the same object-or-array issue would exist now for Link since Link, by design, does have an array representation one could use instead of the object if one were so inclined. So we're not even creating a new inconsistency, just letting that same inconsistency apply consistently. :-)
I defer to WimLeers on whether the patch in #7 is the correct way to do that.
Comment #15
wim leersI'd also like to get @Fabianx' thoughts on this. And I think this should be committed by catch or alexpott, and should preferably be reviewed by both.
Comment #16
benjy commentedIs there still time to do this before release? It would be great to enable contrib and see what happens.
Comment #17
joelpittetBumping to a possible feature for 8.1.x
Comment #18
Crell commentedI don't see why it's postponed now that 8.1.0 is the next stable. :-)
Comment #19
joelpittet@crell was what I was told since the branch wasn't open.
Comment #20
xanoThis concept seems to break BC, because with the patch render arrays aren't just arrays anymore, so any code that expects them to be arrays, will break on
RenderableInterface: type hints,arrray_*()functions, the addition operator, etc. #2316941-81: Use the builder pattern to make it easier to create render arrays provides a potential interim solution.Comment #21
sam152 commentedThis would only be a BC break if another core patch changed an array to an object. Since that'll be where BC needs to be evaluated and this is a contrib blocker, I believe it should still be merged.
Comment #22
xanoThis also breaks when new objects are introduced. We currently tell everyone render arrays are pure arrays, with the exception of element 'property' values. Allowing objects breaks any code that uses array functionality over elements, or type hints on them.
The only reason this was marked a blocker, is for future development and not because it currently blocks contrib functionality.
As much as I'd like to see a full conversion, I see this as 9.0.x material.
Comment #24
fabianx commentedIt is not a BC break for core as we just allow contrib to use RenderableInterface objects instead of arrays.
In fact we already allow that but only for Twig variables, so it seems fair to make that even earlier.
I wanted to RTBC this, but:
On the other hand as pointed out contrib can easily circumvent that:
Both cannot be traversed, however the object could be early-rendered to change its contents by the caller, but not sure that is desirable. (kinda reminds one of the Shadow-DOM dilemma).
But for the render array with #type one a #pre_render could be added.
but that would not work as when the type is a lazy builder it would bail out and if the type is using #pre_render itself, it would overwrite it as we don't merge deep here.
So the #pre_render would need to use:
and hence repeat it.
To get the same effect for the renderable objects, we would need MutableRenderableInterface, which would allow to do:
or
Given that the same problems happen and there is no distinct advantage to storing objects in the array tree, I am tending to won't fix this:
UNLESS
we think about adding a generic #type => renderable to core itself, which then likely should indeed use a lazy builder (though it can't as its an object) and only allow manipulation on the object itself OR by unwrapping it (and accessing #renderable property to early render it).
So that would take Xano's BC concerns into account and give contrib all the flexibility it needs, while ensuring that renderables can be used far and wide (and are controlled from core).
@Sam152: Thoughts?
---
Edit:
Hmmm there is _one_ advantage to the object itself and that is that neither lazy builders nor #type are allowed to return #cache properties.
However there is a very simple workaround:
Just use a child item in #pre_render:
e.g. in RenderableObject::preRender()
So the only ugliness is that someone could overwrite #type information, though maybe that is good if additional things are needed to add to the object itself.
--
TL;DR: Object in render array => no go as Xano described (got that now), adding generic support for '#type' => 'renderable' => lets discuss that!
Comment #25
fabianx commentedComment #30
markhalliwellComment #32
MerryHamster commentedReroll #7 patch for 8.7x
Comment #33
MerryHamster commentedComment #34
MerryHamster commentedComment #35
andypostComment #42
jonathanshaw#22 and #24 agree on the problem:
Here's one approach to solving this making use of php 8's throwing TypeErrors for non-array inputs to array functions:
1. Have RenderableInterface extend Traversable, Iterable and ArrayAccess, so most code can continue to work without trouble.
2. Create RenderableBase and RenderableDefault classes implementing RenderableInterface
3. In Renderer::doRender() begin by casting $elements into a RenderableDefault if an array is passed
4. In Renderer::doCallback and ThemeManager::render, try with a RenderableInterface and fall back to array with a deprecation error:
This allows us to gracefully change the expectations about what is passed to theme hooks. Once the system is passing objects around, it gets easier to improve how we are using them.
Comment #45
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #need-reveiw-queue. We are working to keep the size of Needs Review queue [2700+ issues] to around 200, following Review a patch or merge require as a guide.
Would like to see an approach like #42 for 10 (where php8 is required)
Comment #46
smustgrave commentedAlso if that is the approach the issue summary should be updated to reflect that.
Comment #48
geek-merlin