Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
The Context class currently uses an array to represent its definition. It almost exactly mimics the DataDefinition class, but is not actually a definition of data.
Arrays are not an API!
Proposed resolution
Replace the array definition with a new ContextDefinition/ContextDefinitionInterface.
This code was already developed for the D8 Rules port, and works well for the Page Manager use case as well.
Remaining tasks
Write the patch
User interface changes
N/A
API changes
The all-but-unused Context class will no longer deal with arrays, but objects.
Comment | File | Size | Author |
---|---|---|---|
#58 | 2281635-58-interdiff.txt | 4.5 KB | EclipseGc |
#58 | 2281635-58.patch | 58.86 KB | EclipseGc |
#56 | interdiff.txt | 6.11 KB | fubhy |
#56 | 2281635-56.patch | 58.53 KB | fubhy |
#46 | 2281635-46-interdiff.txt | 3.59 KB | EclipseGc |
Comments
Comment #1
fagoThe code developed so far lives in https://github.com/fago/rules/tree/8.x-3.x/src/Context - so we can get started with move it to Core instead and improve it as necessary.
Comment #2
tim.plunkettComment #4
blueminds CreditAttribution: blueminds commentedWill work on this as part of the layout sprint: https://groups.drupal.org/node/423448
Comment #5
blueminds CreditAttribution: blueminds commentedWould need some help here.
For example the LanguageConditionTest, here is the code that fails:
What happens when calling setContextValue() is that it tries to set the $language object into the context found under the 'language' key. But that blows up because there isn't any definition for 'language' key in ContextAwarePluginBase::contextDefinitions. From reading the code I understand that the static contextDefinitions() should provide these definitions, but I do not see it implemented anywhere.
The patch also adds ContextInterface into Core/Plugin/Context dir, and this interface does not seem to be used.
Comment #6
blueminds CreditAttribution: blueminds commentedJust a reroll as ContextAwarePluginBase ended up with conflicts after merge with latest HEAD.
Comment #7
blueminds CreditAttribution: blueminds commentedComment #8
blueminds CreditAttribution: blueminds commentedwrong patch... retry
Comment #11
blueminds CreditAttribution: blueminds commentedWith big support from @fubhy here comes the patch. It still does not do the merge of context definitions with other plugin configuration, that is to come after the review of the current state.
Comment #13
fubhy CreditAttribution: fubhy commentedThat needs a type hint to the ContextDefinitionInterface
White space issue. Anymore is one word :)
That should use $this->getTypedDataManager().
Thats not true anymore :)
Documentation missing for the @param and @return value.
Should return $this.
Shouldn't that be @see?
Misses documentation
That leading \ is redundant.
Misses documentation.
We need to inject the typed data manager there. So that means we should extend the ContainerPluginFactoryInterface here.
Without the dash! :) (I think?!) :)
I would prefer testing the separate methods like ->getLabel(), etc.
Can you put these into their own code blocks? with Line breaks? :)
Can you name it $definitionss please?
Comment #14
blueminds CreditAttribution: blueminds commented- Implemented comments from #13
- Provided the TypedDataTrait as well as TypedDataAwareInterface as discussed in person with @fubhy. However I am not that sure I got right the interface as now to have something TypedDataAware the interface needs to be implemented as well as the trait used in the class.
Comment #15
blueminds CreditAttribution: blueminds commentedComment #16
fubhy CreditAttribution: fubhy commentedLets fix the documentation on the constructor too.
Missing typehint.
Missing typehint.
Missing whitespace before $.
Missing typehint.
The trait is good I guess, but we don't need that interface.
That's the data definition, not the context definition :).
As said before, I don't think we need that interface. :/
Comment #17
blueminds CreditAttribution: blueminds commentedYes, the interface is now gone. Other than that I fixed few minor things but there is one problem with context in component. As now the ContextInterface depends on TypedData stuff we have a problem in the component part. Discussed this with @Berdir and he suggested to move the whole Context thing into the core.
Comment #18
blueminds CreditAttribution: blueminds commentedSo after discussion with @Berdir and @fubhy we decided to move the ContextDefinitionInterface to component and having such interface also in core where it actually provides the only method coupled with TypedData "getDataDefinition()"
Comment #19
fubhy CreditAttribution: fubhy commentedShould be "Component" in both cases I guess ;)
2 newlines.
These references to typed data should probably not stay there if we move it to Component.
:)
This is in the trait so it should not refer to context
Comment #20
blueminds CreditAttribution: blueminds commentedThnx for review, all implemented.
Comment #21
fubhy CreditAttribution: fubhy commentedThat should be \Drupal\Core\...
Comment #22
blueminds CreditAttribution: blueminds commentedhopefully this time...
Comment #23
BerdirWondering, this is the only reason we have this whole complexity with injecting typed data manager, and having two interfaces...
Would not be as nice, but could we move this to the typed data manager and have something like createDataDefinitionFromContextDefinition($context_definition) (a bit long...
Would make it a bit more complicated to use, but it would remove a lot of complexity from this patch..
Not sure I like the method name, but have no better suggestion right now.
baseFieldDefinitions() and propertyDefinitions() are what the thing contains, this is what it needs.. but as I said, no better idea..
Comment #24
klausiI'm also not completely happy with the two interfaces, but I also don't see how this would look much better directly on the typed data manager.
The removed test cases seem to be fine, as they were asserting behavior that we don't want. Just returning NULL when the context is not set makes more sense.
Since this is already used by Rules and Page Manager in contrib I think this is a good step forward in making progress, so RTBC.
Comment #25
tim.plunkettI haven't tried using this yet...
Comment #26
EclipseGc CreditAttribution: EclipseGc commentedYeah no, we have a few problems here.
1.) Contexts in static methods... I am very against this. Yes it can work, but you can't use it this way, it has to be parsed back into the definition inside the manager.
2.) in addition to this problem, you have a problem of derivatives for plugins whose context changes. Case in point "Entity is of bundle" would need to change to "Node is of bundle", "Product is of bundle" etc. This is why contexts are on plugin definitions, and why they can be changed via derivatives. If you want to define contexts this way, please see point 1, but keep in mind that you are actively retarding the capabilities of plugin contexts through this methodology and generally making people's lives more difficult.
3.) In order to support plugins that CAN just define a single context (say user role) I have previously suggested (and still favor) a custom annotation class that returns a context definition object. Let's go that route. I think it will make life generally easier. If rules wants to define conditions this way, that's fine, it can hijack the condition manager service and parse contexts into its custom plugin definitions in its own way. Changing core's approach to this seems completely unnecessary and a complete deviation from the approach already set forth.
In short, this needs some work still. But I think it's got some good things going for it. Lets fix these problems and get this in.
Eclipse
Comment #27
blueminds CreditAttribution: blueminds commentedThere has been some discussion on how to proceed with this between fubhy and Berdir. They have not yet come to a conclusion on what to do here. For now unassigning as I do not know how to proceed.
Comment #28
BerdirYeah, not sure either.
- The current patch did not update filterPluginDefinitionsByContexts() at all, this would be completely broken now, I guess there are only unit tests that still use the old definitions?
- I don't think our current plugin system can deal with separate @annotations, so it would be easier to keep it inside the plugin definition just like we do right now?
- But then the question is who will give you context definition objects based on the current arrays.
- If you look closer at ContextHandler, you can see that it currently hardcodes the assumption that context definitions *are* data definitions, the reason we can't do that anywhere is that context definition and context in general right now is in Drupal\Component.
- I agree that the static method pattern doesn't make much sense because it's a completely different scenario than we have for typed data/field type property definitions, because those receive the field/data definition object and based on that, they can make the returned properties dynamic.
Comment #29
EclipseGc CreditAttribution: EclipseGc commentedI'm only going to address your 4th point for the moment berdir, just because I don't want this to get out of control.
I specifically didn't push for a ContextHandler in component. This is for reasons two fold:
1.) Drupal needs typed data (or similar) to really function at this level
2.) The plugin component is only interested in classes & interfaces. I have solutions for making that a REALLY workable tool, but drupal core and I have history there so I was seeking the road of least debate and didn't push tim & others toward build the plugin component element of this. I figured I could build it later and then change what's there currently to be a subclass.
In short, I still think my plan there is not bad, and will totally be stuff that can be feature addition instead of API change. Getting context in this way gave me a lot of leeway in terms of this being a relevant API in core today... otherwise we'd have to justify it all again.
I'll see if I can wade in here today and help with this patch, but I'm taking my family out here this morning, so it'll be a few hours.
Eclipse
Comment #30
EclipseGc CreditAttribution: EclipseGc commentedThis is just a reroll against head.
Eclipse
Comment #31
EclipseGc CreditAttribution: EclipseGc commentedOk, I ran a limited set of tests against this to make sure I didn't COMPLETELY break stuff. This introduces a ContextDefinition Annotation class and reverts all the static context definition stuff. I also updated the various context subscribers to continue to work, and updated the node type, user role and language conditions. All basically seems to still be working, a cursory run through the UI revealed nothing broken. I dunno that it'll just magically go green, but hey, I can hope. :-D
Eclipse
PS: Sorry for the lack of interdiff, this was hard to debug, and my normal flow didn't support an interdiff right off the bat. I'll try to get one up soon.
Comment #33
EclipseGc CreditAttribution: EclipseGc commentedFixed the Contextual Plugins tests, dunno what's up with Node Block functionality, but waaaay too tired to care tonight. Uploaded the interdiff between the last patch and this one.
Eclipse
Comment #35
EclipseGc CreditAttribution: EclipseGc commentedThis should fix the derivative tests. I had to move it to assertEqual() since we have an object in the definition now. (Thanks to fubhy for the explanation)
Eclipse
Comment #37
tim.plunkettHere's one fix. Though I think the removal of the other thrown exceptions in ContextAwarePluginBase is the rest of the problem, especially this one:
throw new PluginException("The $name context is not yet set.");
Comment #40
EclipseGc CreditAttribution: EclipseGc commentedOk, I THINK I got it. In addition to the problem's Tim found I looked through the changes in the Context classes (Core and Component) and found that in my haste to adopt what looked like generally saner approaches I removed some of the exception throwing we were depending on which was the root of the problem Tim found. Without both of these fixes all hell breaks loose.
I attempted to update the docs as well to better illustrate how this works (and also to not be a direct copy of @Translation()).
Eclipse
Comment #41
EclipseGc CreditAttribution: EclipseGc commentedAlso, while I'm at it, here's an interdiff from 30-40 which will hopefully give a better snapshot of the whole set of changes from what was initially proposed here.
Eclipse
Comment #42
fubhy CreditAttribution: fubhy commentedBeautiful!
This is not about micro optimization or anything... I just find that it looks ugly to do the same chaining twice. Can we do like $definition = $this->getContextDefinition(); and then continue from there? :)
That looks rather sub-optimal but I can't think of a better solution right now.
Wrong "Contains".
Newline.
Same as before.
Redundant leading backslash.
:)
Comment #43
EclipseGc CreditAttribution: EclipseGc commentedOk then, how about now?
Eclipse
Comment #46
EclipseGc CreditAttribution: EclipseGc commentedThe previous tests expected required contexts to return a NULL when they are not set, however only optional contexts perform this way. Updated the existing test for the proper response and added a plugin definition & test for the different optional context logic.
Eclipse
Comment #47
fubhy CreditAttribution: fubhy commentedReally good. RTBC from me ...
Redundant leading backslash.
Comment #48
er.pushpinderrana CreditAttribution: er.pushpinderrana commentedRemoved redundant leading backslash in this patch. Please review.
Comment #49
fubhy CreditAttribution: fubhy commentedComment #50
EclipseGc CreditAttribution: EclipseGc commentedFubhy pointed out a couple of doc issues. I took care of them. Just a docs issue so the RTBC should stand.
Eclipse
Comment #52
EclipseGc CreditAttribution: EclipseGc commentedRerolled for HEAD
Eclipse
Comment #53
tim.plunkettBased on our usages in core thus far, I think we'll have far more context definitions with labels than we will optional or multiple definitions. Can we reorder these to put label second?
I don't think its too much to ask, since we're adding this now (punting to a follow-up doesn't make much sense).
Comment #54
tim.plunkettWell actually, I guess those aren't *that* bad.
If someone has time to reroll this with the swapped constructor it'd be nice, but it shouldn't hold up commit.
Comment #55
EclipseGc CreditAttribution: EclipseGc commentedYeah, the setters still exist and the constructor values are sane defaults, so this shouldn't be any more difficult to use before I added the parameters to the constructor. I'll file a follow up to change the order.
Eclipse
Comment #56
fubhy CreditAttribution: fubhy commentedDid that real quick ...
Comment #58
EclipseGc CreditAttribution: EclipseGc commentedThis should fix the broken tests.
Eclipse
Comment #59
tim.plunkettOoh, thanks! @fubhy++ @EclipseGc++
Comment #60
EclipseGc CreditAttribution: EclipseGc commentedAfter a bit of Discussion it was determined that we didn't need a Change Notice for this, so I think this is ready to go in any time. I'm working on adding docs to the plugin handbook currently.
Eclipse
Comment #61
webchickCommitted and pushed to 8.x. Thanks!
Comment #62
tim.plunkettThis didn't get pushed.
Comment #63
webchickSigh. :P Always the last patch of the day. :P
Comment #65
EclipseGc CreditAttribution: EclipseGc commentedThanks!!!
Comment #66
tim.plunkettFollow-up #2292889: ContextHandler does not expect ContextDefinitionInterface :(
Comment #67
Jose Reyero CreditAttribution: Jose Reyero commentedHi, me late as usual, following the track of TypedDataTrait that magically popped up in TypedData...
It looks like this one is adding a new (poorly named btw) trait that adds "magic" *public* methods to classes and are not part of any interface....
Also it seems there's a new interface that mostly duplicates DataDefinitionInterface interface instead of maybe fixing / extending it...
Now I'm thinking about:
a) Reopening this one to properly document why / what for we've got two new interfaces, why we cannot reuse existing ones, etc... Does this look like enough explanation for any of them?
Or is there any follow up for that?.
b) Making that new trait's methods part of some existing interfaces to be able to address issues like #2053415: Allow typed data plugins to receive injected dependencies
Anyone working on / interested on / is there already any other related issue I'm missing..?
Comment #68
EclipseGc CreditAttribution: EclipseGc commentedBefore we filed this issue, I was leveraging DataDefinitionInterface for all of this stuff. Fago, Tim Plunkett and myself had long discussions over fago's approach which is essentially what we've adopted here. I too wanted to find a common interface for these, but what we have here is a problem of dependencies. Plugins (and context is part of plugins) are a stand alone php component. Typed Data is not (yet). Building a dependency here was not feasible, and as fago will tell you, despite the marked similarities of these two systems (ContextDefinitions and DataDefinitions) they are in fact separate things for separate uses. At the end of the day I am pleased to not have to spend weeks bikeshedding & detangling the intricacies of trying to combine those two systems. I sympathize with your position, it's actually how I approached this issue initially (before it was filed) but in retrospect, I think what's in core now was a very good idea and really the only way to make forward progress on the very very tight time line we have now.
Eclipse
Comment #69
Jose Reyero CreditAttribution: Jose Reyero commented@EclipseGc,
Really, thanks for the explanation.
I can understand that because we are, for typed configuration, trying to reuse typed data stuff and right, it is a major headache.
Comment #71
fagoThanks guys for driving this home. Sadly you forgot to credit me for writing all the original code though :-/
I did not mean to change defining context definitions in this issue (yet), as this change is not complete (context definitions are not parsed into plugin definitions) and deserve a separate issue - so the committed change of making use a ContextDefinition annotation class is the right thing to do here (as discussed in Austin afaik)
Looking at the patch I noticed two left overs of the context definition statics, created a quick follow-up: #2305569: Follow-up to context definitions: Remove unused, left-over static contextDefinitions() methods
Besides that, I dislike the add ContextDefinition constructor with many arguments. I opened #2305573: Use setters instead of many ContextDefinition constructor arguments for discussing and hopefully resolving that.
Comment #72
EclipseGc CreditAttribution: EclipseGc commentedI apologize for your name not being on this fago. Got tunnel vision on getting the patch in. My sincerest apologies. I'll check your follow ups for the other issues you have here.
Eclipse
Comment #73
fagothanks, no biggie!