Slide 1

Slide 1 text

Altering, Extending, and Enhancing, Drupal MidWestPHP - 2017 Joe (@eojthebrave) Shindelar http://lb.cm/mEP

Slide 2

Slide 2 text

Hi, I’m Joe @eojthebrave

Slide 3

Slide 3 text

What’s This All About? • How modules enhance Drupal • Plugins, Services, Events, and Hooks • Example use-cases for each • Choosing the right tool for the job

Slide 4

Slide 4 text

Don’t hack core.

Slide 5

Slide 5 text

Let others change your module without hacking

Slide 6

Slide 6 text

? i

Slide 7

Slide 7 text

Don’t hack, use a hook, or
 maybe write a plugin, create a service, or subscribe to an event.

Slide 8

Slide 8 text

Plugins

Slide 9

Slide 9 text

Plugins • Extend Drupal with interchangeable units of functionality • Implement an Interface + meta-data* • A design pattern, not a finished product

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Examples of Plugins • Blocks • Field formatters • Views row style • Actions • etc.

Slide 12

Slide 12 text

Elements of the Plugin System • Plugin types • Discovery • Factory • Plugins

Slide 13

Slide 13 text

Plugin Recipe 1. Determine the type of plugin? • Where does the meta-data and code go? 2. Is there a base class I can extend? 3. Implement the interface, and provide meta-data so that the plugin manager can find your instance.

Slide 14

Slide 14 text

modules/icecream/Plugin/Flavor/Chocolate.php namespace Drupal\icecream\Plugin\Flavor; use Drupal\icecream\FlavorBase; /** * Provides a 'chocolate' flavor. * * @Flavor( * id = "chocolate", * name = @Translation("Chocolate"), * price = 1.75 * ) */ class Chocolate extends FlavorBase { public function slogan() { return t('The other best flavor.'); } }

Slide 15

Slide 15 text

user.links.menu.yml YAML user.page: title: 'My account' weight: -10 route_name: user.page menu_name: account user.logout: weight: 10 menu_name: account class: Drupal\user\Plugin\Menu\LoginLogoutMenuLink

Slide 16

Slide 16 text

Plugin Types Recipe • Plugins that perform similar functionality are of the same plugin type. • You can implement your own new plugin types using DefaultPluginManager • Choose a discovery method • Determine factory to use for initialization • Define an Interface and BaseClass

Slide 17

Slide 17 text

Plugin Resources • https://drupalize.me/blog/201407/drupal-8-plugins- explained • https://drupalize.me/blog/201409/unravelling- drupal-8-plugin-system • https://www.drupal.org/docs/8/api/plugin-api http://lb.cm/mEP

Slide 18

Slide 18 text

Services

Slide 19

Slide 19 text

Services • Global utilities with a known Interface • Services can be swapped • Easier to test • Better reusability

Slide 20

Slide 20 text

Examples of Services • Caching & Database Access • Asset (JS/CSS) optimizer • Plugin Manager / Module Handler / Event Dispatcher • API integration • Validation handlers

Slide 21

Slide 21 text

https://api.drupal.org/api/drupal/services/8

Slide 22

Slide 22 text

Service Recipe 1. Choose a unique name. HINT: Use your module name as a prefix, ‘mymodule.service_name’ 2. Define an Interface, and then implement it 3. Register the service in a mymodule.services.yml file 4. Access it via the container using the unique name \Drupal::service(‘mymodule.service_name’)

Slide 23

Slide 23 text

core/modules/breakpoint/breakpoint.services.yml services:
 breakpoint.manager:
 class: Drupal\breakpoint\BreakpointManager
 arguments: ['@module_handler', '@theme_handler', '@cache.discovery', '@string_translation']
 tags:
 - { name: plugin_manager_cache_clear }

Slide 24

Slide 24 text

Service Resources • https://api.drupal.org/api/drupal/ core%21core.api.php/group/container/8 • https://drupalize.me/videos/introduction- dependency-injection • https://drupalize.me/series/module-development- essentials • https://www.drupal.org/node/2133171 http://lb.cm/mEP

Slide 25

Slide 25 text

Events

Slide 26

Slide 26 text

