Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Optimize AnnotationToAttributeRector #296

Merged
merged 8 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions docs/core_plugin_conversion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Core annotation to attribute conversion

To convert a plugin in core from an annotation to an attribute, you need to do the following:

## Install drupal-rector
```bash
composer require --dev palantirnet/drupal-rector
```

## Configure drupal-rector (rector.php)

Create the folling file in the root of core. In this example we are converting the `ContentEntityType` and `ConfigEntityType` annotations to attributes. If you want to convert other annotations, you will need to configure the `AnnotationToAttributeRector` with the appropriate `AnnotationToAttributeConfiguration` objects.

```php
<?php
declare(strict_types=1);

use Rector\Config\RectorConfig;

return static function(RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(\DrupalRector\Drupal10\Rector\Deprecation\AnnotationToAttributeRector::class, [

// Setting both introduce and remove version to 10.x means the comments are not kept. Which is good for core. ;)
new \DrupalRector\Drupal10\Rector\ValueObject\AnnotationToAttributeConfiguration('10.0.0', '10.0.0', 'ContentEntityType', 'Drupal\Core\Entity\Attribute\ContentEntityType'),
new \DrupalRector\Drupal10\Rector\ValueObject\AnnotationToAttributeConfiguration('10.0.0', '10.0.0', 'ConfigEntityType', 'Drupal\Core\Entity\Attribute\ConfigEntityType'),
]);

$rectorConfig->autoloadPaths([
'./lib',
'./modules',
'./profiles',
'./themes'
]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These settings and you're in core but the script execution looks like it's from the directory above

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right



$rectorConfig->skip([
'*/upgrade_status/tests/modules/*',
'*/ProxyClass/*',
'*/tests/fixtures/*',
'*/vendor/*',
]);
$rectorConfig->fileExtensions([
'php',
'module',
'theme',
'install',
'profile',
'inc',
'engine'
]);
$rectorConfig->importNames(FALSE, FALSE);
$rectorConfig->importShortClasses(FALSE);
};
```
## Running rector against core

Running will take a while. You can run against specific directories like so:

```bash
vendor/bin/rector process ./core/lib
vendor/bin/rector process ./core/modules
vendor/bin/rector process ./core/themes
```

Or run against speific modules:

```bash
vendor/bin/rector process ./core/modules/system
vendor/bin/rector process ./core/modules/user
```

Or if you have horsepower, run against the whole of core:

```bash
vendor/bin/rector process ./core
```

## Review the changes

Always review the changes. Rector is a tool to help you, not to do the work for you. It will not be able to convert everything, and it may make mistakes. Make sure you understand the changes and that they are correct.

## Reporting errors

If you find an error, please report it to the rector project. You can do this by creating an issue in the rector project on Drupal.org.

We are also available on the #rector channel on Drupal Slack.

@bbrala @mglaman @agentrickard
36 changes: 30 additions & 6 deletions src/Drupal10/Rector/Deprecation/AnnotationToAttributeRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use PhpParser\Node\Attribute;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
Expand Down Expand Up @@ -224,12 +223,15 @@ private function createAttribute(string $attributeClass, array $parsedArgs): Att
if ($value->key == 'deriver') {
$arg = $this->nodeFactory->createClassConstFetch($value->value->value, 'class');
} elseif ($value->value instanceof DoctrineAnnotationTagValueNode) {
$arg = $this->convertTranslateAnnotation($value->value);
} elseif ($value->key === 'forms') {
$arg = $this->convertAnnotation($value->value);
} else {
$attribute = $this->annotationToAttributeMapper->map($value);
$arg = $attribute->value;
} else {
$arg = new String_($value->value->value);
}

// Sometimes the end ) matches. We need to remove it.
if ($value->key === null) {
continue;
}

$args[] = new Arg($arg, \false, \false, [], new Node\Identifier($value->key));
Expand All @@ -238,6 +240,28 @@ private function createAttribute(string $attributeClass, array $parsedArgs): Att
return new Attribute($fullyQualified, $args);
}

