From 1cac63498a3c60693e8cebff1455fb272868dd17 Mon Sep 17 00:00:00 2001 From: chx Date: Fri, 7 Feb 2025 04:58:15 -0800 Subject: [PATCH] Fix up makeEntitiesAvailableWithShortClassNames for php:cli (#6221) * Fix up makeEntitiesAvailableWithShortClassNames * also add __construct changes * Comment the new code * Add bundle classes * Add a usage example * formatting --- src/Commands/core/CliCommands.php | 49 +++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/Commands/core/CliCommands.php b/src/Commands/core/CliCommands.php index d8dbeee7e7..f7f1228025 100644 --- a/src/Commands/core/CliCommands.php +++ b/src/Commands/core/CliCommands.php @@ -9,7 +9,9 @@ use Drupal\Core\Config\ConfigBase; use Drupal\Core\Config\Entity\ConfigEntityInterface; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\EntityTypeRepositoryInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FieldItemListInterface; use Drush\Attributes as CLI; @@ -34,7 +36,9 @@ final class CliCommands extends DrushCommands const PHP = 'php:cli'; public function __construct( - protected EntityTypeManagerInterface $entityTypeManager + protected EntityTypeManagerInterface $entityTypeManager, + protected EntityTypeRepositoryInterface $entityTypeRepository, + protected EntityTypeBundleInfoInterface $entityTypeBundleInfo ) { parent::__construct(); } @@ -59,6 +63,7 @@ public function docs(): void #[CLI\Option(name: 'cwd', description: 'A directory to change to before launching the shell. Default is the project root directory')] #[CLI\Topics(topics: [self::DOCS_REPL])] #[CLI\Usage(name: '$node = Node::load(1)', description: 'Entity classes are available without their namespace. For example, Node::load(1) works instead of Drupal\Node\entity\Node::load(1).')] + #[CLI\Usage(name: '$node = NodeArticle::load(1)', description: 'Entity bundles classes are also available without their namespace. For example, NodeArticle::load(1) works instead of Drupal\node_article\entity\NodeArticle::load(1).')] #[CLI\Usage(name: '$paragraph = Paragraph::loadRevision(1)', description: 'Also, a loadRevision static method is made available for easier load of revisions.')] #[CLI\Bootstrap(level: DrupalBootLevels::FULL)] public function cli(array $options = ['version-history' => false, 'cwd' => self::REQ]): void @@ -309,18 +314,36 @@ protected function getPhpKeywords(): array public function makeEntitiesAvailableWithShortClassNames(): void { - foreach ($this->entityTypeManager->getDefinitions() as $definition) { - $class = $definition->getClass(); - $reflectionClass = new \ReflectionClass($class); - $parts = explode('\\', $class); - $end = end($parts); - // https://github.com/drush-ops/drush/pull/5729, https://github.com/drush-ops/drush/issues/5730 - // and https://github.com/drush-ops/drush/issues/5899. - if ($reflectionClass->isFinal() || $reflectionClass->isAbstract() || class_exists($end)) { - continue; + // The entity type repository stores a map from class name to entity + // type id, sneak our short classes in there. + $classNameEntityTypeMapReflection = (new \ReflectionObject($this->entityTypeRepository))->getProperty('classNameEntityTypeMap'); + $classNameEntityTypeMap = $classNameEntityTypeMapReflection->getValue($this->entityTypeRepository); + foreach ($this->entityTypeManager->getDefinitions() as $entityTypeId => $definition) { + $classNameEntityTypeMap = $this->createShortClassForEntityClass($definition->getClass(), $entityTypeId, $classNameEntityTypeMap); + foreach ($this->entityTypeBundleInfo->getAllBundleInfo() as $bundles) { + foreach ($bundles as $info) { + if (isset($info['class'])) { + $classNameEntityTypeMap = $this->createShortClassForEntityClass($info['class'], $entityTypeId, $classNameEntityTypeMap); + } + } } - // Make it possible to easily load revisions. - eval(sprintf('class %s extends %s { + } + $classNameEntityTypeMapReflection->setValue($this->entityTypeRepository, $classNameEntityTypeMap); + } + + public function createShortClassForEntityClass(string $class, string $entityTypeId, array $classNameEntityTypeMap): array + { + $reflectionClass = new \ReflectionClass($class); + $parts = explode('\\', $class); + $end = end($parts); + // https://github.com/drush-ops/drush/pull/5729, https://github.com/drush-ops/drush/issues/5730 + // and https://github.com/drush-ops/drush/issues/5899. + if ($reflectionClass->isFinal() || $reflectionClass->isAbstract() || class_exists($end)) { + return $classNameEntityTypeMap; + } + $classNameEntityTypeMap[$end] = $entityTypeId; + // Make it possible to easily load revisions. + eval(sprintf('class %s extends %s { public static function loadRevision($id) { $entity_type_repository = \Drupal::service("entity_type.repository"); $entity_type_manager = \Drupal::entityTypeManager(); @@ -328,6 +351,6 @@ public static function loadRevision($id) { return $storage->loadRevision($id); } }', $end, $class)); - } + return $classNameEntityTypeMap; } }