Problem/Motivation
Since Drupal 8 we've done some work to remove 'magic array keys'. But we still have render arrays, which every time you use them cause you to need to look-up the allowed keys. This is really bad DX. It's not clear what the allowed keys are, or where to find them. For backend developers who don't have years of experience with the nuts and bolts of Drupal's rendering system, this is more of a learning cliff than a learning curve, and it's very discouraging.
Proposed resolution
Provide builder classes for each element type to make defining render arrays discoverable from IDEs.
before
$variables['table'] = [
'#type' => 'table',
'#header' => $headers,
'#rows' => $rows,
'#attributes' => [
'id' => $table_id,
],
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => $weight_class,
],
],
];
after
$variables['table'] = TableElement::create()
->setHeader($headers)
->setRows($rows)
->setAttributes([
'id' => $table_id,
])
->setTableDrag([
[
'action' => 'order',
'relationship' => 'sibling',
'group' => $weight_class,
],
])->toRenderArray();
This sort of interface is a lot clearer, and borrows heavily from both Url helper and FieldDefinition stuff.
In this issue, we should only introduce a base class for these builders, plus one or two concrete implementations that we use in core, to prove they work. Then, in follow-up child issues, we can introduce more builders for the various core elements, piecemeal.
Remaining tasks
Refactor the patch in #106 to modernize it -- i.e., adding type hints -- and remove most of the builders it implements (punt to follow-ups). Keep one or two useful builders, and change core to use them where possible. Add unit or kernel test coverage. Then review and commit.
Manual testing
- To check DropbuttonBuilder: go to
/admin/content, check that the dropbutton display correctly - To check ImageBuilder: go to
http://drupal.local/en/admin/help/contextual, make sure the icon displays in the help text
User interface changes
None
API changes
Creates a new optional way to create render elements.
| Comment | File | Size | Author |
|---|
Issue fork drupal-2316941
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:
Comments
Comment #1
larowlanComment #2
larowlanComment #3
chx commentedEdit: nevermind.
Comment #4
larowlanFrom irc I was asked 'but we don't have these for tables' etc
But we could.
This adds TableElement.
We don't need to do everything now, but this minor change means we could do it later.
Comment #5
xtfer commentedI've written some of these for my own purposes in the past. They are quite useful. A general +1 from me.
Comment #6
joelpittetI agree with @chx, make a template if possible. Also though, #type=>table won't go away that easy and this would make them much easier to build! so +1 from me too
Comment #7
tim.plunkettThis has some interesting overlap with #2305839: Convert hook_element_info() to annotated classes
Comment #8
larowlanRemoved InlineTemplate helper, too contentious.
Started out hating on #type => inline_template, but that's not the issue, the issue is render arrays keys are magic.
Removing InlineTemplateHelper to focus on the real issue.
Comment #9
larowlanNote this can totally go in 8.1 or later - just pointing that out.
Comment #10
jibranI think we should add a setRow() method as well to add a single row to rows. Just a thought.
Comment #13
kim.pepperWhat about just
RenderableInterface?Comment #14
dawehnerNice idea in the first place!
I think for now we cannot support this line, rather people which create the form have to explicit call it on the render element. The problem is that we lose consistency for example when we do alter the elements.
Can we use some reflection on the object to figure this out maybe? This would dramatically improve the DX of writing those helpers
This feels wrong given how I consider URL as a value object, not something you directly render but yeah it does have the method as well
Comment #15
fabianx commentedAll for it, but this will need benchmarks to show how bad the performance hit of adding many many more function calls is ...
Comment #16
jhodgdonSo...
For the really big win here... We are already proposing defining the render elements themselves as plugin classes on #2305839: Convert hook_element_info() to annotated classes. Is it possible that we could, instead of having 1 class that defines the render element as a plugin, and another that lets you insert it into a render array with various properties, we could combine all of that into one class? Because they both need to know what the properties are...
Comment #17
larowlanI agree, and have spoken to tim about combining forces
Comment #18
star-szrJust want to check in here, I confess to not having read much here but #2305839: Convert hook_element_info() to annotated classes has been in for a while now. Is this issue still relevant?
Comment #19
larowlanNew name because #14 rightly points out that this has to talk in arrays still, but no reason we can't have nicer DX.
Also this can go in contrib or later
Comment #20
larowlanComment #21
larowlanComment #22
larowlanComment #23
jhodgdonI believe that this issue is properly classified as a feature request, not a task. It is adding a DX feature, right?
Even if it isn't a feature request... If it's a task, it isn't Major or Critical or in one of the "Unfrozen" or "Prioritized" categories. So at this point, unfortunately, I believe it needs to be pushed out to 8.1.x or a later release according to #2144413: Config translation does not support text elements with a format. If you disagree with this conclusion, my suggestion would be to reclassify and add a comment and a piece in the issue summary explaining why it fits into one of the categories of tasks/bugs that need to be done now.
Meanwhile, looking at the patch... I have a few docs suggestions:
a) You definitely need to add something to the Render topic about this functionality, so that developers can discover that it exists:
https://api.drupal.org/api/drupal/core!modules!system!theme.api.php/grou...
b) RenderElementBase has no documentation header at all.
c) RenderElementInterface has barely any documentation. I think it should explain what the class is used for and how to use it. Then the hypothetical section in the theme_render topic can be short and link to this class for further information.
d) RenderElementInterface::toRenderArray() references drupal_render instead of drupal_render()... but actually that sentence is misleading, because actually drupal_render() calls this method itself... That aside, the phrase used for this all over the rest of our documentation is "A render array suitable for drupal_render()" I think?
e) TableElement first-line docs do not end in . and a couple of the member variable docs headers are missing the blank line before the @var.
f) So... At this point reading the patch for TableElement, I'm like , uh.... is this really better than just making a render array directly? And if so, why? I don't really see the benefit of this whole patch. You've added a bunch more classes, just so that you can do this in field.inc:
before:
after:
This is about the same number of lines of code and I don't see that it is all that more understandable. And there's overhead to take this simple object and convert it back into an array.... Why do we want to do this at all? I don't get it.
g) I also don't see why you need all the get() methods on the helper object. They are not ever used and I can't see a reason why they would be.
Comment #24
larowlanHi @jhodgdon agree totally about a) feature request b) 8.1.x (or even contrib) c) the patch is rough (proof of concept) but in terms of 'whats the point' if you try and use the array format if you don't know what the keys are - there is no discoverability - you have to lookup the reference.
With the builder pattern - after you type TableElement::create() all the methods will autocomplete with your IDE.
So its completely about DX
Comment #25
jhodgdonAh, I see -- for the convenience of coders, at the probable expense of performance (that needs to be checked, but probably can't really be until we have more of these builder/helpers in place so that you can try building/rendering a typical page with mostly builders and see how much it slows down).
Comment #26
jibran@larowlan are you interested in working on it in a sandbox as a contrib module?
Comment #27
sam152 commentedThis is an awesome DX improvement. I had a go at what a contrib solution might look like for this problem: https://www.drupal.org/sandbox/sam/2485729
It's a tad rough at this stage, but a great POC. I must admit after spitting out a few images in a matter of seconds, I didn't feel it would be much fun to go back to blindly guessing keys and waiting for an error.
Comment #28
jibranThat looks awesome. It can be a handy drush extension in D8.
Perhaps we can define @param type for all the setters by parsing function doc or something.
Comment #29
sam152 commentedThanks for the feedback Jibran. We actually have access to the default values for each variable in the theme definition so we can kind of derive the type from there. Arrays and bools are fairly straightforward and string usually default to NULL.
Comment #30
benjy commentedAwesome, i'm glad someone has started this in contrib.
Comment #31
fabianx commentedGreat sandbox, please see #2485995: Please do not render early, return render arrays instead for an issue with the current DX, early rendering is a little problem atm. (also for attachments)
Comment #32
sam152 commentedThanks for the feedback. I'll continue the conversation in the issue you created.
Comment #33
sam152 commentedIf there was a patch generated to provide these wrappers for core is the suffix 'Element' too overloaded given Drupal\Core\Render\Element\Table exists and we are proposing introducing Drupal\Core\Render\TableElement? If they are "builder classes" why not use 'Builder' as a suffix for clarity. IDE integration for class inclusion will also probably match less results with 'builder' as a keyword.
They could probably also do with their own folder, perhaps 'Builder' inside 'core/lib/Drupal/Core/Render' making the final namespace for the table builder class 'Drupal\Core\Render\Builder\TableBuilder'.
Comment #34
sam152 commentedHere is a patch which adds functioning builders to core using a modified version of the contrib solution posted above. I think the script that builds the method names needs some work and things like the naming convention and namespace will need agreeing upon, but it's an example of what a patch for this issue could look like.
Comment #35
sam152 commentedTestbot
Comment #39
sam152 commentedComment #42
benjy commentedwrong version for a testbot run.
Comment #44
sam152 commentedAh, good catch. Thanks.
Comment #45
sam152 commentedAdded some extra builders, removed some useless keys.
Comment #46
fabianx commentedJust to not give any illusions, but being a feature request this can only go into 8.1.x.
Testing and making patches is fine however - of course :).
Comment #47
dawehnerYeah I agree with @fabianx that this is a 8.1.x feature, BUT a really great one.
I'd even call this one of the most influential one, if you are honest.
Comment #48
sam152 commentedGood to hear the efforts aren't going to waste. I've been looking over the current progress and methods on each of the builder classes aren't good enough. I can't find a reliable way of determining the keys that are available for each one of the builders. From what I can tell things are documented as a combination of the keys inside getInfo and the preRender method comment.
Docs from 'Range':
Compared to docs from HtmlTag:
My feelings are that the list of elements and the appropriate methods will need to manually be built. I don't think this will be a big problem in the scheme of things and there is probably a fair bit of code that can be written to make the process of extracting meaningful information from the comments/info methods a lot quicker.
Unless anyone has a recommendation I haven't come across for deriving appropriate methods I'll proceed with getting this underway. The alternative that I can see is a method similar to 'variables' on hook_theme which documents the keys on the element. Not sure how feasible or useful this would be outside this use case.
Comment #49
sam152 commentedI have attached a new patch which address a number of issues:
On a cursory play around with the result, the builders seem more accurate and are improved by the base class.
Comment #50
sam152 commentedComment #51
sam152 commentedComment #53
sam152 commentedMay as well get it green.
Comment #57
joelpittetI do really like this, especially for the Table. This looks ripe for refactoring. Can tableselect extend table builder?
If each builder sets the renderable array type, do we need a setType? Maybe you can cast between builders and remove that method?
Can these setter methods be added to the base class to avoid the duplication?
Comment #58
sam152 commentedThanks for the feedback.
I'm interested to hear thoughts on how we could cast between builders of different types. Right now, we could add a key that sets 'type' but then you could have an instance of a builder which represents entirely different output. Perhaps the create method could accept an array of keys so you could:
Comment #59
dave reidNo beta evaluation means this needs to go to 8.1.x.
Comment #60
joelpittetYeah this has to get postponed to 8.1.x unfortunately, luckily it's a good candidate to be included as a feature in 8.1.x but right now it would likely just block or distract from issues blocking release.
Love this issue though, wish I could favrouite issues:)
Also to respond to #58 certain and most types it would be very tricky to cast between because there may be very few keys. But if you could turn it into an array, change the type and pass the array into say the new builder's constructor, that may work.
Comment #61
sam152 commentedSorry, version was just for the test bot.
Comment #62
sam152 commentedGoing to bump this for reviews now that we almost have a release and core is slowing down.
Comment #63
Crell commentedNote that core recently added a RenderableInterface, which is for objects that can be dumped to a render array. It's already being used in core. Any additional builder utilities (which I support) should tie into the same system. Ideally, they object can just be stuck directly into the render array and the render system will extract it as needed. (We should verify that works for all objects in core, but I think it does?)
Comment #64
sam152 commentedI've implemented RenderableInterface. Not sure how the objects tie into rendering and if they can be used interchangeably with the array equivalent. From what I can see they are only supported as renderable twig variables but this could probably be tied into the Renderer easily enough.
Comment #65
dawehnerWell, theoretically this should indeed just works, but to be clear, we need to not try to go too many steps at the same time. Having a 150k patch seems to be one of those.
Comment #66
fabianx commentedCan we move that into a contrib module for now so its usable for people that want / need that, then include the patch here step-by-step for 8.1.x?
Comment #67
sam152 commentedI have opened #2602368 to look at allowing RenderableInterface to be treated as a renderable array.
I can stick these in a contrib module. The original idea of the contrib module was to provide a build process to automate the creation of the classes but I think it makes sense to keep those two concerns separate for those who just want to leverage the ones in core.
Comment #68
sam152 commentedTestbot ahoy.
Comment #69
joelpittetCan this be factored out any further to reduce some of the duplicate methods and maybe slim the patch down?
This grid may help visualize where the grouping (base classes) could occur
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.h...
Comment #70
sam152 commentedI don't think we should introduce any base classes unless there is actually a polymorphic relationship in play. It could get very messy, difficult to follow and I think the value might be limited. By it's nature I don't think this patch will be very DRY.
Perhaps I could get on board with a more concrete example?
Comment #71
Crell commentedIf all you're doing is avoiding boilerplate code, traits are a much better solution than base classes.
Comment #72
joelpittet@Crell hoping to get some logical groupings of types elements not at all a goal to avoid boilerplate.
Comment #73
sam152 commentedWe already have inheritance where it exists for the element definitions. Traits are an option for the grouping but not sure how much value they will bring given we already have a lot of methods on the base builder and the form element base. Happy to look into that in any case.
If the feedback at this stage is optimisation related, can it assumed the approach and structure are validated?
Comment #74
jibranShould we add some tests to theses classes?
Comment #75
cilefen commentedMy rule of thumb is to test anything new and anything that has broken in the past.
Comment #76
cilefen commentedThis needs a change record because it is a new API.
Comment #77
xanoThe core responsibility of our current render element plugins is to provide render arrays (that's essentially what "element info" has always been in Drupal). As @jhodgdon suggested back in #16, can't we add the additional builder logic to these plugin classes? That will make them easier to find, and will allow us to build on top of the current plugin swappability.
Comment #78
xanoThis is an extremely bare example of what I mean. Element plugins' builds are part of their internal configuration (which can be imported and exported verbatim through
ConfigurablePluginInterface), and the base class automatically renders this based on elements' default info and optional cacheability metadata. Any child class can choose to expose additional methods to modify the build. This approach lets us convert elements individually, so we can gradually move towards an OO API for render elements, while maintaining compatibility and integration with our current approach.Comment #79
xanoComment #80
xanoSince we cannot entirely replace render arrays with objects because of BC (see #2602368: Allow objects that implement RenderableInterface to used interchangeably with render arrays.), here's a method to help configure elements based on render arrays, so we can easily alter render arrays by creating and configuring elements using this method, then export them back to render arrays using
::toRenderable(). I think it would be useful to add::createInstanceFromRenderable()toElementInfoManager, which isn't really just an element info manager anymore... We cannot add this method toElementInfoManagerInterface, because that would break BC.Comment #81
xanoComment #82
xanoThis will even allow elements to implement
PluginFormInterfaceto provide their own configuration UIs, which could be useful for form building tools.Comment #83
sam152 commentedThis was discussed in detail over IRC. Logs are here: http://codepad.org/CToqn2yu
Would appreciate some outside perspectives.
Comment #84
benjy commentedDoes $this->getInfo() give us parity with the builder patch in #64, it was my understanding that "build" array in the builders patch had been manually constructed from a number of places?
I think the IRC discussions touch on it, but it does feel like we'd be making a step towards an OO Render API without actually knowing if it will be a step in the right direction. However, adding the builder classes gives us the DX improvement now and I can see that in the future, regardless of what direction our OO Render API goes in, we'll be able to update those builder classes to return instances of something that make sense in the new Render API.
Also, I think the IDE completion has to be solved, for me, it's a primary part of this issue.
Comment #85
xanoOnce we have introduced and released any new classes, we can only alter parameter and return value types as long as those do not violate the Liskov substitution principle. This is especially relevant to class dependencies, because the original builder classes do not use generic factory methods for their dependency injection.
My patches use
::getInfo()to provide default build arrays, something which any builder solution should be able to do using whatever implementation we see fit. Adding these defaults in the builder gives us more power to build arrays (e.g. we can depend on default property values, check/compare them and act depending on their values).Comment #87
sam152 commentedComment #88
eric_a commentedWhy don't we add a render element type that uses #lazy_builder to build a render array out of a proper ViewModelInterface object?
This #lazy_builder callback would be focused on mapping ViewModelInterface to a Drupal render array. Then Drupal\Core\Render\Renderer(Interface) and Drupal\Core\Render\Element\Element(Interface) don't risk becoming too complicated. We can use the same old renderer for now.
(It remains to be seen if we can easily implement full mapping of something resembling Zend\View\ViewModelInterface, but still.)
Comment #89
xanoBecause it's not about when we build the render array, but about having a typed API to work with for improved DX.
#lazy_builderwill not help with that.Could you clarify how you expect the renderer to get too complicated? Also, how does Zend's
ViewModelInterfacefit into this issue? We're not all familiar with it.Comment #90
eric_a commentedA
#lazy_buildercan help with last-minute converting typed data to a render array suitable for the Drupal renderer. Using a separate converter is a nice alternative to each object having knowledge how to convert itself to Drupal render arrays, like withRenderableInterface. To me the separate converter sounds like the simplest solution with regards to our current renderer.I haven't delved too deep into the patches, I'm sorry if I'm misunderstanding the issue summary.
Zend's
ViewModelInterfaceor similar would be your typed API alternative to 'magic array keys'.http://framework.zend.com/apidoc/2.4/classes/Zend.View.Model.ModelInterf...
http://framework.zend.com/manual/current/en/modules/zend.view.quick-star...
Pseudo code to compare with the issue summary:
Comment #91
xanoThat would work and wouldn't be a BC break. It would, however, mean that quite some code may be converted to this, and that dependents would have to increase their minimum requirements. This is in accordance with our policies, but I expect it is a large and disruptive change, especially since both the render array and the object would have to provide the ability to contain children, which begs the question which tree of children would get priority over the other. It sounds similar to #2602368: Allow objects that implement RenderableInterface to used interchangeably with render arrays., but without the BC break.
Comment #93
xanoComment #94
fabianx commented#79 and #81 should live in its own issue - please - as they are unrelated to this issue - which is about adding the builder pattern to create renderable arrays.
And I really like #90.
Traversing is definitely still a problem.
I also will comment on #2602368: Allow objects that implement RenderableInterface to used interchangeably with render arrays. as I forgot to do so.
Comment #95
fabianx commentedComment #96
xano@FabianX: Please include arguments supporting your claim that is #79 out of scope. The patch shows a builder pattern, but based on our existing element plugins for future compatibility, rather than by introducing another new concept.
Comment #97
fabianx commented#96: First: Pardon if I came through to harsh. Not meant like that.
Second: Please Fabianx (with lowercase x) - that is important as d.org is not case-insensitive.
Third:
Your patch might enable contrib to do so, but it does not match the issue summary and it feels that it is an implementation detail of Sam's patch.
I have "hijacked" issues before myself (and likely that was not always the best idea - as I had to learn, too - sometimes one is just so enthusiastic :D) and I am not saying it is bad, but I feel that Sam's patch, IS and idea goes into a very specific direction and especially introduces examples, while your patch goes into another and is very generic and abstract.
I of course might be wrong here, but my feeling is still that a new issue would be appropriate as I feel the architectural approach is different, which usually happens when the IS does not match.
With a good IS and supporting arguments your patch might be long in, while this one is still debated. So there might be something for you to win, too.
If things end up similar again, it might be a good idea to merge again or one issue might deprecate the other.
I hope my arguments for the general feeling I got have been easier to understand now.
Comment #101
larowlantagging
Comment #103
markhalliwellThis concept is something that I think is desperately needed in core.
We've been doing something similar in the Drupal Bootstrap base theme for a few years now, but not as "type" specific as this:
http://cgit.drupalcode.org/bootstrap/tree/src/Utility/Element.php
I've been working on abstracting this into a separate module though, Drupal+:
https://cgit.drupalcode.org/plus/tree/src/Utility/Element.php?h=8.x-4.x
Ultimately, I think core needs better utility classes in general, but I think it's going to have to start from the very basics: #2972143: Create \Drupal\Component\Utility\ArrayObject.
---
Regarding this issue specifically, I think the patches from #79 onwards, while similar, are really a separate issue altogether. I think we should keep this issue focused on the helper classes themselves.
I am going to set to CNW though because I don't think extending from RenderElement is the most appropriate thing to do.
These objects are ultimately just glorified arrays and I think we need some better groundwork (#2972143: Create \Drupal\Component\Utility\ArrayObject) in place first before continuing.
Also, not a huge fan of using the "Builder" suffix nomenclature on all the classes here. Seems a bit overkill, e.g.
Table::create()works just fine.Another thing that this issue should think about is allowing these element classes to be subclassed. Themes (especially base themes) will need to participate in these classes somehow. #2869859: [PP-1] Refactor theme hooks/registry into plugin managers may be able to help in this area eventually.
Comment #104
markhalliwellComment #106
kim.pepperRe-uploading #64 with some code style fixes, and to see if the testbot still likes it.
Comment #113
phenaproximaComment #115
kristen polTried to get a patch via gitlab and then apply it manually but it's not applying cleanly. Maybe this is due to how I'm getting the patch?
https://git.drupalcode.org/project/drupal/-/merge_requests/610/diffs.patch
Comment #116
tim.plunkettIdk what the terminology is, but that's a patch formatted for
git am. Each commit is a portion of the patch (see theSubject: [PATCH 1/7] Patch #106.in the header)If you instead use https://git.drupalcode.org/project/drupal/-/merge_requests/610.diff (which is linked at the top of the issue as "plain diff") will have the patch as you usually expect it.
Comment #118
nod_Been through the issue and I see that one of the reason for this is DX but there hasn't been discussion about the actual DX beside "IDE autocomplete". I guess it was a bit too early then, so can we talk a bit about what will be the DX of actual developers? like why are we prefixing all methods with
set? especially since there is nogetmethods. I think we can borrow from JS/jQuery/DOM as far as DX goes.What is the current API in the patch:
What I would expect:
It's starting to look a bit like the DOM, except it's not; so we might need to explain clearly why we didn't go with that (IDE autocomplete, returns an array, not a string, Drupal elements don't map 1:1 to HTML elements, etc.)
About having a list of what goes where, like said in #48 looks like it'll need to be a manual step. As far as human documentation goes once the list is done, since it looks like the DOM, the MDN pages for DOM elements and attributes are a pretty good examples IMO. I like using it at least.
This also makes render array somewhat similar to the DOM… so Drupal Object Model, or DRAMA (Drupal Render Api Model Abstraction) :þ?
Comment #119
nod_Umm I guess there are some existing code that use the set* pattern, still better than render arrays :)
Here is a patch for D10
Comment #120
mallezieAdded a comment about the phpstan fails in #3259355: Always do a full phpstan analysis on DrupalCI
This will need to be tackled first probably.
Comment #121
mallezieNever mind my above comment. Phpstan is right here. Classes mentioned do not exist (anymore).
Comment #122
nod_yeah forgot to add the new files to my patch…
As per the issue summary I remove all the extra code that is not related to the image builder. I do not understand why we add methods to the
RenderElementclass, it seems completely unrelated. In any case I rerolled the patch with the bare minimum to make the image builder work according to the merge request.Comment #123
nod_Ok read the logs in #83 which explains why stuff is in renderElement. I'm with Sam152 from 6 years ago personally.
The new MR against 10.x is using code from #64. Not trying to be fancy, just providing IDE auto-completion to create render arrays. It's been years since the work started and #64 would have been a net improvement compared to the still current situation. Solution proposed from #79 feels like too big a step to wrap this issue up in a reasonable timeframe.
I updated the method names to remove all the
setprefixes because it's nicer to work with. It's missing almost all the render API stuff, there is just enough to replace#theme => image. We can talk about what should be a trait, in the base class etc. once we agree to go the "easy" way :)Comment #125
nod_Added type hints
Comment #126
nod_Back to green
Comment #127
jibranI think we should add
setprefix to all the setters because it makes it easier to drill down all the setters. Should we add__setas well toBuilderBase?Then
can also be
Comment #128
nod_If we don't declare width/height/alt explicitly an rely on __set, we're loosing the IDE autocompletion no? Also how to document the various possibilities?
In the case of dropbutton it allows us to alias properties nicely (assign
#dropbutton_typeby calling->type()for example)In my mind there are nothing else than setters so it's redundant to prefix them. Those are helpers to generate render arrays, altering the render array is still done old school (where you need to know the magic keys names)
Comment #129
larowlanYeah I opened this (7.5 years ago) because I was tired of looking up random array keys in docs, using magic setters is no better in my opinion
Comment #130
kristen polIt would be good to add testing notes in the issue summary so we know how to manually test this.
For example, the following changed so I assume that checking the pencil icon is showing up would be sufficient for this one.
Comment #131
nod_MR doesn't apply and #130
Comment #133
bhanu951 commentedI have re-rolled patch for 10.1.x branch, but as the initially MR is raised against 10.0.x branch It is showing as not mergeable. Anyone with edit access can pls change the target branch to 10.1.x so we can check MR status. Thanks. #130 needs to be addressed.
Comment #134
nod_thanks, updated he branch
Comment #135
bhanu951 commentedComment #136
nod_reroll looks good
Comment #137
nod_We still need to add typehints and all the fancy php 8.1 stuff that's available now. leaving as NR just to get more eyes on it before sinking too much time here :)
Comment #138
manuel garcia commentedUpdated summary examples array() -> []
Comment #139
volegerAttaching related issue for #states builder. #3011365: Introduce FormElementStatesBuilder for #states key of form element render array
Comment #140
smustgrave commentedWas tagged for tests and change record that I believe still need to happen.
Comment #142
chi commentedPHP has evolved a lot since this issue was created. Type hints, property promotion, named arguments, etc. So instead of builders we can create value objects. It'll give same DX in modern IDEs.
Builder
Constructor
Comment #143
chi commentedOverall, this will only mitigate the problem. Dropping render arrays is the only way to fully resolve the issue. I’ve filed a ticket in the ideas queue.
Comment #144
andypostComment #145
oily commentedComment #146
oily commentedAdded change record based on the current issue description.
Comment #147
oily commented@chi Re: #143 Good point. But this seems like a major step/ leap forward. I hope this issue be completed as-is as a first step?
Comment #148
chi commented@oily The are dozens different render elements in Drupal core. The MR currently covers just a few ones.
Comment #149
ghost of drupal pastif people want to go ahead with this -- and I am not saying they either should or they should not, I really have no advice on that -- then, if someone wanted the opinion of an old ghost then #142 is the way because then it's possible to add
RenderElementBase::fromRenderableso that form alter does not need to deal with arrays either. Otherwise, people would need to learn both syntax to be able to debug code. Not to mention how much less code would this require in core. One could even save this gist, rundrush scr buildergenerator.php; composer phpcbf $(git diff --name-only core)and then smooth the results. Not saying you should, but, you know, you could. https://i.imgur.com/0Xt8Puu.png https://i.imgur.com/F6e8c1h.pngComment #150
larowlanYes, agree #142 is nicer and it also gels with some thinking I had in this experiment
It also means we might not have to add new classes for everything, we could possibly use the existing render element plugins but instantiate them.
Comment #151
andypostComment #152
catch#2702061-106: Unify & simplify render & theme system: component-based rendering (enables pattern library, style guides, interface previews, client-side re-rendering) and downwards is relevant, but the most likely outcome would be that the number of different elements is reduced, and eventually #theme gets dropped in favour of #type component, but don't really see any reason that this couldn't all be worked on in parallel without explicit dependencies.
Comment #153
ghost of drupal pastI tried #142 but the amount of methods you'd need to add is staggering and at the end of the day since people use arbitrary properties in render arrays you would need to support some sort of set/get anyways so I leaned heavily on that and so #3525331: Reuse element plugins as object wrappers around render arrays is born. If that issue gets accepted this issue might be outdated.
Comment #154
nod_I spent quite some time working on making just 1 conversion, I agree with #153, this is not the way to go about it. #3525331: Reuse element plugins as object wrappers around render arrays is a much nicer solution.
Comment #155
pdureau commentedYes, extending existing Render Elements classes (as proposed in #3525331: Reuse element plugins as object wrappers around render arrays) looks better than adding a Builder class for each Render Element as proposed in the current MR.
Also, when we will replace most (but not all 😉) of Render & Form elements by SDC, all the logic to remove will be contained in a single file.
Comment #156
catchI think this is good background reading for the other issue, but let's explicitly postpone it on that one.