Upgrade your module to d8
Based on CAPTCHA module experience
Artem Miroshnyk
Web developer
Propeople Ukraine

Agenda
- You HAVE to start upgrading your modules now!
- Module upgrade checklist
- Tools, manuals, community that will help you
-
CAPTCHA
- Problems of 7.x version
- 3 ways to make it works
- How can you help
- Conclusion

Start upgrading your modules now!
Why?

Drupal 8.0.0-beta2 has been released
- Real code freeze
- No critical bugs
- No big documentation changes
- Release candidate is close enough!


It's still beta :)
And you have a chance to modify something in core if it fits your module and will bring benefits to others

D8 stable will be released
Sooner or later ;)
And you have to be ready to start use it
PHP OOP, OOD, Symfony 2, PSR4, Composer, new D8 APIs, Twig, etc
And videos, blogposts and sessions won't help you as much as coding

Upgrade checklist

Just put your module into drupal 8 project with all dependencies
Any IDE or configured Text Editor will show most of broken places:
- Removed functions
- Modified functions
- Deprecated functions
Other wrong places you will notice from runtime errors/notices.
Left parts of your code could be changed into completely new system.
Deprecated
if (!empty($views_field_options['fieldset']['id'])) {
$id = $views_field_options['fieldset']['id'];
$id = $views_field->handler->tokenize_value($id, $view->row_index);
$vars['attributes_array']['id'] = drupal_html_id($id);
}Most IDEs will highlight deprecated function.
Also all deprecated function/classes/methods in D8 has comments when it will be removed and what to use instead.
/**
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.0.
* Use \Drupal\Component\Utility\Html::getUniqueId()
*/
function drupal_html_id($id) {
return Html::getUniqueId($id);
}
Removed
Fatal error: Call to undefined function Drupal\image_captcha\Plugin\Captcha\watchdog() in
/var/www/modules/captcha/image_captcha/src/Plugin/Captcha/ImageCaptcha.php on line 35Stunning error... But thanks Drupal team we have "Change records for Drupal core" that has record for our problem - "hook_watchdog() and watchdog() removed" and some other useful stuff if you will try to search using "watchdog" keyword.
No D8 procedural code looks like that:
<?php
// Logs a notice
\Drupal::logger('my_module')->notice($message);
// Logs an error
\Drupal::logger('my_module')->error($message);
?>CMI
Hook_menu()
YML, HTTP Foundation, HTTPKernel, Routing, Controllers
New stuff

