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

Experiences in migrating a Drupal 7 module to Drupal 8

Experiences in migrating a Drupal 7 module to Drupal 8

https://seville2017.drupaldays.org/sessions/experiences-migrating-drupal-7-module-drupal-8

In this session, I will describe my experiences in updating a Drupal module from Drupal 7 to Drupal 8 (the adsense module).

The session will describe the lessons learned in this process, including the removal of the previous "sub-module as plugins" system, and it's replacement with a true plugin system based on the infrastructure provided by Drupal 8. It will also advocate for a thorough removal of the .module file as much as possible.

Some tools helpful for module development will also be addressed including:

Composer - to manage external dependencies.
Drupal Module Upgrader - for automatic update of code from D7 to D8.
Coder - static checks for coding standards.

Main points to discuss on the subject of module development for Drupal 8:
module.info.yml and the other YAML files
Object Oriented Programming
PHP's PSR-4 and the module file structure
PHP Annotations
The Drupal 8 plugin system
Forms
Blocks
Twig templates
Page controllers and the routing system

João Ventura

March 22, 2017
Tweet

More Decks by João Ventura

Other Decks in Programming

Transcript

  1. E x p e r i e n c e s i n m i g r a t i n g a D r u p a l 7
    m o d u l e t o D r u p a l 8
    João Ventura
    @jcnventura

    View Slide

  2. T H A N K S !

    View Slide

  3. J o ã o V e n t u r a @ j c n v e n t u r a
    Senior Developer at Wunder (Germany).
    Part of Drupal Portugal community (sometimes).
    Drupal user since Drupal 4.6.
    Maintainer of the print and adsense modules.
    1 patch in D7 (moved drupal_eval to php_eval).
    22 patches in D8.

    View Slide

  4. View Slide

  5. D r u p a l 5 → 6
    https://www.drupal.org/update/modules/5/6
    82 API changes!
    CCK (Content types)
    Languages / Translations
    Menu
    Schema API

    View Slide

  6. D r u p a l 6 → 7
    https://www.drupal.org/update/modules/6/7
    264 API changes!
    hook_nodeapi -> hook_node_xxx (same for + hook_block)
    CCK (Fields in core)
    Render API (and render arrays…)
    New database API

    View Slide

  7. Taken from “Pirates of the Caribbean: At World's End” under the fair-use rule.
    (C) 2007 Walt Disney Pictures / Jerry Bruckheimer Films.

    View Slide

  8. D r u p a l 7 → 8
    https://www.drupal.org/update/modules/7/8
    ??? API changes
    Symfony + Twig
    OOP
    Plugins
    Config

    View Slide

  9. P e r s o n a l e x p e r i e n c e

    View Slide

  10. p r i n t + a d s e n s e
    Maintainer of these modules since Drupal 5
    Used at first in personal site (scratch my own itch)
    Allowed me to contribute to Drupal on my own free time
    Porting from Drupal 5 to 6: easy, able to follow core
    Porting from Drupal 6 to 7: hard, had to adapt multiple times to
    changing API.

    View Slide

  11. L e s s o n s l e a r n e d p r e - D 8
    Wait for beta. Don’t chase core.
    Leverage the improved system. Don’t just upgrade it.
    Coder upgrade provided some help.
    But in retrospective, pretty easy to upgrade a module.

    View Slide

  12. L e t ’ s g e t
    Te c h n i c a l
    From “Ada Lovelace: The First Computer Programmer”
    http://iq.intel.com/ada-lovelace-the-first-computer-programmer/

    View Slide

  13. . i n f o → . i n f o . y m l
    adsense.info
    name = AdSense core
    description = (…)
    package = Adsense
    core = 7.x
    configure = admin/config/services/
    adsense
    adsense.info.yml
    name: 'AdSense'
    type: module
    description: (…)
    package: Adsense
    core: 8.x
    configure: adsense.main_settings

    View Slide

  14. C o m p o s e r f i l e
    {
    "name": "drupal/adsense",
    "description": "Displays Google AdSense ads on your site to earn revenue.",
    "type": "drupal-module",
    "homepage": "https://drupal.org/project/adsense",
    "authors": [
    {
    "name": "João Ventura",
    "homepage": "https://www.drupal.org/u/jcnventura"
    }
    ],
    "support": {
    "issues": "https://www.drupal.org/project/issues/adsense"
    },
    "license": "GPL-2.0+"
    }

    View Slide

  15. V a r i a b l e s
    adsense.module
    define('ADSENSE_BASIC_ID_DEFAULT', ‘’)
    adsense.admin.inc
    variable_get('adsense_basic_id',
    ADSENSE_BASIC_ID_DEFAULT)
    adsense.install
    variable_del(‘adsense_basic_id’)

    config/install/adsense.settings.yml
    adsense_basic_id: ‘’
    src/Form/AdsenseIdSettings.php
    $config =
    \Drupal::config('adsense.settings');
    $config->get(‘adsense_basic_id’)

    View Slide

  16. U p g r a d e p a t h
    migration_templates/d7_adsense_settings.yml
    id: d7_adsense_settings
    label: AdSense 7 configuration
    migration_tags:
    - Drupal 7
    source:
    plugin: variable
    variables:
    - adsense_basic_id
    process:
    adsense_basic_id: adsense_basic_id
    destination:
    plugin: config
    config_name: adsense.settings

    View Slide

  17. M e n u r o u t i n g
    adsense.module
    function adsense_menu() {
    $items = array();
    $items['admin/settings/adsense'] = array(
    'title' => 'AdSense',
    'description' => ‘…’,
    'page callback' => 'drupal_get_form',
    'page arguments' =>
    array('adsense_main_settings'),
    'access arguments' => array('administer
    adsense'),
    'file' => 'adsense.admin.inc',
    );

    adsense.routing.yml
    adsense.main_settings:
    path: /admin/config/services/adsense
    defaults:
    _title: AdSense
    _form:
    \Drupal\adsense\Form\AdsenseMainSettin
    gs
    requirements:
    _permission: 'administer adsense'

    View Slide

  18. C o n f i g u r a t i o n f o r m
    adsense.admin.inc
    function adsense_id_settings() {
    $form['adsense_basic_id'] = array(
    '#type' => 'textfield',
    '#title' => t(…),
    '#required' => TRUE,
    '#default_value' => variable_get(),
    '#description' => t(…),
    );
    $form['#validate'][] = '_adsense_id_settings_validate';
    return system_settings_form($form);
    }
    src/Form/AdsenseIdSettings.php
    class AdsenseIdSettings extends ConfigFormBase {
    public function getFormId() {
    return 'adsense_id_settings';
    }
    protected function getEditableConfigNames() {
    return ['adsense.settings'];
    }
    public function buildForm(array $form, FormStateInterface
    $form_state) {
    $form['adsense_basic_id'] = [
    '#type' => 'textfield',
    '#title' => t(…),
    '#required' => TRUE,
    '#default_value' => $config->get(…),
    '#pattern' => 'pub-[0-9]+',
    '#description' => t(…),
    ];
    return parent::buildForm($form, $form_state);
    }

    View Slide

  19. Tw i g t e m p l a t e
    templates/adsense-managed-async.html.twig
    <br/>script><br/><!-- {{ format }} --><br/><ins class="adsbygoogle"<br/>style="display:inline-block;width:{{ width }}px;height:{{ height }}px"<br/>data-ad-client="ca-{{ client }}"<br/>data-ad-slot="{{ slot }}"></ins><br/><script><br/>(adsbygoogle = window.adsbygoogle || []).push({});<br/>

    View Slide

  20. B l o c k s
    adsense_managed.module
    function adsense_managed_block_info()
    function adsense_managed_block_configure($delta = ‘’)
    function adsense_managed_block_save($delta = ‘', $edit =
    array())
    function adsense_managed_block_view($delta = ‘')

    src/Plugin/Block/ManagedAdBlock.php
    /**
    * Provides an AdSense managed ad block.
    *
    * @Block(
    * id = "adsense_managed_ad_block",
    * admin_label = @Translation("Managed ad"),
    * category = @Translation("Adsense")
    * )
    */
    class ManagedAdBlock extends BlockBase implements
    AdBlockInterface {
    public function defaultConfiguration()
    public function buildConfigurationForm(array $form,
    FormStateInterface $form_state)
    public function blockSubmit($form, FormStateInterface
    $form_state)
    public function build()
    }

    View Slide

  21. A n n o t a t i o n s / P l u g i n s
    Drupal 7: plugin system via submodules and hook_adsense_* API
    Drupal 8: real plugin system, based on Annotations
    src/Annotation/AdsenseAd.php
    /**
    * Defines an adsense ad item annotation object.
    * Plugin Namespace: Plugin\adsense\AdsenseAd.
    * @Annotation
    */
    class AdsenseAd extends Plugin {
    public $id;
    public $name;
    public $isSearch;
    public $needsSlot;
    }

    View Slide

  22. A n n o t a t i o n s / P l u g i n s
    src/Plugin/AdsenseAd/ManagedAd.php
    /**
    * Provides an AdSense managed ad unit.
    * @AdsenseAd(
    * id = "managed",
    * name = @Translation("Content ads"),
    * isSearch = FALSE,
    * needsSlot = TRUE
    * )
    */
    class ManagedAd extends ContentAdBase {

    View Slide

  23. P S R - 4
    “describes a specification for autoloading classes from file paths. (…) This
    PSR also describes where to place files that will be autoloaded according to
    the specification”
    Class namespace + name:
    namespace Drupal\adsense\Plugin\Block
    class ManagedAdBlock extends BlockBase implements
    AdBlockInterface {
    Class filename
    src/Plugin/Block/ManagedAdBlock.php

    View Slide

  24. D r u p a l M o d u l e U p g r a d e r
    Handles the boring parts
    Converts module.info to module.info.yml
    Converts your hook_menu() to module.routing.yml
    Converts the configuration forms to src/Form/FormName.php
    etc.
    NOT a magic wand. You still have to port your functionality to work with D8
    https://www.drupal.org/project/drupalmoduleupgrader

    View Slide

  25. C o d e r S n i f f e r
    drupalcs: signals all code standards violations (coder sniffer).
    drupalcbf: automatically fixes everything it can (coder beautifier).
    https://www.drupal.org/project/coder
    Installing Coder Sniffer: https://www.drupal.org/node/1419988

    View Slide

  26. – Murphy
    “ W H A T C O U L D G O W R O N G ? ”
    L I V E D E M O

    View Slide

  27. L e s s o n s l e a r n e d D 8
    Easy path
    Drupal module upgrader.
    Keep code in .module files.
    Make it work.
    Hard path
    Object-oriented-programming (Single responsibility principle, Plugins, etc.).
    No code other than hook_something() in .module file.
    Rewrite from scratch.

    View Slide

  28. • João Ventura
    • d.o: jcnventura
    • Phone: +49.89.85636307
    [email protected]
    • Wunder Germany
    [email protected]
    • www.wunder.io/de
    • Agnes-Pockels-Bogen 1, D1.019; 80992
    München
    A n y q u e s t i o n s ? ?

    View Slide