class EntityConverter

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/ParamConverter/EntityConverter.php \Drupal\Core\ParamConverter\EntityConverter
  2. 10 core/lib/Drupal/Core/ParamConverter/EntityConverter.php \Drupal\Core\ParamConverter\EntityConverter
  3. 11.x core/lib/Drupal/Core/ParamConverter/EntityConverter.php \Drupal\Core\ParamConverter\EntityConverter

Parameter converter for upcasting entity IDs to full objects.

This is useful in cases where the dynamic elements of the path can't be auto-determined; for example, if your path refers to multiple of the same type of entity ("example/{node1}/foo/{node2}") or if the path can act on any entity type ("example/{entity_type}/{entity}/foo").

In order to use it you should specify some additional options in your route:


example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node

If you want to have the entity type itself dynamic in the url you can specify it like the following:


example.route:
  path: foo/{entity_type}/{example}
  options:
    parameters:
      example:
        type: entity:{entity_type}

If your route needs to support pending revisions, you can specify the "load_latest_revision" parameter. This will ensure that the latest revision is returned, even if it is not the default one:


example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node
        load_latest_revision: TRUE

When dealing with translatable entities, the "load_latest_revision" flag will make this converter load the latest revision affecting the translation matching the content language for the current request. If none can be found it will fall back to the latest revision. For instance, if an entity has an English default revision (revision 1) and an Italian pending revision (revision 2), "/foo/1" will return the former, while "/it/foo/1" will return the latter.

Hierarchy

Expanded class hierarchy of EntityConverter

See also

entities_revisions_translations

3 files declare their use of EntityConverter
EntityConverterTest.php in core/tests/Drupal/Tests/Core/ParamConverter/EntityConverterTest.php
EntityRevisionConverter.php in core/modules/content_moderation/src/ParamConverter/EntityRevisionConverter.php
EntityUuidConverter.php in core/modules/jsonapi/src/ParamConverter/EntityUuidConverter.php
1 string reference to 'EntityConverter'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses EntityConverter
paramconverter.entity in core/core.services.yml
Drupal\Core\ParamConverter\EntityConverter

File

core/lib/Drupal/Core/ParamConverter/EntityConverter.php, line 68

Namespace

Drupal\Core\ParamConverter
View source
class EntityConverter implements ParamConverterInterface {
    use DeprecatedServicePropertyTrait;
    use DynamicEntityTypeParamConverterTrait;
    
    /**
     * {@inheritdoc}
     */
    protected $deprecatedProperties = [
        'entityManager' => 'entity.manager',
        'languageManager' => 'language_manager',
    ];
    
    /**
     * Entity type manager which performs the upcasting in the end.
     *
     * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     */
    protected $entityTypeManager;
    
    /**
     * Entity repository.
     *
     * @var \Drupal\Core\Entity\EntityRepositoryInterface
     */
    protected $entityRepository;
    