Entity&Field API
// Forget about:
$node->body[LANGUAGE_NONE][0]['value']
$node->title
$tid = $node->field_tags[LANGUAGE_NONE][2]['tid']
$term = taxonomy_term_load($tid);
$term->name
// Meet new D8!
$node->body->value
$node->title->value
$node->field_tags[2]->name
Plugins API
/**
* Class ImageCaptcha
* @package Drupal\image_captcha\Plugin\Captcha
*
* @Captcha(
* id = "image",
* title = @Translation("Image captcha")
* )
*/
class ImageCaptcha extends PluginBase implements CaptchaInterface, ContainerFactoryPluginInterface {D8 requires lots of new knowledge and skill
How could we handle it?

Drupal is famous by its magic
"Do you need X feature? Drupal just has module X for this feature!"
The same magic with similar mages are available in other local communities: Symfony, Composer, Assets, Zend, etc
Let's become friends!
Composer
- PHP dependency manager (Now we have own Bundler, Bower, etc)
- Autoloader manager (composer install and class will be autoloaded)
- Packagist.org database of php classes!

drush dmu-analyze MODULE_NAMEThis will print a report showing any relevant change notices where you can read more.
The script will output a few lines as it attempts various conversions. Go into your modules/MODULE_NAME directory and check out all of your new YAML files and such.
drush dmu-upgrade MODULE_NAME
Continues Integration
Tests



PHP_CodeSniffer
PHP Mess Detector
PHP Copy/Paste Detector

GitHub
TravisCI
CAPTCHA
required module for public site
interface for such submodules like recaptcha, keycaptcha, draggable captcha
But 7.x version has probems
- Dirty code (code sniffer returns thousand of warnings!)
- Image captcha has handmade CAPTCHA generation without performance, unit and functional tests
- CAPTCHA completely disables page cache
- Has too much settings which are hard to understand
- Has weird UI that is done via too much custom code
- HoneyPot and Mollom are much better modules, lets fix it!
What is going outside of drupal?
-
neutron/recaptcha - The most used implementation of reCAPTCHA and compatible with HTTP Foundation
-
gregwar/captcha - The most used stadalone image captcha library also compatible with HTTP Foundation
Step 1
Capcha settings for particular form transform into custom entity
/**
* Defines the CaptchaPoint entity.
*
* @ConfigEntityType(
* id = "captcha_point",
* label = @Translation("Captcha Point"),
* handlers = {
* "list_builder" = "Drupal\captcha\CaptchaPointListBuilder",
* "form" = {
* "add" = "Drupal\captcha\Form\CaptchaPointForm",
* "edit" = "Drupal\captcha\Form\CaptchaPointForm",
* "delete" = "Drupal\captcha\Form\CaptchaPointDeleteForm"
* }
* },
* fieldable = FALSE,
* config_prefix = "captcha_point",
* admin_permission = "administer CAPTCHA settings",
* entity_keys = {
* "id" = "formId",
* "label" = "label",
* },
* links = {
* "edit-form" = "captcha_point.edit",
* "delete-form" = "captcha_point.delete",
* }
* )
*/
class CaptchaPoint extends ConfigEntityBase implements CaptchaPointInterface {Step 2
Implement Captcha plugin type instead of hook_captcha_info()
/**
* MathCaptcha class.
*
* @Captcha(
* id = "math",
* title = @Translation("Math Captcha")
* )
*/
class MathCaptcha extends PluginBase implements CaptchaInterface {
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->firstAddendum = mt_rand(1, 20);
$this->solution = mt_rand(1, $this->firstAddendum);
$this->secondAddendum = $this->solution + $this->firstAddendum;
}
public function getQuestionFormElement(array $form, FormStateInterface $form_state, $captcha_sid) {
return array(
'#markup' => $this->firstAddendum . ' + ' . $this->secondAddendum
);
}
public function getAnswerFormElement(array $form, FormStateInterface $form_state) {
return array(
'#type' => 'textfield',
'#title' => t('Math question'),
'#description' => t('Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.'),
'#field_prefix' => t('@x + @y = ', array('@x' => $this->firstAddendum, '@y' => $this->secondAddendum)),
'#size' => 4,
'#maxlength' => 2,
'#required' => TRUE,
'#attributes' => array(
'autocomplete' => 'off',
),
);
}
public function getChallengeDescription() {
return $this->t('Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.');
}
public function getQuestionDescription() {
return $this->t('Math');
}
public function getSolutionValue($captcha_sid) {
return $this->solution;
}
}
Step 3
rewrite image captcha generation using external captcha library
services:
controller.image_captcha:
class: Drupal\image_captcha\Controller\CaptchaImageGenerator
image_captcha.generator:
class: Drupal\image_captcha\Generator\ImageCaptchaGenerator
arguments:
- @gregwar_captcha.captcha_builder
- @gregwar_captcha.phrase_builder
gregwar_captcha.captcha_builder:
class: Gregwar\Captcha\CaptchaBuilder
gregwar_captcha.phrase_builder:
class: Gregwar\Captcha\PhraseBuilderStep 4
Provide continues ingration based on Travis ci
PHPUnit, WebTests, Code Styles, Drupal Build
- composer global require drush/drush:dev-master
- composer global require youngj/httpserver:dev-master
- composer global require squizlabs/php_codesniffer:$PHPCS_VERSION
- composer global require drupal/coder:$CODER_VERSION
- sudo apt-get update
- sudo apt-get install apache2 libapache2-mod-fastcgi
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
- sudo a2enmod rewrite actions fastcgi alias
- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
- echo "$(curl -fsSL https://gist.githubusercontent.com/nickveenhof/11386315/raw/b8abaf9304fe12b5cc7752d39c29c1edae8ac2e6/gistfile1.txt)" | sed -e "s,PATH,$TRAVIS_BUILD_DIR/../drupal,g" | sudo tee /etc/apache2/sites-available/default > /dev/null
- sudo service apache2 restart
- curl -v "http://localhost"
before_script:
- ln -s ~/.composer/vendor/drupal/coder/coder_sniffer/Drupal ~/.composer/vendor/squizlabs/php_codesniffer/CodeSniffer/Standards
- TESTDIR=$(pwd)
- cd ..
- mysql -e 'create database drupal'
- git clone --depth 1 --branch $DRUPAL_VERSION $DRUPAL_REPO drupal
- cd drupal
- php -d sendmail_path=`which true` ~/.composer/vendor/bin/drush.php --yes site-install --db-url=mysql://root:@127.0.0.1/drupal testing
- composer require gregwar/captcha:1.0.11
- ln -s $TESTDIR modules/$MODULE_NAME
- drush --yes pm-enable simpletest $MODULE_NAME
script:
- phpcs --report=full --standard=Drupal ./modules/$MODULE_NAME
- php ./core/scripts/run-tests.sh --php `which php` --concurrency 12 --url http://localhost/ --verbose --color "$MODULE_TEST_GROUP"
- ./core/vendor/phpunit/phpunit/phpunit -c ./core/phpunit.xml.dist ./modules/$MODULE_NAME
github.com/M1r1k/captcha
Help is approciated
Port your module on D8. E.g. lets port CAPTCHA module.
By Artyom Miroshnik
Port your module on D8. E.g. lets port CAPTCHA module.
- 1,640