30
HELLO!

Drupal 8 Plugin API

Embed Size (px)

Citation preview

HELLO!

I'M ALEX

ZVIRYATKO

5 YRS AT

DRUPAL 8 PLUGIN API

WHAT IS PLUGIN IN D8?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! BUT HOW TO ADDCUSTOM PLUGIN?

EASIER THAN IN D7

WHERE SHOULD I PUT MYFILES?

All plugins should be placed insrc/Plugin/PLUGIN_NAME directory*

HOW TO DEFINE?

USE ANNOTATIONS/** * @Block( * id = "simple_message", * admin_label = @Translation("Simple Message"), * ) */

WHAT IS THE CODE?

IT DEPENDS ON INTERFACEclass SimpleMessageBlock extends BlockBase /** * @inheritdoc */ public function build() return [ 'message' => [ '#markup' => $this­>t('Just a simple message.'), ], ];

LOOKS SIMPLE

IS IT ALL?

NO!

WHAT IS DERIVATIVES?

DYNAMIC PLUGINSforeach (module_implements('block_info') as $module) $module_blocks = module_invoke($module, 'block_info'); $blocks[$module] = $module_blocks;

DERIVATIVE EXAMPLEcore/modules/system/src/Plugin/Block/SystemMenuBlock.php/** * @Block( * id = "system_menu_block", * admin_label = @Translation("Menu"), * category = @Translation("Menus"), * deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock" * ) */class SystemMenuBlock extends BlockBase // ...

This block is being used for all site menus

BUT HOW IT WORKS?Check the deriver annotation property

deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock"

core/modules/system/src/Plugin/Derivative/SystemMenuBlock.phpclass 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;

WHAT IS PLUGIN MANAGER?Fat replacement of hook_*_info system

Plugin manager is responsible for:

Plugin discovery (annotation, yaml)Plugin creation (factory)

WHY DO YOU NEED IT?Create extendable architecture

example: layouts

you can provide layouts from theme or module and have not be hard linked to main module

HOW TO ADDmymodule/mymodule.services.yml

services: plugin.manager.sandwich: class: Drupal\mymodule\SandwichPluginManager parent: default_plugin_manager

mymodule/src/SandwichPluginManager.phpclass 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, 'Drupal\mymodule\SandwichInterface', // strict interface 'Drupal\Core\Annotation\Plugin' // annotation class ); $this­>alterInfo('sandwich_info'); $this­>setCacheBackend($cache_backend, 'sandwich_info');

HOW TO USEGet a list of available plugins:

$type = \Drupal::service('plugin.manager.sandwich');/** * @var Drupal\mymodule\SandwichInterface[] $plugins */$plugins = $type­>getDefinitions();

In this case you will receive only objects that implementyour interface

PLUGIN DISCOVERYANNOTATION

YAML

STATIC

HOOK

ANNOTATION DISCOVERYYou already saw it

/** * @Block( * id = "system_menu_block", * admin_label = @Translation("Menu"), * ) */

This is much better then ctools $plugin = array();

Using in plugin managernew AnnotatedClassDiscovery( "Plugin/Sandwich", // Subdirectory $namespaces, // Service "container.namespaces" "Drupal\Core\Block\Annotation\Block" // Annotation @Block);

YAML DISCOVERYUsefull for theme plugins, like breakpoints or layouts

core/themes/bartik/bartik.breakpoints.ymlbartik.wide: label: wide mediaQuery: 'all and (min­width: 851px)' multipliers: ­ 1x

Drupal\breakpoint\BreakpointManager::$defaultcontains all possible keys

$directories = $moduleHandler­>getModuleDirectories() + $themeHandler­>getThemeDirectories();new YamlDiscovery('breakpoints', $directories);

STATIC DISCOVERYUseful 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' => '\Some\Vendor\Library\CheeseSandwich', ]); return $this­>discovery;

HOOK DISCOVERYGood 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");

DISCOVERY DECORATORSCombine 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");

IS IT ALL NOW?

THANX!

presentation

drupal.org/u/zviryatkogithub.com/zviryatko

[email protected]/ynFqVo

QUESTIONS?