From dc2e858a5f5cea2ef3e2b770350169f0d0af926b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Brala?= Date: Sat, 9 Mar 2024 20:12:48 +0100 Subject: [PATCH] feat: Optimize AnnotationToAttributeRector and add core plugin conversion documentation (#296) * feat: add PluralTranslation and test for ConfigEntityType * fix: codestyle * fix:L ContentEntityType * fix: overmatching ) * fix: tests and style * fix: new Drupal\Core\StringTranslation\TranslatableMarkup should be new \Drupal\Core\StringTranslation\TranslatableMarkup * feat: add documentation for core plugin conversion * fix: correct paths for rector.php --- docs/core_plugin_conversion.md | 88 +++++++++ .../AnnotationToAttributeRector.php | 36 +++- .../config/configured_rule.php | 5 +- .../action_bc_basic_fixture.php.inc | 2 +- ...tion_bc_existing_attribute_fixture.php.inc | 4 +- ..._bc_multiple_translation_arguments.php.inc | 2 +- .../fixture/action_basic_fixture.php.inc | 2 +- .../action_existing_attribute_fixture.php.inc | 4 +- ...ion_multiple_translation_arguments.php.inc | 2 +- .../fixture/block_basic_fixture.php.inc | 2 +- .../content_entity_type_fixture.php.inc | 175 +++++++++++++++++ ...ententitytype_blockcontent_fixture.php.inc | 180 ++++++++++++++++++ 12 files changed, 485 insertions(+), 17 deletions(-) create mode 100644 docs/core_plugin_conversion.md create mode 100644 tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/content_entity_type_fixture.php.inc create mode 100644 tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/contententitytype_blockcontent_fixture.php.inc diff --git a/docs/core_plugin_conversion.md b/docs/core_plugin_conversion.md new file mode 100644 index 00000000..60b9d8d9 --- /dev/null +++ b/docs/core_plugin_conversion.md @@ -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 +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([ + './core/lib', + './core/modules', + './core/profiles', + './core/themes' + ]); + + + $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 diff --git a/src/Drupal10/Rector/Deprecation/AnnotationToAttributeRector.php b/src/Drupal10/Rector/Deprecation/AnnotationToAttributeRector.php index e34d84a9..5f0c0e94 100644 --- a/src/Drupal10/Rector/Deprecation/AnnotationToAttributeRector.php +++ b/src/Drupal10/Rector/Deprecation/AnnotationToAttributeRector.php @@ -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; @@ -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)); @@ -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. @@ -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); } } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/config/configured_rule.php b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/config/configured_rule.php index b7d8687c..712150a7 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/config/configured_rule.php +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/config/configured_rule.php @@ -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'), ]); }; diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_basic_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_basic_fixture.php.inc index 4b4d78d9..02dda630 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_basic_fixture.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_basic_fixture.php.inc @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_existing_attribute_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_existing_attribute_fixture.php.inc index 8b197dfe..147f5e32 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_existing_attribute_fixture.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_existing_attribute_fixture.php.inc @@ -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 { } @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_multiple_translation_arguments.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_multiple_translation_arguments.php.inc index 8b1ef848..85aa674d 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_multiple_translation_arguments.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture-next-major/action_bc_multiple_translation_arguments.php.inc @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_basic_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_basic_fixture.php.inc index b2d29312..c2d1efc6 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_basic_fixture.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_basic_fixture.php.inc @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_existing_attribute_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_existing_attribute_fixture.php.inc index b61b3c69..a9c13f4e 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_existing_attribute_fixture.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_existing_attribute_fixture.php.inc @@ -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 { } @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_multiple_translation_arguments.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_multiple_translation_arguments.php.inc index fc1736ee..f3d8f52c 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_multiple_translation_arguments.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/action_multiple_translation_arguments.php.inc @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/block_basic_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/block_basic_fixture.php.inc index 14ee6b23..28814b8c 100644 --- a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/block_basic_fixture.php.inc +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/block_basic_fixture.php.inc @@ -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 { } diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/content_entity_type_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/content_entity_type_fixture.php.inc new file mode 100644 index 00000000..3a73132b --- /dev/null +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/content_entity_type_fixture.php.inc @@ -0,0 +1,175 @@ + '@count content item', 'plural' => '@count content items'], bundle_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Content type'), handlers: ['storage' => 'Drupal\node\NodeStorage', 'storage_schema' => 'Drupal\node\NodeStorageSchema', 'view_builder' => 'Drupal\node\NodeViewBuilder', 'access' => 'Drupal\node\NodeAccessControlHandler', 'views_data' => 'Drupal\node\NodeViewsData', 'form' => ['default' => 'Drupal\node\NodeForm', 'delete' => 'Drupal\node\Form\NodeDeleteForm', 'edit' => 'Drupal\node\NodeForm', 'delete-multiple-confirm' => 'Drupal\node\Form\DeleteMultiple'], 'route_provider' => ['html' => 'Drupal\node\Entity\NodeRouteProvider'], 'list_builder' => 'Drupal\node\NodeListBuilder', 'translation' => 'Drupal\node\NodeTranslationHandler'], base_table: 'node', data_table: 'node_field_data', revision_table: 'node_revision', revision_data_table: 'node_field_revision', show_revision_ui: true, translatable: true, list_cache_contexts: ['user.node_grants:view'], entity_keys: ['id' => 'nid', 'revision' => 'vid', 'bundle' => 'type', 'label' => 'title', 'langcode' => 'langcode', 'uuid' => 'uuid', 'status' => 'status', 'published' => 'status', 'uid' => 'uid', 'owner' => 'uid'], revision_metadata_keys: ['revision_user' => 'revision_uid', 'revision_created' => 'revision_timestamp', 'revision_log_message' => 'revision_log'], bundle_entity_type: 'node_type', field_ui_base_route: 'entity.node_type.edit_form', common_reference_target: true, permission_granularity: 'bundle', links: ['canonical' => '/node/{node}', 'delete-form' => '/node/{node}/delete', 'delete-multiple-form' => '/admin/content/node/delete', 'edit-form' => '/node/{node}/edit', 'version-history' => '/node/{node}/revisions', 'revision' => '/node/{node}/revisions/{node_revision}/view', 'create' => '/node'])] +class Node extends EditorialContentEntityBase implements NodeInterface { + +} diff --git a/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/contententitytype_blockcontent_fixture.php.inc b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/contententitytype_blockcontent_fixture.php.inc new file mode 100644 index 00000000..3440a703 --- /dev/null +++ b/tests/src/Drupal10/Rector/Deprecation/ActionAnnotationToAttributeRector/fixture/contententitytype_blockcontent_fixture.php.inc @@ -0,0 +1,180 @@ + '@count content block', 'plural' => '@count content blocks'], bundle_label: new \Drupal\Core\StringTranslation\TranslatableMarkup('Block type'), handlers: ['storage' => 'Drupal\Core\Entity\Sql\SqlContentEntityStorage', 'access' => 'Drupal\block_content\BlockContentAccessControlHandler', 'list_builder' => 'Drupal\block_content\BlockContentListBuilder', 'view_builder' => 'Drupal\block_content\BlockContentViewBuilder', 'views_data' => 'Drupal\block_content\BlockContentViewsData', 'form' => ['add' => 'Drupal\block_content\BlockContentForm', 'edit' => 'Drupal\block_content\BlockContentForm', 'delete' => 'Drupal\block_content\Form\BlockContentDeleteForm', 'default' => 'Drupal\block_content\BlockContentForm', 'revision-delete' => \Drupal\Core\Entity\Form\RevisionDeleteForm::class, 'revision-revert' => \Drupal\Core\Entity\Form\RevisionRevertForm::class], 'route_provider' => ['revision' => \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class], 'translation' => 'Drupal\block_content\BlockContentTranslationHandler'], admin_permission: 'administer block content', base_table: 'block_content', revision_table: 'block_content_revision', data_table: 'block_content_field_data', revision_data_table: 'block_content_field_revision', show_revision_ui: true, links: ['canonical' => '/admin/content/block/{block_content}', 'delete-form' => '/admin/content/block/{block_content}/delete', 'edit-form' => '/admin/content/block/{block_content}', 'collection' => '/admin/content/block', 'create' => '/block', 'revision-delete-form' => '/admin/content/block/{block_content}/revision/{block_content_revision}/delete', 'revision-revert-form' => '/admin/content/block/{block_content}/revision/{block_content_revision}/revert', 'version-history' => '/admin/content/block/{block_content}/revisions'], translatable: true, entity_keys: ['id' => 'id', 'revision' => 'revision_id', 'bundle' => 'type', 'label' => 'info', 'langcode' => 'langcode', 'uuid' => 'uuid', 'published' => 'status'], revision_metadata_keys: ['revision_user' => 'revision_user', 'revision_created' => 'revision_created', 'revision_log_message' => 'revision_log'], bundle_entity_type: 'block_content_type', field_ui_base_route: 'entity.block_content_type.edit_form', render_cache: false)] +class BlockContent extends EditorialContentEntityBase implements BlockContentInterface { + +}