Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Altering, Extending, and Enhancing, Drupal 8

Altering, Extending, and Enhancing, Drupal 8

Presentation that describes the various ways that Drupal module developers will be able to interact with Drupal 8 core to alter existing functionality, extend Drupal, and enhance it with new functionality.

As well as how the various design patterns work in-case they might be useful to implement in your own projects.

eojthebrave

May 10, 2016
Tweet

More Decks by eojthebrave

Other Decks in Technology

Transcript

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

    View full-size slide

  2. Hi, I’m Joe @eojthebrave

    View full-size slide

  3. 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

    View full-size slide

  4. Don’t hack
    core.

    View full-size slide

  5. Let others change your
    module without hacking

    View full-size slide

  6. Don’t hack,
    use a hook, or

    maybe write a plugin,
    create a service, or
    subscribe to an event.

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  10. 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.

    View full-size slide

  11. 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.');
    }
    }

    View full-size slide

  12. 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

    View full-size slide

  13. 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

    View full-size slide

  14. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. 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’)

    View full-size slide

  19. 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 }

    View full-size slide

  20. 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

    View full-size slide

  21. 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.

    View full-size slide

  22. 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

    View full-size slide

  23. 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 ...
    }
    }

    View full-size slide

  24. 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.

    View full-size slide

  25. ADD SOME EVENTS
    DISPATCH EXAMPLE
    CODE HERE!

    View full-size slide

  26. 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

    View full-size slide

  27. 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

    View full-size slide

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

    View full-size slide

  29. 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

    View full-size slide

  30. 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 …

    }
    }

    View full-size slide

  31. 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);

    View full-size slide

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

    View full-size slide

  33. Hooks or Events?

    View full-size slide

  34. 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

    View full-size slide

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

    View full-size slide