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
#2272801: Allow blocks to be context aware. allows classes extending BlockBase to also be context-aware.
However, this shouldn't be needed, since many different plugins should be able to opt into context without breaking their parent class relationship
Proposed resolution
Figure out a way to make a ContextAwarePluginTrait.
Remaining tasks
The main problem here is the differences between \Drupal\Component\Plugin\ContextAwarePluginBase and \Drupal\Core\Plugin\ContextAwarePluginBase
User interface changes
N/A
API changes
API additions only.
Comment | File | Size | Author |
---|---|---|---|
#88 | 2273381-88.patch | 37 KB | andypost |
#88 | interdiff.txt | 4.39 KB | andypost |
#82 | 2273381-82.patch | 37.07 KB | clayfreeman |
#82 | 2273381-82.interdiff.txt | 6.77 KB | clayfreeman |
Comments
Comment #1
andypostThe difference is really confusing, +1
Comment #2
tim.plunkettThanks to https://bugs.php.net/bug.php?id=65576, this had a problem due to the constructor. My workaround is less than ideal.
Comment #3
tim.plunkettBecause traits cannot safely have __construct(), every class using the trait must call this method in their __construct(). Ugly.
Open to better ideas.
Comment #4
dawehnerJust an idea.
Comment #5
tim.plunkettThe interdiff was wrong, the patch was good.
I think this is okay, @EclipseGC can you take a look?
Comment #8
XanoDo we still want this? I noticed we now have a
\Drupal\Component\Plugin\ContextAwarePluginBase
too.Comment #9
mgiffordUnassigning stale issue. Hopefully someone else will pursue this.
Comment #10
EclipseGc CreditAttribution: EclipseGc at Acquia commentedWe've always had a Component version of this class. I wrote that first.
I don't know how I missed this. I support this in principle, but the code that's there isn't going to work, we'll need to abstract the component version first and then figure out how we want to handle the TypedData specifics that the core implementation provides.
Eclipse
Comment #17
tim.plunkettThis is still needed.
Comment #18
tim.plunkettRecreated this, no real change in approach.
Comment #20
tim.plunketttraits, buh
Comment #22
tim.plunkettFixed the abstract classes I changed.
Comment #24
tim.plunkettMissed moving the context-aware caching stuff. And my fix in #20 was backwards.
Comment #26
tim.plunkettConfirmed with @alexpott that a class in Drupal\Component may be deprecated in favor of something in Drupal\Core, but that requires a tweak of DrupalComponentTest.
Comment #28
tim.plunkettOkay PHPUnit.
Comment #32
tim.plunkettThanks to @Berdir, found a fix for the last fail.
Comment #33
tim.plunkettThis is ready for a real review, but calling out the docs work that is needed:
These need a real CR
Needs real docs
Comment #34
clayfreeman\Drupal\Core\Condition\ConditionManager::createInstance()
for passing context values to plugins via configuration.Comment #36
tim.plunkettThanks for the help @clayfreeman!
Fixed those links to point to the new CR, and fixed the test fail (which was introduced by #3118477: RegistryTest, RegistryLegacyTest both define the same class, use mock instead)
Also I restored the @return overrides, they are needed to specify Drupal\Core vs Drupal\Component.
I moved the getContextDefinition[s]() methods to the same spot they were before, cleaner diff.
I think this is ready for final review!
Comment #37
clayfreemanLooks good, I just removed an unused use statement in one of the test cases to fix the code style warning that was reported.
Sorry for stepping on your toes on the @return overrides; didn't notice the distinction there!
Comment #38
clayfreemanWhat's the plan for
\Drupal\Component\Plugin\ContextAwarePluginInterface
once we hit Drupal 10? I noticed that the only two places it's used are in\Drupal\Component\Plugin\ContextAwarePluginBase
(which is now deprecated for removal in 10.x) and\Drupal\Core\Plugin\ContextAwarePluginInterface
.The reason I ask is that if we intend to remove the component interface in favor of the core interface, we should probably note that in the inline documentation, no? I believe a deprecation notice via
trigger_error()
would be a bit heavy handed here, especially since it's still the ancestor of the core interface.I'm not sure if this warrants a reversion of RTBC; I'll leave that to your better judgement @tim.plunkett.
Comment #39
clayfreemanBackporting patch to 8.9.x branch for additional testing.
Comment #41
clayfreemanFixing failing tests.
Comment #42
clayfreemanComment #43
xjm9.1.x issue now, which means we need to update the deprecation message at least.
Comment #44
clayfreemanUpdating backport patch for testing on 8.9.x.
Comment #45
clayfreemanUpdating main patch. Change record has also been updated to reflect the new target.
Comment #46
clayfreemanPlease advise whether RTBC should be reverted on the reported test error:
Comment #47
tim.plunkettYes, tests must pass before it can be committed.
Also you cannot RTBC your own patch. We'll need a third person to review it.
Comment #48
clayfreemanA discussion via Slack on #46 has yielded that the test failure is from
9.1.x/HEAD
thus the most recent patch can be considered ready for review.Comment #49
clayfreemanNow that the tests have passed for the most recent patch, I wanted to highlight a question that may have been missed earlier in the thread for the reviewer to consider:
Comment #50
jungleComment #51
clayfreemanHopefully this fixes the patch. Seems as though there was a conflict introduced in a test case.
Comment #52
clayfreemanComment #53
jungleShould be
protected function setUp(): void
here. #3107732: Add return typehints to setUp/tearDown methods in concrete test classes just got committedNot sure, whether
sprintf()
is still encouraged to use. See #3118957: Evaluate replacing all usage of sprintf by dot concatenation or variable inside stringAnd I would like to kill
else
s, for instance:can be
As inside
if
, if the condition meets, the function returns.else
killed.Comment #54
clayfreemanContextAwarePluginBase::__construct()
).sprintf()
in\Drupal\Component\Plugin\Context\Context
. Let me know if this file should be updated too.ContextAwarePluginDefinitionInterface
is encountered without a matching context definition. I recommend that we leave the second case alone. Correct me if I'm wrong on this.Comment #55
jungle@clayfreeman thanks!
2. My bad. did not realize it's the CR associated with this issue
3. I'm ok with that. as it's still undecided yet.
4. Yes, kill
else
, notelseif
. :)Comment #57
jungle{@inheritdoc}
s should be replaced with real docs. A trait can not inherit docs.The question in #49 might be missed and should be answered, maybe, @tim.plunkett is the right person to answer it :)
Meanwhile,
\Drupal\Component\Plugin\ContextAwarePluginInterface
vs\Drupal\Core\Plugin\ContextAwarePluginInterface
, it's CONFUSING too. Just like\Drupal\Component\Plugin\ContextAwarePluginBase
vs\Drupal\Core\Plugin\ContextAwarePluginBase
Furthermore, a similar question, what about
ContextInterface
andContext
?\Drupal\Component\Plugin\Context\ContextInterface
vs\Drupal\Core\Plugin\Context\ContextInterface
\Drupal\Component\Plugin\Context\Context
vs\Drupal\Core\Plugin\Context\Context
NW for #1. Separate issue(s) for #2 and #3?
Comment #58
clayfreeman{@inheritdoc}
being used in traits that are paired with interfaces that the referencing class is expected to implement (e.g.Drupal\Core\Cache\CacheableDependencyTrait
andDrupal\Core\Cache\CacheableDependencyInterface
). If this is something that needs to be done, I'm more than happy to do it, but we should also create a "clean-up" ticket for other occurrences as well.Comment #59
EclipseGc CreditAttribution: EclipseGc at Acquia commentedSeems completely unrelated and also not as nice or as safe as what is there today. Reading the linked issue above, I don't really buy the logic for removing sprintf() in general. Let's remove this from the patch.
More generally, there are a few things here that pain me.
This feels like it needs some more work yet, and ideally more discussion. I +1'd the idea many years ago and am still +1 to the trait option, but I think I'd like to see a slightly different implementation here.
Also, while I'm not certain what other traits are doing with regard to inheritdoc, I'm ok with it so long as we have an @see to the intended interface implementation. Again I know we have standards around this, so we should figure out what that standard is and follow it. I'm just espousing an opinion here.
Eclipse
Comment #60
clayfreemanUploading this for preliminary discussion and test bot; not expected to be worthy of being the final patch.
I agree that any clean up should be in a follow up ticket if we want to squash the base class, but I don't believe we'll even want to.
I opted not to include the
::prepareContext()
method in the trait since it seemed extraneous to me; all that you have to do in your constructor if you're not extendingContextAwarePluginBase
is the following:Obviously, this also has the added benefit of allowing one to customize the approach that they take for sourcing the context configuration; cleaner & better in my opinion.
I also added an
@see
to the trait that references the interface that should be implemented.Let's see if tests pass for this...
Comment #61
jungleAbout
{@inheritdoc}
s in ContextAwarePluginTrait, I have not fond the standard about it yet.. As there is an @see above the Trait definition and PHPStorm on my local can understand it. I am totally ok to keep them.And about the sprint() thing, yes, it’s unrelated, and I already commented "3. I'm ok with that. as it's still undecided yet." in #55.
Comment #62
clayfreemanAs per discussion with @EclipseGc and @tim.plunkett via Slack call, we decided to middleground the issue:
::setContextValue()
should be used instead to avoid the initialization that we can't do in traits due to prohibition on constructors in them. Implicit initialization is performed via::prepareContext()
until the deprecated functionality is removed.sprintf()
since that has yet to be decided and is presently out of scope of this issue.This means that
ContextAwarePluginBase
will be deprecated for contrib and replaced withPluginBase implements ContextAwarePluginInterface
anduse ContextAwarePluginTrait;
for all core code.Interdiff posted for this is from #54.
Comment #63
tim.plunkett+1 from me, the interdiff looks great and the comment in #62 captures our agreement.
Comment #64
EclipseGc CreditAttribution: EclipseGc at Acquia commentedSo, we have a variable in the exception, we need it in sprintf(). $name isn't typehinted, so no guarantees what that is. I know this is how it was previously, but let's fix it. It should never have gone in this way.
Otherwise this looks great.
Eclipse
Comment #65
clayfreemanAttached patch better demonstrates (with
diff.renames
) that #64 wasn't introduced by the patch in #62. The interdiff is a bit odd due to the config change, so I've omitted it;git apply 65.patch && git apply -R 61.patch
should result in a clean working tree.Comment #66
EclipseGc CreditAttribution: EclipseGc at Acquia commentedOk, then I retract my statement about the exception. This looks good to me. RTBC pending passing tests.
Eclipse
Comment #67
clayfreemanExpect a test failure; citation from 9.1.x that seems to indicate an intermittent failure: https://www.drupal.org/pift-ci-job/1730324
The fact that #62 passed and there are no changes from that patch seems to line up with my suspicion.
Comment #69
xjmYeah
WidgetUploadTest
is a very frequent random fail in HEAD.Meanwhile, patch review:
Drupal\Core\Plugin\ContextAwarePluginBase
is being deprecated, but not the whole ofDrupal\Component\Plugin\ContextAwarePluginBase
. Only the "passing values via configuration" part is deprecated.Drupal\Core
one extends theDrupal\Component
one.BlockBase
that extend theDrupal\Core
one are being changed to extend straight-upPluginBase
and implementing the inteface, rather than extending the component one, despite the component one not being deprecated.What's the scoop on all that?
This doesn't look to be a method on the trait; how can we be sure it exists wherever the trait is used?
Remind me again why we have one copy of all this stuff in
Drupal\Core
and another inDrupal\Component
? (I knew the answer to this at some point, but have since forgotten.) The docblock of theDrupal\Core
one just says:An override of ContextAwarePluginInterface for documentation purposes.
Uh, wha?
I guess this is because we can't rely on its existence because there's no constructor to set it.
No
@todo
without followups, please. Also, there should not be a colon after@todo
, and our standard is to add two spaces to indent subsequent lines of the to-do (after the//
for inline comments).I'm confused by this deprecation. I couldn't find a
prepareContext()
method on either the core or component base classes. But if it's not coming from the parent, then why the combination of private and deprecated? Especially with a deprecation message that says what the caller should do, when it's... private. What's the story with this?Comment #70
xjmAh, here's the answer to one of my questions at least:
Can we get an
@todo
and a followup for that in the code? Because it's WTFy as-is.Comment #71
clayfreemanThanks @xjm for the review; I'm happy with the progress that we've made on this today. Here are my answers to your questions as best as I understand them:
@todo
for this. Ideally when everything is said and done, only core will exist and only as an interface / trait (once base class is removed after deprecation).ContextAwarePluginInterface
, we can assume that it's available, but I'm not sure if that's best practice.@todo
may have come from component code; not sure that we're responsible for that being there in this ticket.::prepareContext()
is the temporary way that we're handling laxy initialization of context from configuration in the new trait. It will be removed in 10.x when support for context via configuration is removed. This is why it's defined asprivate
and marked as deprecated.Comment #72
EclipseGc CreditAttribution: EclipseGc at Acquia commented@xjm
re: 2
ContextAwarePluginInterface (which this trait implements) extends the Component interface of the same name which extends \Drupal\Component\Plugin\PluginInspectionInterface which is where this method is found. So, in so far as a trait COULD be used anywhere, this one is explicitly meant to satisfy the Core/ContextAwarePluginInterface and so long as it is used as intended, the PluginInspectionInterface::getPluginDefinition() method should 100% always be available.
re: 6
This was how Tim encapsulated the code that was originally in the constructor for config context injection purposes. Since it's private but in a trait, any class that uses the trait will have access to the private method. So putting a deprecation notice in it from day one (since we're not going to support constructor context injection) seems sensible. Here's a quick code explanation. This is valid:
So the patch is just trying to prevent anyone from relying on that method.
Eclipse
Comment #73
clayfreemanUpdating the patch to include an issue for the dangling
@todo
in::validateContexts()
. Also adding a@todo
for deprecating\Drupal\Component\Plugin\ContextAwarePluginBase
and\Drupal\Component\Plugin\ContextAwarePluginInterface
.Comment #74
EclipseGc CreditAttribution: EclipseGc at Acquia commentedI think we're back to RTBC since only the todo portion of xjm's review seemed actually actionable. I'll add a little more commentary here to respond to that review.
re: 4
Yes :-)
re: 3
The Drupal\Component namespace was intended, from day one, to be a place we could subtree split and make our components more widely available to the PHP community. A trojan horse for both spreading Drupal code outside of Drupal as well as pulling non-Drupal PHPists into the Drupal community bit by bit. While this goal still has not manifest in any actionable way, I 100% support it still and I also support Plugins as a more widely available component. That being said (and admittedly, tangential to this issue) there are issues with the Plugin system in Component.
I think I'm delving into "remove component" follow up territory at this point, but I hope that helps give context to why the core/component split exists.
Eclipse
Comment #75
tim.plunkett#69
2) The trait can add
abstracted protected function getPluginDefinition()
to protect against this.6) Discussed with @xjm, instead of adding a new private method and immediately deprecating this, let's simplify and inline this code directly within getContext().
#73
Thanks for the new issues! One documentation nit: can't have @see inside @todo. In this case, just change "@see" to "See" and have it be a full sentence
Comment #76
clayfreemanAll review criteria should be addressed by this patch. #3153956: Remove code related to "context from configuration" that was deprecated in Drupal 9 was created to remove deprecations from this issue when Drupal 10.0.x hits.
Re: @see inside @todo
We should probably have someone update the screenshot in this section of standards to reflect this suggestion.
Comment #77
EclipseGc CreditAttribution: EclipseGc at Acquia commentedLooks good to me.
Comment #78
tim.plunkettI noticed a couple lines missing a trailing . and went to fix them.
Then I thought about the added @todo's to deprecate the component stuff.
As much I very much want those to go away, that feels aspirational and if it never happens the comments will be stuck there pointing to an issue that went nowhere.
I think opening the issue is enough.
This only applies to the Component stuff, all of the other new @todos are fine.
Leaving RTBC, see interdiff.
Comment #79
EclipseGc CreditAttribution: EclipseGc at Acquia commentedI can definitely ++ this logic.
Comment #80
tim.plunkettRerolled after #3091309: Broken context-aware block plugins throw an unexpected exception. No changes.
Comment #81
alexpottIs it possible that this is called multiple times on a request - and end up doing the reflection multiple times?
Should we initialise $this->context to NULL and only do this if it is NULL and then set it to an empty array in here?
Is there test coverage of both code paths? I think TestContextAwarePlugin tests the reflection path but I'm not sure about the other.
Are we okay with these not implementing the ContextAwarePluginInterface interface - other test classes that now use the trait do this.
Comment #82
clayfreeman$initializedContextConfig
, used to track the state of initialization; if we initialize$context
toNULL
, we could run into potential type safety issues, or BC concerns where implementing classes depend on theNULL
value instead of an empty array. Plus, it was much easier to account for an additional boolean flag instead of changing a bunch of code in other places.Comment #83
tim.plunkettI missed the last two comments on this, sorry. I think the concerns of #81 are valid, and I think #82 addressed them adequately. Thanks both of you!
Comment #85
jungleLooks like a random failure. Re-queued.
Comment #87
andypostNR for https://www.drupal.org/node/3176667
Comment #88
andyposthere's
Comment #89
tim.plunkettThanks @andypost, re-RTBC-ing
Comment #90
alexpottCommitted bc0cbe8 and pushed to 9.1.x. Thanks!
Comment #93
mglamanWhy wasn't the class flagged as deprecated? All we have is a runtime deprecation. This cannot be caught by PHPStan.