class EntityMethodDeriver

Same name and namespace in other branches
  1. 10 core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityMethodDeriver.php \Drupal\Core\Config\Action\Plugin\ConfigAction\Deriver\EntityMethodDeriver

Derives config action methods from attributed config entity methods.

@internal This API is experimental.

Hierarchy

Expanded class hierarchy of EntityMethodDeriver

1 file declares its use of EntityMethodDeriver
EntityMethod.php in core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityMethod.php

File

core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityMethodDeriver.php, line 26

Namespace

Drupal\Core\Config\Action\Plugin\ConfigAction\Deriver
View source
final class EntityMethodDeriver extends DeriverBase implements ContainerDeriverInterface {
    use StringTranslationTrait;
    
    /**
     * Inflector to pluralize words.
     */
    protected readonly InflectorInterface $inflector;
    
    /**
     * Constructs new EntityMethodDeriver.
     *
     * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
     *   The entity type manager.
     */
    public function __construct(EntityTypeManagerInterface $entityTypeManager) {
        $this->inflector = new EnglishInflector();
    }
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container, $base_plugin_id) {
        return new static($container->get('entity_type.manager'));
    }
    
    /**
     * {@inheritdoc}
     */
    public function getDerivativeDefinitions($base_plugin_definition) {
        // Scan all the config entity classes for attributes.
        foreach ($this->entityTypeManager
            ->getDefinitions() as $entity_type) {
            if ($entity_type instanceof ConfigEntityTypeInterface) {
                $reflectionClass = new \ReflectionClass($entity_type->getClass());
                while ($reflectionClass) {
                    foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
                        // Only process a method if it is declared on the current class.
                        // Methods on the parent class will be processed later. This allows
                        // for a parent to have an attribute and an overriding class does
                        // not need one. For example,
                        // \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::setComponent()
                        // and \Drupal\Core\Entity\EntityDisplayBase::setComponent().
                        if ($method->getDeclaringClass()
                            ->getName() === $reflectionClass->getName()) {
                            foreach ($method->getAttributes(ActionMethod::class) as $attribute) {
                                $this->processMethod($method, $attribute->newInstance(), $entity_type, $base_plugin_definition);
                            }
                        }
                    }
                    $reflectionClass = $reflectionClass->getParentClass();
                }
            }
        }
        return $this->derivatives;
    }
    
    /**
     * Processes a method to create derivatives.
     *
     * @param \ReflectionMethod $method
     *   The entity method.
     * @param \Drupal\Core\Config\Action\Attribute\ActionMethod $action_attribute
     *   The entity method attribute.
     * @param \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type
     *   The entity type.
     * @param array $derivative
     *   The base plugin definition that will used to create the derivative.
     */
    private function processMethod(\ReflectionMethod $method, ActionMethod $action_attribute, ConfigEntityTypeInterface $entity_type, array $derivative) : void {
        $derivative['admin_label'] = $action_attribute->adminLabel ?: $this->t('@entity_type @method', [
            '@entity_type' => $entity_type->getLabel(),
            '@method' => $method->name,
        ]);
        $derivative['constructor_args'] = [
            'method' => $method->name,
            'exists' => $action_attribute->exists,
            'numberOfParams' => $method->getNumberOfParameters(),
            'numberOfRequiredParams' => $method->getNumberOfRequiredParameters(),
            'pluralized' => FALSE,
        ];
        $derivative['entity_types'] = [
            $entity_type->id(),
        ];
        // Build a config action identifier from the entity type's config
        // prefix  and the method name. For example, the Role entity adds a
        // 'user.role:grantPermission' action.
        $this->addDerivative($method->name, $entity_type, $derivative, $method->name);
        $pluralized_name = match (TRUE) {    is_string($action_attribute->pluralize) => $action_attribute->pluralize,
            $action_attribute->pluralize === FALSE => '',
            default => $this->inflector
                ->pluralize($method->name)[0],
        
        };
        // Add a pluralized version of the plugin.
        if (strlen($pluralized_name) > 0) {
            $derivative['constructor_args']['pluralized'] = TRUE;
            $derivative['admin_label'] = $this->t('@admin_label (multiple calls)', [
                '@admin_label' => $derivative['admin_label'],
            ]);
            $this->addDerivative($pluralized_name, $entity_type, $derivative, $method->name);
        }
    }
    
    /**
     * Adds a derivative.
     *
     * @param string $action_id
     *   The action ID.
     * @param \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type
     *   The entity type.
     * @param array $derivative
     *   The derivative definition.
     * @param string $methodName
     *   The method name.
     */
    private function addDerivative(string $action_id, ConfigEntityTypeInterface $entity_type, array $derivative, string $methodName) : void {
        $id = $entity_type->getConfigPrefix() . PluginBase::DERIVATIVE_SEPARATOR . $action_id;
        if (isset($this->derivatives[$id])) {
            throw new EntityMethodException(sprintf('Duplicate action can not be created for ID \'%s\' for %s::%s(). The existing action is for the ::%s() method', $id, $entity_type->getClass(), $methodName, $this->derivatives[$id]['constructor_args']['method']));
        }
        $this->derivatives[$id] = $derivative;
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
DeriverBase::$derivatives protected property List of derivative definitions. 1
DeriverBase::getDerivativeDefinition public function Gets the definition of a derivative plugin. Overrides DeriverInterface::getDerivativeDefinition
EntityMethodDeriver::$inflector protected property Inflector to pluralize words.
EntityMethodDeriver::addDerivative private function Adds a derivative.
EntityMethodDeriver::create public static function Creates a new class instance. Overrides ContainerDeriverInterface::create
EntityMethodDeriver::getDerivativeDefinitions public function Gets the definition of all derivatives of a base plugin. Overrides DeriverBase::getDerivativeDefinitions
EntityMethodDeriver::processMethod private function Processes a method to create derivatives.
EntityMethodDeriver::__construct public function Constructs new EntityMethodDeriver.
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.