    /**
     * Constructs a new EntityConverter.
     *
     * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
     *   The entity type manager.
     * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
     *   The entity repository.
     *
     * @see https://www.drupal.org/node/2549139
     * @see https://www.drupal.org/node/2938929
     */
    public function __construct(EntityTypeManagerInterface $entity_type_manager, $entity_repository = NULL) {
        if ($entity_type_manager instanceof EntityManagerInterface) {
            @trigger_error('Passing the entity.manager service to EntityConverter::__construct() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Pass the entity_type.manager service instead. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
        }
        $this->entityTypeManager = $entity_type_manager;
        if (!$entity_repository instanceof EntityRepositoryInterface) {
            @trigger_error('Calling EntityConverter::__construct() with the $entity_repository argument is supported in drupal:8.7.0 and will be required before drupal:9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
            $entity_repository = \Drupal::service('entity.repository');
        }
        $this->entityRepository = $entity_repository;
    }
    
    /**
     * {@inheritdoc}
     */
    public function convert($value, $definition, $name, array $defaults) {
        $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults);
        // If the entity type is revisionable and the parameter has the
        // "load_latest_revision" flag, load the active variant.
        if (!empty($definition['load_latest_revision'])) {
            return $this->entityRepository
                ->getActive($entity_type_id, $value);
        }
        // Do not inject the context repository as it is not an actual dependency:
        // it will be removed once both the TODOs below are fixed.
        
        /** @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface $contexts_repository */
        $contexts_repository = \Drupal::service('context.repository');
        // @todo Consider deprecating the legacy context operation altogether in
        //   https://www.drupal.org/node/3031124.
        $contexts = $contexts_repository->getAvailableContexts();
        $contexts[EntityRepositoryInterface::CONTEXT_ID_LEGACY_CONTEXT_OPERATION] = new Context(new ContextDefinition('string'), 'entity_upcast');
        // @todo At the moment we do not need the current user context, which is
        //   triggering some test failures. We can remove these lines once
        //   https://www.drupal.org/node/2934192 is fixed.
        $context_id = '@user.current_user_context:current_user';
        if (isset($contexts[$context_id])) {
            $account = $contexts[$context_id]->getContextValue();
            unset($account->_skipProtectedUserFieldConstraint);
            unset($contexts[$context_id]);
        }
        $entity = $this->entityRepository
            ->getCanonical($entity_type_id, $value, $contexts);
        return $entity;
    }
    
    /**
     * Returns the latest revision translation of the specified entity.
     *
     * @param \Drupal\Core\Entity\RevisionableInterface $entity
     *   The default revision of the entity being converted.
     * @param string $langcode
     *   The language of the revision translation to be loaded.
     *
     * @return \Drupal\Core\Entity\RevisionableInterface
     *   The latest translation-affecting revision for the specified entity, or
     *   just the latest revision, if the specified entity is not translatable or
     *   does not have a matching translation yet.
     *
     * @deprecated in drupal:8.7.0 and is removed from drupal:9.0.0.
     *   Use \Drupal\Core\Entity\EntityRepositoryInterface::getActive() instead.
     */
    protected function getLatestTranslationAffectedRevision(RevisionableInterface $entity, $langcode) {
        @trigger_error('\\Drupal\\Core\\ParamConverter\\EntityConverter::getLatestTranslationAffectedRevision() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0. Use \\Drupal\\Core\\Entity\\EntityRepositoryInterface::getActive() instead.', E_USER_DEPRECATED);
        $data_type = 'language';
        $context_id_prefix = '@language.current_language_context:';
        $contexts = [
            $context_id_prefix . LanguageInterface::TYPE_CONTENT => new Context(new ContextDefinition($data_type), $langcode),
            $context_id_prefix . LanguageInterface::TYPE_INTERFACE => new Context(new ContextDefinition($data_type), $langcode),
        ];
        $revision = $this->entityRepository
            ->getActive($entity->getEntityTypeId(), $entity->id(), $contexts);
        // The EntityRepositoryInterface::getActive() method performs entity
        // translation negotiation, but this used to return an untranslated entity
        // object as translation negotiation happened later in ::convert().
        if ($revision instanceof TranslatableInterface) {
            $revision = $revision->getUntranslated();
        }
        return $revision;
    }
    
    /**
     * Loads the specified entity revision.
     *
     * @param \Drupal\Core\Entity\RevisionableInterface $entity
     *   The default revision of the entity being converted.
     * @param string $revision_id
     *   The identifier of the revision to be loaded.
     *
     * @return \Drupal\Core\Entity\RevisionableInterface
     *   An entity revision object.
     *
     * @deprecated in drupal:8.7.0 and is removed from drupal:9.0.0.
     */
    protected function loadRevision(RevisionableInterface $entity, $revision_id) {
        @trigger_error('\\Drupal\\Core\\ParamConverter\\EntityConverter::loadRevision() is deprecated in Drupal 8.7.0 and will be removed before Drupal 9.0.0.', E_USER_DEPRECATED);
        // We explicitly perform a loose equality check, since a revision ID may
        // be returned as an integer or a string.
        if ($entity->getLoadedRevisionId() != $revision_id) {
            
            /** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
            $storage = $this->entityTypeManager
                ->getStorage($entity->getEntityTypeId());
            return $storage->loadRevision($revision_id);
        }
        else {
            return $entity;
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function applies($definition, $name, Route $route) {
        if (!empty($definition['type']) && strpos($definition['type'], 'entity:') === 0) {
            $entity_type_id = substr($definition['type'], strlen('entity:'));
            if (strpos($definition['type'], '{') !== FALSE) {
                $entity_type_slug = substr($entity_type_id, 1, -1);
                return $name != $entity_type_slug && in_array($entity_type_slug, $route->compile()
                    ->getVariables(), TRUE);
            }
            return $this->entityTypeManager
                ->hasDefinition($entity_type_id);
        }
        return FALSE;
    }
    
    /**
     * Returns a language manager instance.
     *
     * @return \Drupal\Core\Language\LanguageManagerInterface
     *   The language manager.
     *
     * @internal
     */
    protected function languageManager() {
        return $this->__get('languageManager');
    }

}

Members

Title Sort descending Deprecated Modifiers Object type Summary Overriden Title Overrides
DeprecatedServicePropertyTrait::__get public function Allows to access deprecated/removed properties.
DynamicEntityTypeParamConverterTrait::getEntityTypeFromDefaults protected function Determines the entity type ID given a route definition and route defaults.
EntityConverter::$deprecatedProperties protected property
EntityConverter::$entityRepository protected property Entity repository.
EntityConverter::$entityTypeManager protected property Entity type manager which performs the upcasting in the end.
EntityConverter::applies public function Determines if the converter applies to a specific route and variable. Overrides ParamConverterInterface::applies 2
EntityConverter::convert public function Converts path variables to their corresponding objects. Overrides ParamConverterInterface::convert 3
EntityConverter::getLatestTranslationAffectedRevision Deprecated protected function Returns the latest revision translation of the specified entity.
EntityConverter::languageManager protected function Returns a language manager instance.
EntityConverter::loadRevision Deprecated protected function Loads the specified entity revision.
EntityConverter::__construct public function Constructs a new EntityConverter. 1

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