Change record status: 
Project: 
Introduced in branch: 
8.0.x
Description: 

Plugin factories can now check that plugins inherit a given interface, if you pass it as a second argument to their constructor:

  /**
   * Constructs a Drupal\Component\Plugin\Factory\DefaultFactory object.
   *
   * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $discovery
   *   The plugin discovery.
   * @param string|null $plugin_interface
   *   (optional) The interface each plugin should implement.
   */
  public function __construct(DiscoveryInterface $discovery, $plugin_interface = NULL) {
    $this->discovery = $discovery;
    $this->interface = $plugin_interface;
  }

DefaultPluginManager takes the same argument in order to pass it to the factory constructor.


  /**
   * Creates the discovery object.
   *
   * @param string|bool $subdir
   *   The plugin's subdirectory, for example Plugin/views/filter.
   * @param \Traversable $namespaces
   *   An object that implements \Traversable which contains the root paths
   *   keyed by the corresponding namespace to look for plugin implementations.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param string|null $plugin_interface
   *   (optional) The interface each plugin should implement.
   * @param string $plugin_definition_annotation_name
   *   (optional) The name of the annotation that contains the plugin definition.
   *   Defaults to 'Drupal\Component\Annotation\Plugin'.
   */
  public function __construct($subdir, \Traversable $namespaces, ModuleHandlerInterface $module_handler, $plugin_interface = NULL, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
    $this->subdir = $subdir;
    $this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $plugin_definition_annotation_name);
    $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
    $this->factory = new ContainerFactory($this, $plugin_interface);
    $this->moduleHandler = $module_handler;
  }

Note that the new argument is inserted in fourth position, invalidating any calls to the DefaultPluginManager constructor using the $plugin_definition_annotation_name argument. Change them accordingly:

Before:

    parent::__construct('Plugin/mymodule/MyPlugin', $namespaces, $module_handler, 'Drupal\mymodule\Annotation\MyPlugin');

After:

    parent::__construct('Plugin/mymodule/MyPlugin', $namespaces, $module_handler, '\Drupal\mymodule\MyPluginInterface', 'Drupal\mymodule\Annotation\MyPlugin');

To disable the interface check, NULL can be passed instead.

Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done