Creating a Drupal Rector rule
Please note that this documentation was written for version 0.5.x of Drupal Rector, and may be out of date. Until updated documentation is available, please refer to the release notes for the current version on GitHub.
Overview
Creating a Rector rule in Drupal Rector requires three steps:
- Create an example file that shows deprecated code
- Create a Rector class
- Register the Rector class in a configuration file
We have recorded a video demonstrating how to create a simple rule.
Code used in the video example is provided below.
For additional examples and base classes, please refer to the Drupal Rector repository, https://github.com/palantirnet/drupal-rector/tree/master/src/Rector/Deprecation.
Video example
Updates
$this->getName() changes
Replace:
$this->getName($node)
With:
$this->getName($node->name)
This video was recorded using Rector 0.6. The new pattern works in both versions.
Rector class name changes
Rector has changed the class names used for its classes.
Replace:
use Rector\RectorDefinition\CodeSample;
With:
use Rector\Core\RectorDefinition\CodeSample;
Identifying classes to use in Rector
In the video, we used the Rector documentation to find class names. You can also use Php Parse to help.
Thanks to Adam Bergstein for suggesting the Php Parse tool and helping us understand how to use it.
For example:
vendor/bin/php-parse drupal-rector/rector_examples/drupal_url.php
The line in the example file:
\Drupal
This will produce output in Php Parse which includes:
class: Name_FullyQualified(
Which translates to this class in Rector:
Node\Name\FullyQualified
Code used in this example
These examples have been updated to work with Rector 0.7.* and are slightly different than the video.
drupal-rector/rector_examples/format_date.php.
First, we create an example file that shows the deprecated code that we need to update. Place that in a stand-alone PHP file. The example file is used to test the Rector rule we will write.
<?php
/**
* This demonstrates the deprecated static calls that might be called from procedural code like '.module' files.
*/
/**
* A simple example using the minimum number of arguments.
*/
function simple_example() {
$formatted_date = format_date(123456);
}
/**
* An example using all of the arguments.
*/
function using_all_arguments() {
$formatted_date = format_date(time(), 'custom', 'Y M D', 'America/Los_Angeles', 'en-us');
}
drupal-rector/src/Rector/Deprecation/FormatDateRector.php
Next, we create the Rector file that replaces the deprecated code.
<?php
namespace DrupalRector\Rector\Deprecation;
use PhpParser\Node;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
/**
* Replaces deprecated format_date() calls.
*
* See https://www.drupal.org/node/1876852 for change record.
*
* What is covered:
* - Static replacement
*
* Improvement opportunities
* - Dependency injection
*/
final class FormatDateRector extends FunctionToServiceBase
{
/**
* @inheritdoc
*/
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Fixes deprecated format_date() calls', [
new CodeSample("$formatted_date = format_date(123456);", "\Drupal::service('date.formatter')->format(123456);")
]);
}
/**
* @inheritdoc
*/
public function getNodeTypes(): array
{
return [
Node\Expr\FuncCall::class,
];
}
/**
* @inheritdoc
*/
public function refactor(Node $node): ?Node
{
/* @var Node\Expr\FuncCall $node */
if ($this->getName($node->name) === 'format_date') {
$var = new Node\Expr\StaticCall(new Node\Name\FullyQualified('Drupal'), new Node\Identifier('service'), [new Node\Arg(new Node\Scalar\String_('date.formatter'))]);
$name = new Node\Identifier('format');
$args = $node->args;
$node = new Node\Expr\MethodCall($var, $name, $args);
return $node;
}
return null;
}
}
drupal-rector/config/drupal-8/drupal-8.0-deprecations.yml
Finally, we add the working rule to the list of deprecations in the YML file.
# Contains automatic fixes for some deprecations introduced in Drupal 8.0.
services:
DrupalRector\Rector\Deprecation\FormatDateRector: ~
References
For more in-depth coverage of how to write rector rules, see the following documentation:
Drupal Rector repository rules and base classes
https://github.com/palantirnet/drupal-rector/tree/master/src/Rector/Deprecation
Rector node overview documentation
https://github.com/rectorphp/rector/blob/master/docs/NodesOverview.md
Thanks
Thanks to everyone who has provided feedback on Drupal Rector and on the existing project documentation!
We greatly appreciate hearing about what worked, what didn't work, and what bugs you encountered. We are working to incorporate that feedback into the project documentation and supporting resources like this page.
We also want to thank everyone who has and who will contribute resources around using Drupal Rector and the tools that it is built on. These additional perspectives are invaluable as we collectively build our knowledge of the capabilities and best practices for using these tools.