It has been a while since I didn't post on my blog. I'm trying to get back on it these days.
In this example I will create a Drupal 8/9 service to add a custom Drush command.
The command will sanitize user passwords in the database.
I will start by creating the services file:
services:
mymodule_drush_commands.commands:
class: \Drupal\mymodule_drush_commands\Commands\MyCustomCommands
Here I defined the service and the corresponding class.
Now I will add the code for the class we created (folder “src/Commands”), we extend the DrushCommands class:
<?php
namespace Drupal\mymodule_drush_commands\Commands;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drush\Commands\DrushCommands;
use Drupal\Core\Site\Settings;
class MyCustomCommands extends DrushCommands {
const DOMAIN_PATTERN = '#^(http|https):\/\/(?<name>.*\D)#';
/**
*
*/
const DOMAIN_NAME = [
'dev' => 'develop',
'rel' => 'staging',
'prep' => 'preprod',
];
protected $database;
protected $passwordHasher;
protected $settings;
protected $environment;
/**
* @var EntityTypeManagerInterface
*/
protected $entityTypeManager;
public function __construct($database, $passwordHasher, Settings $settings, EntityTypeManagerInterface $entity_type_manager) {
$this->database = $database;
$this->passwordHasher = $passwordHasher;
$this->settings = $settings;
$this->entityTypeManager = $entity_type_manager;
}
}
We should now inject the services we are using here (database, password, settings, entity type manager) by adding to the services yaml file as class arguments :
services:
tra_drush_commands.commands:
class: \Drupal\mymodule_drush_commands\Commands\TraCustomCommands
arguments: ['@database', '@password', '@settings', '@entity_type.manager']
tags:
- { name: drush.command }
I also added a tag to the service created, here is a more detailed explanation about tags.
Then I will start working on the main task which is to sanitise passwords.
First we will get the environment base url from settings (in the controller of the class we made):
$base_url = $this->settings->get('base_url', FALSE);
if(preg_match(static::DOMAIN_PATTERN, $base_url, $matches)) {
$this->environment = $matches['name'] === 'dev' ? 'dev' : array_search($matches['name'], static::DOMAIN_NAME);
}
We also check if domain is matching one of our list (dev, staging,...) to be sure we are not on a production environment.
Finally we add the code for the sanitize command:
/**
* Drush command to sanitize passwords.
*
* @command mymodule_commands:sanitize
* @aliases mymodule-san
* @usage mymodule_commands:sanitize
*/
public function sanitize() {
$message = 'Environment not suitable for password sanitization.';
if ($this->environment !== false) {
$users = $this->database->select('users_field_data', 'u')->fields('u', ['uid', 'name'])->condition('u.uid', 0, '>')->execute()->fetchAll();
foreach ($users as $user) {
$password = sprintf('%s@%s', strtolower(str_replace(' ', '', $user->name)), static::DOMAIN_NAME[$this->environment]);
$hash = $this->passwordHasher->hash($password);
$query = $this->database->update('users_field_data')
->fields(['pass' => $hash])
->condition('uid', $user->uid, '=')
->execute();
}
$message = 'User passwords sanitized.';
}
$this->output()->writeln($message);
}
This code updates all user passwords with a pattern we defined : "username@enviroment".
Comments