Spin-off from #1863816: Allow plugins to have services injected:
Problem/Motivation
In order to make the issue above work, plugin managers and / or factories need to reference the global container, making them non-serializable (the container is based on closures).
However, we currently stores a reference to the discovery within instantiated plugin objects, to support PluginBase::getDefinition() (returns the definition entry for the object's own plugin_id).
According to #1851706: Make all core plugin managers be consistent as to whether $this or $this->discovery is passed to the factory, this discovery object is either:
- the manager, it therefore contains a reference to the container
- the raw discovery, containing in most cases a reference to the manager because of ProcessDecorator($this, 'processDefinition'); (where $this is the manager), and thus containing a reference to the container.
Meaning, in both cases, plugin objects end up containing a reference to the container, and are therefore not serializable.
This is a problem, because tracking what gets serialized where and when can be tricky.
- $form['#entity'] = $node;
is going to break if/when $entities become plugin instances.
- In the D8 cycle, support for (some) FAPI/render callbacks as methods : $form['#pre_render'][] = array($this, 'myMethod');
.
This is something plugin implementations are going to be very tempted to do (some of them do this already). But serialize($form) will fatal.
Proposed resolution
Do not embed the discovery in plugin instances, but directly copy the definition array. This array is going to be read-only in at least 99% cases, so thanks to php's copy-on-write behavior, this should make no difference memory-wise.
Comment | File | Size | Author |
---|---|---|---|
#23 | pluginBase_copy_definition-1875182-23.patch | 34.19 KB | yched |
#22 | pluginBase_copy_definition-1875182-22.patch | 35 KB | yched |
#22 | interdiff.txt | 1.54 KB | yched |
#18 | pluginBase_copy_definition-1875182-18.patch | 34.97 KB | yched |
#17 | pluginBase_copy_definition-1875182-17.patch | 34.96 KB | yched |
Comments
Comment #1
yched CreditAttribution: yched commentedAttached is a preliminary patch to get feedback.
@todo : reflect the change in all plugin types (patch only does widgets, formatters, & view plugins)
Ran xhprrof on the following test code:
(that's 3000 plugins on my test setup)
and the results show no difference in memory or CPU use.
Comment #2
yched CreditAttribution: yched commentedI'll add that when a plugin does get serialized, it containing the discovery (including CacheDecorator and its static list of definitions) is actually a bit scary - potentially huge serialized strings...
Comment #3
effulgentsia CreditAttribution: effulgentsia commentedI'm in favor of this.
Comment #4
tim.plunkettNot in scope
However, we can likely remove all of the
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
Comment #5
yched CreditAttribution: yched commentedYeah, arguably not.
This patch introduces a property in PluginBase for the definition array. Calling it $definition lacks some namespacing and steals the term from possible use by actual plugin classes (views plugins actually use $definition already). So, PluginBase::$pluginDefinition.
But then it kind of clashes with the existing PluginBase::$plugin_id, which violates coding standards, so I figured I'd rename it as well, since it's only a couple hunks. I can remove that from the patch if it hurts reviewers eyes :-).
But yeah, more importantly, I'd like agreement on the approach before converting the other plugin types.
Comment #6
tstoecklerThis totally makes sense. Another reason why I am in favor of this is if I do a
debug($plugin)
I totally don't want to see the innards of some discovery object (let alone the whole plugin manager) on my screen. This benefit is surely outweighed by the other factors mentioned above, but I thought I'd bring it up.Regarding the patch: I'm not sure, but I think our coding standards would require
$plugin->pluginID
though, rather than$plugin->pluginId
.Comment #7
yched CreditAttribution: yched commentedReal patch, then.
Comment #8
yched CreditAttribution: yched commentedre @tstoeckler #6: the current PluginBase::$discovery member is protected, so I don't think it would show up in a debug($plugin) anyway ?
Comment #10
yched CreditAttribution: yched commentedMissed a direct plugin instantiation in views' PluginBaseUnitTest.
Comment #11
yched CreditAttribution: yched commentedUpdated after "Blocks as plugins" (just needed to update the new ViewsBlock::__construct())
Comment #12
tim.plunkett#11: pluginBase_copy_definition-1875182-11.patch queued for re-testing.
Comment #14
yched CreditAttribution: yched commentedUn-hibernate. We need this if we want plugin objects to be able to serialize and keep our sanity.
Reroll + update for the plugins that appeared meanwhile.
Comment #16
EclipseGc CreditAttribution: EclipseGc commentedFailures aside, this doesn't look insane to me, and the sooner we settle this particular issue the better as new plugin types are being created. I'd really like if neclimdul could weigh in on this as I think I proposed essentially this when we started and he wanted the discovery injected and I don't recall why. But in general I'm ++ to this approach.
Eclipse
Comment #17
yched CreditAttribution: yched commentedShould fix the fails.
- If $plugin_id doesn't exist, $plugin_definition is NULL and DefaultFactory::getPluginClass($plugin_id, $plugin_definition) fails because its $plugin_definition param is hinted as an array. Fixed that by setting NULL as default value.
I'm just a bit surprised that we have so many cases of createInstance($invalid_plugin_id) in our test suite.
- Missed a use of $this->discovery in TipPluginBase::__construct().
But actually the $this->definition and $this->module properties defined there are useless (duplicate $this->pluginDefinition already provided by Pluginbase), and actually not used anywhere, so removed the entire __construct() override.
While I was at it, opened #1925576: "Tip" plugins managed by TourManager ??
Comment #18
yched CreditAttribution: yched commentedReroll.
Comment #19
tstoecklerStill Looks good.
Comment #20
neclimdulQuick pass, got some deeper thoughts I'm working on:
Looks like the indenting is off on the @param lines?
This change seems unrelated and possibly a regression.
hugh? if we're not passing discovery why are we still bothering with it here?
Comment #21
neclimdulMegh, I don't think its as big a deal. The lack of changes this caused to testing makes me very unhappy with the plugin tests but that's unrelated. I'm not sure we need to remove this from the reflection factory though.
Comment #22
yched CreditAttribution: yched commentedRegarding TipPluginBase :
See 2nd point in #17. $this->module is not used at all in TipPluginBase or existing tip plugin implementations. This __construct() override is useless, and #1932048: Clean up tour ConfigEntity architecture also removes it. Even if i kept it here, either patch would need to be rerolled after the other one gets in, so I see no point in preserving it in this patch.
Attached patch fixes the other points mentioned in #20.
Regarding #21: Yeah, not sure either but :
- Plugins containing a reference to the factory are not something we want to encourage, for the reasons that are the motivations of this patch (serialization hell down the road)
- ReflectionFactory has no ability to pass the manager or the factory (itself) down to plugins, so why would discovery be special ? It only had the ability to pass the discovery because that was the regular way for a plugin to access its own definition. We're changing that, so why would we allow passing the discovery any longer ?
For now I left those lines removed.
Comment #23
yched CreditAttribution: yched commentedReroll.
Actually #1932048: Clean up tour ConfigEntity architecture didn't remove the needless __construct() override in TipPluginBase, so I left it here as well, and will post a followup over there.
Comment #24
yched CreditAttribution: yched commentedGreen, back to RTBC.
Comment #25
EclipseGc CreditAttribution: EclipseGc commented#23: pluginBase_copy_definition-1875182-23.patch queued for re-testing.
Comment #26
EclipseGc CreditAttribution: EclipseGc commentedAfter discussing this further, neclimdul and I are both ++ on the RTBC for this if 23 comes back green again.
Eclipse
Comment #27
EclipseGc CreditAttribution: EclipseGc commentedAlso, effulgentsia indicated support of the approach in general in #3, so I think we have all 3 of the plugin devs on board here.
Eclipse
Comment #28
webchickThis makes a lot more sense to me, and seems to simplify things quite a bit too. Yay!
Committed and pushed to 8.x. Thanks!