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

Experiences in migrating a Drupal 7 module to D...

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

Avatar for João Ventura

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
  2. 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.
  3. 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
  4. 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
  5. Taken from “Pirates of the Caribbean: At World's End” under

    the fair-use rule. (C) 2007 Walt Disney Pictures / Jerry Bruckheimer Films.
  6. D r u p a l 7 → 8 https://www.drupal.org/update/modules/7/8

    ??? API changes Symfony + Twig OOP Plugins Config
  7. P e r s o n a l e x

    p e r i e n c e
  8. 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.
  9. 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.
  10. 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/
  11. . 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
  12. 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+" }
  13. 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’)
  14. 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
  15. 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'
  16. 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); }
  17. Tw i g t e m p l a t

    e templates/adsense-managed-async.html.twig <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></ script> <!-- {{ format }} --> <ins class="adsbygoogle" style="display:inline-block;width:{{ width }}px;height:{{ height }}px" data-ad-client="ca-{{ client }}" data-ad-slot="{{ slot }}"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script>
  18. 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() }
  19. 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; }
  20. 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 {
  21. 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
  22. 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
  23. 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
  24. – 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
  25. 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.
  26. • 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 ? ?