Events • React to application actions/conditions without modifying the application itself. • Events are a common pattern in OOP, hooks are a bit of a Drupalism.

Slide 27

Slide 27 text

Events Recipe - Subscribe 1. Determine the event name
 https://api.drupal.org/api/drupal/core%21core.api.php/group/events/8 2. Define a service tagged ‘event_subscriber’ services: tommy_event_subscriber: class: Drupal\tommy\EventSubscriber\TommySubscriber tags: - {name: event_subscriber} modules/tommy/tommy.services.yml

Slide 28

Slide 28 text

Events Recipe - Subscribe 3. Implement \Symfony\Component\EventDispatcher\EventSu bscriberInterface in the \Drupal\mymodule\EventSubscriber namespace modules/tommy/src/EventSubscriber/TommySubscriber.php // This should follow the PSR-4 standard, and use the EventSubscriber sub-namespace. namespace Drupal\tommy\EventSubscriber; class TommySubscriber implements EventSubscriberInterface { static function getSubscribedEvents() { $events[KernelEvents::REQUEST][] = array('checkForRedirection'); return $events; } public function checkForRedirection(GetResponseEvent $event) { // Do something awesome ... } }

Slide 29

Slide 29 text

Events Recipe - Dispatch 1. Add a class in the Drupal/my_module/Events namespace. Documents event names. 2. Add a class for event objects that extends \Symfony\Component\EventDispatcher\Event, provides additional information about an event. 3. Use \Drupal\Component\EventDispatcher\Containe rAwareEventDispatcher::dispatch(); and pass it an event name, and object.

Slide 30

Slide 30 text

ADD SOME EVENTS DISPATCH EXAMPLE CODE HERE!

Slide 31

Slide 31 text

Events Resources • https://drupalize.me/blog/201502/responding- events-drupal-8 • http://symfony.com/doc/current/components/ event_dispatcher/introduction.html • https://drupalize.me/series/module-development- essentials • https://api.drupal.org/api/drupal/ core%21core.api.php/group/events/8 http://lb.cm/mEP

Slide 32

Slide 32 text

Hooks

Slide 33

Slide 33 text

Hooks • Workhorse of past Drupal versions • Great for altering existing data • FAST! • At the time Drupal started using them they were the best option available

Slide 34

Slide 34 text

Examples of Hooks • Altering forms, hook_form_alter() • Modify meta-data gathered by other means, e.g. field/entity info • Respond to “events”

Slide 35

Slide 35 text

Hooks Recipe - Implement 1. Determine the name of the hook to implement.
 e.g. hook_form_alter() 2. Add a function to your .module file following the naming convention, replace “hook”, with your module name.
 e.g. example_form_alter() 3. Implement according to documentation 4. Clear cache

Slide 36

Slide 36 text

Hook Implementation /**
 * Implements hook_user_login().
 */
 function system_user_login(UserInterface $account) {
 $config = \Drupal::config('system.date');
 // If the user has a NULL time zone, notify them to set a // time zone.
 if (!$account->getTimezone() && $config->get('timezone.user.configurable')
 && $config->get('timezone.user.warn')) {
 drupal_set_message(t('Configure your …
 } }

Slide 37

Slide 37 text

Hooks Recipe - Invoke 1. Pick a unique name for your hook 2. Use \Drupal\Core\Extension\ModuleHand lerInterface methods // Invoke a standard hook on all enabled modules. $hook = ‘user_login’; \Drupal::moduleHandler()->invokeAll($hook, $args); // Invoke an alter style hook on all enabled modules. \Drupal::moduleHandler()->alter($type, &$data);

Slide 38

Slide 38 text

Hooks Resources • {MODULE_NAME}.api.php • https://api.drupal.org/api/drupal/ core%21core.api.php/group/hooks/8 http://lb.cm/mEP

Slide 39

Slide 39 text

Hooks or Events?

Slide 40

Slide 40 text

Recap • Plugins provide interchangeable bits of functionality with one or many active • Services encapsulate functionality into discrete bundles with a known interface • Events allow objects to communicate • Hooks are good for altering forms and aggregated meta-data

Slide 41

Slide 41 text

Thanks Twitter: @eojthebrave Email: [email protected] Slides: Feedback: http://lb.cm/mEP