public function convertAnnotation(DoctrineAnnotationTagValueNode $value): ?Node\Expr
{
return match ($value->identifierTypeNode->name) {
'@Translation' => $this->convertTranslateAnnotation($value),
'@PluralTranslation' => $this->convertPluralTranslationAnnotation($value),
default => null,
};
}

public function convertPluralTranslationAnnotation(DoctrineAnnotationTagValueNode $value): ?Node\Expr
{
// Check the annotation type, this will be helpful later.
if ($value->identifierTypeNode->name !== '@PluralTranslation') {
return null;
}

return $this->nodeFactory->createArray([
$value->values[0]->key => $value->values[0]->value->value,
$value->values[1]->key => $value->values[1]->value->value,
]);
}

public function convertTranslateAnnotation(DoctrineAnnotationTagValueNode $value): ?Node\Expr\New_
{
// Check the annotation type, this will be helpful later.
Expand Down Expand Up @@ -277,6 +301,6 @@ public function convertTranslateAnnotation(DoctrineAnnotationTagValueNode $value
$argArray[] = $contextArg;
}

return new Node\Expr\New_(new Node\Name('Drupal\Core\StringTranslation\TranslatableMarkup'), $argArray);
return new Node\Expr\New_(new Node\Name('\Drupal\Core\StringTranslation\TranslatableMarkup'), $argArray);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

return static function (RectorConfig $rectorConfig): void {
DeprecationBase::addClass(AnnotationToAttributeRector::class, $rectorConfig, false, [
new AnnotationToAttributeConfiguration('10.2.0', '11.0.0', 'Action', 'Drupal\Core\Action\Attribute\Action'),
new AnnotationToAttributeConfiguration('10.2.0', '11.0.0', 'Block', 'Drupal\Core\Action\Attribute\Block'),
new AnnotationToAttributeConfiguration('10.2.0', '12.0.0', 'Action', 'Drupal\Core\Action\Attribute\Action'),
new AnnotationToAttributeConfiguration('10.2.0', '12.0.0', 'Block', 'Drupal\Core\Action\Attribute\Block'),
new AnnotationToAttributeConfiguration('10.2.0', '12.0.0', 'ContentEntityType', 'Drupal\Core\Entity\Attribute\ContentEntityType'),
]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
/**
* A basic example action that does nothing.
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* type = "system"
* )
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand All @@ -21,7 +21,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
/**
* A basic example action that does nothing.
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
/**
* A basic example action that does nothing.
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing and has an @argument', ['@argument' => 'Argument'], ['context' => 'Validation']), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing and has an @argument', ['@argument' => 'Argument'], ['context' => 'Validation']), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
* type = "system"
* )
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* type = "system"
* )
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand All @@ -27,7 +27,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
* type = "system"
* )
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing'), type: 'system')]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
* deriver = "Drupal\Core\Action\Plugin\Action\Derivative\EntityPublishedActionDeriver"
* )
*/
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing and has an @argument', ['@argument' => 'Argument'], ['context' => 'Validation']), type: 'system', deriver: \Drupal\Core\Action\Plugin\Action\Derivative\EntityPublishedActionDeriver::class)]
#[\Drupal\Core\Action\Attribute\Action(id: 'action_example_basic_action', action_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Action Example: A basic example action that does nothing and has an @argument', ['@argument' => 'Argument'], ['context' => 'Validation']), type: 'system', deriver: \Drupal\Core\Action\Plugin\Action\Derivative\EntityPublishedActionDeriver::class)]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class BasicExample extends ActionBase implements ContainerFactoryPluginInterface
* },
* )
*/
#[\Drupal\Core\Action\Attribute\Block(id: 'page_title_block', admin_label: new Drupal\Core\StringTranslation\TranslatableMarkup('Page title'), forms: ['settings_tray' => false])]
#[\Drupal\Core\Action\Attribute\Block(id: 'page_title_block', admin_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Page title'), forms: ['settings_tray' => false])]
class BasicExample extends ActionBase implements ContainerFactoryPluginInterface {

}
Expand Down
Loading
Loading