- Most Discovery::getDefinition($plugin_id) implementations chose to return array() when no definition for $plugin_id could be found.
That's the case for HookDiscovery, AnnotatedClassDiscovery, CacheDecorator.
StaticDiscovery returns NULL instead.
- Then, implementations that rely on the result of a decorated discovery to act on the results (PluginManagerBase, DerivativeDiscoveryDecorator) do something like :
public function getDefinition($plugin_id) {
$definition = $wrapped_discovery->getDefinition($plugin_id);
if (isset($definition)) {
// Do something.
}
return $definition;
}
If $plugin_id does not exist, and $wrapped_discovery->getDefinition($plugin_id) returns array(), the isset() check is true, and the definition gets massaged.
--> Consequence :
- PluginManagerBase::getDefinition('whatever') always returns a non-empty definition, containing PluginManagerBase::$defaults
Comment | File | Size | Author |
---|---|---|---|
#14 | 1778942-getDef-14.patch | 13.97 KB | andypost |
#14 | 1778942-interdiff-10vs14.txt | 1.52 KB | andypost |
#10 | plugins-fix-getDefinition-1778942-10.patch | 13.8 KB | tstoeckler |
#5 | plugins-fix-getDefinition-1778942-5.patch | 3.04 KB | yched |
#3 | plugins-fix-getDefinition-1778942-3.patch | 1.85 KB | yched |
Comments
Comment #1
yched CreditAttribution: yched commentedI guess the choice of returning array() instead of NULL on a non-existent $plugin_id could be debated, however, sonce that's what most implementations do currently, I kept this.
Attached patch :
- makes StaticDiscovery return array() instead of NULL on non-existent $plugin_id
- fixes PluginManagerBase and DerivativeDiscoveryDecorator to not massage empty definitions.
Comment #2
yched CreditAttribution: yched commentedComment #3
yched CreditAttribution: yched commentedOh wait, right now DiscoveryTest::testDiscoveryInterface() actually explicitly tests :
$this->assertIdentical($this->testPluginManager->getDefinition('non_existing'), NULL)
This worked so far because TestPluginManager uses StaticDiscovery, which is the only one to have the correct behavior.
Then, switching the fix to
- makes getDefinition() return NULL instead of array() on non-existent $plugin_id
impacts HookDiscovery, AnnotatedClassDiscovery, CacheDecorator
Comment #4
tim.plunkettThis is something that should have been caught in tests. Maybe more than one of the DiscoveryInterface implementations should be tested?
Otherwise, this makes perfect sense.
Comment #5
yched CreditAttribution: yched commentedActually, it's not only getDefinition().
There are also inconsistencies around getDefinitions() - when no definitions exist, most discoveries return an empty array, but HookDiscovery returns NULL.
Attached patch fixes that too :
- getDefinition() returns a definition or NULL.
- getDefinitions() returns the array of definitions, empty array if no definitions were found.
- Updated phpdocs in DiscoveryInterface to make the contract clearer.
This being said, and re: #4 - True, should be detected by tests, but I'm not sure what's the best way to test this. Do we need to write a full test suite on each discovery + decorator to get the fixes in ?
Comment #6
tim.plunkettI'd say a unit test for AnnotatedClassDiscovery would be the most important.
Comment #7
aspilicious CreditAttribution: aspilicious commentedYES, I want this. I had a discussion about this with eclipse.
Comment #8
andypostHey, we have tests in DiscoveryTest.php
Probably this just needs to be extended for this cases
Comment #9
tstoecklerThis line is already in HEAD, it must have landed along with something else. Re-rolling for that, and also taking a stab at the tests. Thanks for the pointer @andypost, it seems DiscoveryTest was specifically designed for subclassing by Discovery implementations.
Comment #10
tstoecklerHere we go.
I modified DiscoveryTest (now DiscoveryTestBase) to not sub-class PluginTestBase. That was needless overhead and was implicitly testing all sorts of other plugin stuff like the plugin manager, etc. DiscoveryTestBase now acts as a base class for AnnotatedClassDiscoveryTest and StaticDiscoveryTest. HookDiscoveryTest cannot be tested for now, because these are unit tests. There might be a way to do this in the future, but that problem is completely unrelated to this patch and should not hold it up any longer.
Not providing an interdiff, because that would be identical to the hunks that add(/remove) files in the patch file.
Comment #11
andypost+1 to RTBC, now we have a good coverage base for Discovery
Comment #12
Lars Toomre CreditAttribution: Lars Toomre commentedPatch looks good. I noted one small issue:
This @return type hint needs to be updated as well to to 'array|null', I believe.
Comment #13
Lars Toomre CreditAttribution: Lars Toomre commentedWhoops... Did not mean to change status.
Comment #14
andypostPatch fixes hunk that depends on this issue, see #1785256: Widgets as Plugins
According coding standards fixed #12
Comment #15
tstoecklerTentatively marking RTBC. The removed hunk makes total sense. The only thing I rolled for this patch are the tests, and those were RTBCed by @andypost in #11 and AFAICT by @Lars Toomre in #12. Since the actual code changes are trivial, I dare to be bold.
Comment #16
webchickI confess I am not fully following everything going on here, but it seems to do what the issue title says on the tin, and test coverage is extensive.
Committed and pushed to 8.x. Thanks!
Comment #17
tstoecklerShameless plug: #1809200: Consolidate discovery code in a DiscoveryBase and DiscoveryDecoratorBase
Comment #18
tim.plunkettHmm, the OP could have been solved by doing !empty, right?
This means that I can no longer += into an array with getDefinitions, because I can't trust that it is an array.
Comment #19
tstoecklergetDefinitions() is always an array, albeit perhaps an empty one.
getDefinition() is not always an array, it returns NULL if the plugin in question was not found.
Do you want to += on top of getDefinition()?
Comment #20
yched CreditAttribution: yched commentedgetDefinitions() will always return an array.
getDefinition() returns NULL when no definition is found for the requested $plugin_id. This seems semantically more correct, there is no corresponding definition, not "the definition is an empty array" - that's what we do throughout core for somilar cases, I'd say.
You'd want to += the result of getDefinition whether the definition exists or not ? Seems odd, what's the use case ?
Besides, if definitions were classed objects (which they totally could have been) instead of D7-style arrays, null would definitely be the correct value.
Comment #21
tim.plunkettSorry, my code was wrong, I did want getDefinitions() after all.
Glad I didn't reopen the issue :)
Thanks @tstoeckler and @yched.
Comment #22.0
(not verified) CreditAttribution: commentedTypo