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

EclipseGc’s picture

So, 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

sdboyer’s picture

if 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.

xjm’s picture

Also (from #1535868-196: Convert all blocks into plugins):

I think it would be ideal to make block configurations into ConfigEntity objects as part of this initial patch. But, if that will require more than a couple days to accomplish, we can make it a critical follow up instead.

Not sure if this issue is the right place to discuss that or if it should be a separate issue.

xjm’s picture

Related: #1871696: Convert block instances to configuration entities to resolve architectural issues. (This might end up being a duplicate of that issue.)

xjm’s picture

xjm’s picture

xjm’s picture

Status: Postponed » Closed (duplicate)
xjm’s picture

Issue summary: View changes

cleanup :P