Problem/Motivation
This is a followup on #1535868: Convert all blocks into plugins, and as such is postponed until that goes in.
There are a few related issues here, but all stem from the basic paradigm expressed in the ConfigMapper
class, which is a plugin mapper added by the original blocks-as-plugins patch. The behavior at issue in that class is as follows:
class ConfigMapper implements MapperInterface {
public function getInstance(array $options) {
$config = config($options['config']);
if ($config) {
$plugin_id = $config->get('id');
$settings = $config->get();
$settings['config_id'] = $options['config'];
return $this->manager->createInstance($plugin_id, $settings);
}
}
}
This means it expects calling code to provide a config key as part of the definition. It does so with the magic key in the options array called 'config'.
Note - that itself is somewhat opaque, but is also the way the plugins system is currently designed to work: because the MapperInterface
only specifies the single $options parameter, it means all plugins kinda do their own thing with respect to how they inspect that array to figure out which plugin to get.
There are upsides and downsides to this:
- Pros:
- It's REALLY convenient for API clients; all it needs is a config key, then one line of code gets back the appropriate plugin instance.
- Cons:
- For anything that knows it needs to load multiple plugin instances - say, Displays which need to load multiple Blocks - it is impossible to implement any kind of batch-loading strategy that will minimize the number of queries to the config cache (something which is very much planned as a config optimization).
- From a pure architecture point of view, this unnecessarily tightly couples any plugin type using this mapper to the config system.
These issues would be mitigated the config mapper was an optional convenience, rather than a hard requirement, as it is right now. Such a thing could be achieved by making the ConfigMapper
more of an optional thing, for example by turning it into a Decorator - though that'd be harder since there aren't really many other standard mappers out there to decorate.
With respect to blocks in particular, there's the additional issue of block_load()
:
function block_load($plugin_id, array $conf = array()) {
$manager = drupal_container()->get('plugin.manager.block');
try {
$block = $manager->getInstance(array('config' => $plugin_id));
}
catch (Drupal\Component\Plugin\Exception\PluginException $e) {
$block = $manager->createInstance($plugin_id, $conf);
}
This makes the decorator optional as i described above, but done outside of the manager and in a wrapper function. Kinda no bueno. Crell also raised objections to it on the basis that it assumes the case where config is injected is the fallback case, and does so via catching an error, which isn't cheap.
We should refactor block_load()
at the least, and maybe ConfigMapper
as well.
It's possible these things actually deserve a couple different issues, but let's start for now with this one follow-up.
Proposed resolution
Not sure yet. Let's discuss that here :)
Remaining tasks
(reviews needed, tests to be written or run, documentation to be written, etc.)
User interface changes
None.
API changes
Depending on what we decide to do, this could require some simple, but widespread, changes to how blocks are loaded at various points in core.
Comments
Comment #1
EclipseGc CreditAttribution: EclipseGc commentedSo, the mapper is really designed with the intention of returning a single plugin instance, so I'm not sure ConfigMapper is the best place to be messing with this, still that being said the need for what you're asking for hasn't changed any, and chances are we'd be better off just creating a new public method on the Plugin Manager class itself. I've not realized until this point that there is some intention of greater CMI optimization for multi-loading, so once that exists, implementing a custom method on the manager should be relatively trivial (I hope).
Does that seem reasonable?
Eclipse
Comment #2
sdboyer CreditAttribution: sdboyer commentedif we introduce another method onto the relevant plugin interfaces that's intended for multiloading, i'd be good with that as a solution.
the cmi multiloading strategy is going to be a bit of a complex one, but from my discussions with heyrocker, it seems quite feasible.
Comment #3
xjmAlso (from #1535868-196: Convert all blocks into plugins):
Not sure if this issue is the right place to discuss that or if it should be a separate issue.
Comment #4
xjmRelated: #1871696: Convert block instances to configuration entities to resolve architectural issues. (This might end up being a duplicate of that issue.)
Comment #5
xjmComment #6
xjmThis is obsolete now with #1871696: Convert block instances to configuration entities to resolve architectural issues and #1889748: Figure out what to do with ConfigMapper.
Comment #7
xjmComment #7.0
xjmcleanup :P