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 (minwidth: 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?
Top Related