HELLO!
I'MALEX
ZVIRYATKO
5YRSAT
DRUPAL8
PLUGINAPI
WHATISPLUGININD8?
Did you remember ctools? Or any hook_info?
block, eld widget, formatter, form element, action, etc...
even cache backend.
src/Plugin/Block/SimpleMessageBlock.php
/**
 * Defines a block with simple message.
 *
 * @Block(
 *   id = "simple_message",
 *   admin_label = @Translation("Simple Message"),
 * )
 */
class SimpleMessageBlock extends BlockBase {
  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      'message' => [
        '#markup' => $this­>t('Just a simple message.'),
      ],
    ];
  }
}
OK!BUTHOWTOADD
CUSTOMPLUGIN?
EASIERTHANIND7
WHERESHOULDIPUTMY
FILES?
All plugins should be placed in
src/Plugin/{PLUGIN_NAME}directory*
HOWTODEFINE?
USEANNOTATIONS
/**
 * @Block(
 *   id = "simple_message",
 *   admin_label = @Translation("Simple Message"),
 * )
 */
WHATISTHECODE?
ITDEPENDSONINTERFACE
class SimpleMessageBlock extends BlockBase {
  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      'message' => [
        '#markup' => $this­>t('Just a simple message.'),
      ],
    ];
  }
}
LOOKSSIMPLE
ISITALL?
NO!
WHATISDERIVATIVES?
DYNAMICPLUGINS
foreach (module_implements('block_info') as $module) {
  $module_blocks = module_invoke($module, 'block_info');
  $blocks[$module] = $module_blocks;
}
DERIVATIVEEXAMPLE
core/modules/system/src/Plugin/Block/SystemMenuBlock.php
/**
 * @Block(
 *   id = "system_menu_block",
 *   admin_label = @Translation("Menu"),
 *   category = @Translation("Menus"),
 *   deriver = "DrupalsystemPluginDerivativeSystemMenuBlock"
 * )
 */
class SystemMenuBlock extends BlockBase {
    // ...
}
This block is being used for all site menus
BUTHOWITWORKS?
Check the deriverannotation property
deriver = "DrupalsystemPluginDerivativeSystemMenuBlock"
core/modules/system/src/Plugin/Derivative/SystemMenuBlock.ph
class SystemMenuBlock extends DeriverBase {
  // ...
  public function getDerivativeDefinitions($base_definition) {
    $blocks = $this­>menuStorage­>loadMultiple();
    foreach ($blocks as $menu => $entity) {
      $this­>derivatives[$menu] = $base_definition;
    }
    return $this­>derivatives;
  }
}
WHATISPLUGINMANAGER?
Fat replacement of hook_*_infosystem
Plugin manager is responsible for:
Plugin discovery (annotation, yaml)
Plugin creation (factory)
WHYDOYOUNEEDIT?
Create extendable architecture
example: layouts
you can provide layouts from theme or module
and have not be hard linked to main module
HOWTOADD
mymodule/mymodule.services.yml
services:
  plugin.manager.sandwich:
    class: DrupalmymoduleSandwichPluginManager
    parent: default_plugin_manager
mymodule/src/SandwichPluginManager.php
class SandwichPluginManager extends DefaultPluginManager {
  public function __construct(
     Traversable $namespaces,
     CacheBackendInterface $cache_backend,
     ModuleHandlerInterface $module_handler
  ) {
    parent::__construct(
      'Plugin/Sandwich', // subdir where to search plugins
      $namespaces,
      $module_handler,
      'DrupalmymoduleSandwichInterface', // strict interface
      'DrupalCoreAnnotationPlugin' // annotation class
    );
    $this­>alterInfo('sandwich_info');
    $this­>setCacheBackend($cache_backend, 'sandwich_info');
  }
}
HOWTOUSE
Get a list of available plugins:
$type = Drupal::service('plugin.manager.sandwich');
/**
 * @var DrupalmymoduleSandwichInterface[] $plugins
 */
$plugins = $type­>getDefinitions();
In this case you will receive only objects that implement
your interface
PLUGINDISCOVERY
ANNOTATION
YAML
STATIC
HOOK
ANNOTATIONDISCOVERY
You already saw it
/**
 * @Block(
 *   id = "system_menu_block",
 *   admin_label = @Translation("Menu"),
 * )
 */
This is much better then ctools $plugin = array();
Using in plugin manager
new AnnotatedClassDiscovery(
  "Plugin/Sandwich", // Subdirectory
  $namespaces, // Service "container.namespaces"
  "DrupalCoreBlockAnnotationBlock" // Annotation @Block
);
YAMLDISCOVERY
Usefull for theme plugins, like breakpoints or layouts
core/themes/bartik/bartik.breakpoints.yml
bartik.wide:
  label: wide
  mediaQuery: 'all and (min­width: 851px)'
  multipliers:
    ­ 1x
DrupalbreakpointBreakpointManager::$default
contains all possible keys
$directories = $moduleHandler­>getModuleDirectories() +
        $themeHandler­>getThemeDirectories();
new YamlDiscovery('breakpoints', $directories);
STATICDISCOVERY
Useful when you need to add 3rd-party class as plugin
class SandwichPluginManager extends DefaultPluginManager {
  protected function getDiscovery() {
    $this­>discovery = new StaticDiscovery();
    $this­>discovery­>setDefinition('cheese_sandwich', [
      'label' => new TranslatableMarkup('Cheese Sandwich'),
      'class' => 'SomeVendorLibraryCheeseSandwich',
    ]);
    return $this­>discovery;
  }
}
HOOKDISCOVERY
Good old hook_info()
class SandwichPluginManager extends DefaultPluginManager {
  protected function getDiscovery() {
    $this­>discovery = new HookDiscovery(
      $this­>moduleHandler,
      "sandwich_info"
    );
    return $this­>discovery;
  }
}
For hook_info_alter()use this
$this­>alterInfo("sandwich_info");
DISCOVERYDECORATORS
Combine them all together with decorators
$d = new AnnotatedClassDiscovery("Plugin/sandwich", $nmspaces);
$d = new ContainerDerivativeDiscoveryDecorator($d);
$d = new YamlDiscoveryDecorator($d, 'sandwich', $directories);
$d = new InfoHookDecorator($d, 'sandwich_info');
$d = new StaticDiscoveryDecorator($d, "callback");
ISITALLNOW?
THANX!
presentation
drupal.org/u/zviryatko
github.com/zviryatko
sanya.davyskiba@gmail.com
goo.gl/ynFqVo
QUESTIONS?

Drupal 8 Plugin API