class EntityRepository in Drupal 9
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/Entity/EntityRepository.php \Drupal\Core\Entity\EntityRepository
Provides several mechanisms for retrieving entities.
Hierarchy
- class \Drupal\Core\Entity\EntityRepository implements EntityRepositoryInterface
Expanded class hierarchy of EntityRepository
1 file declares its use of EntityRepository
- EntityRepositoryTest.php in core/
tests/ Drupal/ Tests/ Core/ Entity/ EntityRepositoryTest.php
1 string reference to 'EntityRepository'
- core.services.yml in core/
core.services.yml - core/core.services.yml
1 service uses EntityRepository
File
- core/
lib/ Drupal/ Core/ Entity/ EntityRepository.php, line 14
Namespace
Drupal\Core\EntityView source
class EntityRepository implements EntityRepositoryInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The context repository service.
*
* @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
*/
protected $contextRepository;
/**
* Constructs a new EntityRepository.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
* The context repository service.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, ContextRepositoryInterface $context_repository) {
$this->entityTypeManager = $entity_type_manager;
$this->languageManager = $language_manager;
$this->contextRepository = $context_repository;
}
/**
* {@inheritdoc}
*/
public function loadEntityByUuid($entity_type_id, $uuid) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
if (!($uuid_key = $entity_type
->getKey('uuid'))) {
throw new EntityStorageException("Entity type {$entity_type_id} does not support UUIDs.");
}
$entities = $this->entityTypeManager
->getStorage($entity_type_id)
->loadByProperties([
$uuid_key => $uuid,
]);
return $entities ? reset($entities) : NULL;
}
/**
* {@inheritdoc}
*/
public function loadEntityByConfigTarget($entity_type_id, $target) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
// For configuration entities, the config target is given by the entity ID.
// @todo Consider adding a method to allow entity types to indicate the
// target identifier key rather than hard-coding this check. Issue:
// https://www.drupal.org/node/2412983.
if ($entity_type instanceof ConfigEntityTypeInterface) {
$entity = $this->entityTypeManager
->getStorage($entity_type_id)
->load($target);
}
else {
$entity = $this
->loadEntityByUuid($entity_type_id, $target);
}
return $entity;
}
/**
* {@inheritdoc}
*/
public function getTranslationFromContext(EntityInterface $entity, $langcode = NULL, $context = []) {
$translation = $entity;
if ($entity instanceof TranslatableDataInterface && count($entity
->getTranslationLanguages()) > 1) {
if (empty($langcode)) {
$langcode = $this->languageManager
->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
->getId();
$entity
->addCacheContexts([
'languages:' . LanguageInterface::TYPE_CONTENT,
]);
}
// Retrieve language fallback candidates to perform the entity language
// negotiation, unless the current translation is already the desired one.
if ($entity
->language()
->getId() != $langcode) {
$context['data'] = $entity;
$context += [
'operation' => 'entity_view',
'langcode' => $langcode,
];
$candidates = $this->languageManager
->getFallbackCandidates($context);
// Ensure the default language has the proper language code.
$default_language = $entity
->getUntranslated()
->language();
$candidates[$default_language
->getId()] = LanguageInterface::LANGCODE_DEFAULT;
// Return the most fitting entity translation.
foreach ($candidates as $candidate) {
if ($entity
->hasTranslation($candidate)) {
$translation = $entity
->getTranslation($candidate);
break;
}
}
}
}
return $translation;
}
/**
* {@inheritdoc}
*/
public function getActive($entity_type_id, $entity_id, array $contexts = NULL) {
return current($this
->getActiveMultiple($entity_type_id, [
$entity_id,
], $contexts)) ?: NULL;
}
/**
* {@inheritdoc}
*/
public function getActiveMultiple($entity_type_id, array $entity_ids, array $contexts = NULL) {
$active = [];
if (!isset($contexts)) {
$contexts = $this->contextRepository
->getAvailableContexts();
}
// @todo Consider implementing a more performant version of this logic fully
// supporting multiple entities in https://www.drupal.org/node/3031082.
$langcode = $this->languageManager
->isMultilingual() ? $this
->getContentLanguageFromContexts($contexts) : $this->languageManager
->getDefaultLanguage()
->getId();
$entities = $this->entityTypeManager
->getStorage($entity_type_id)
->loadMultiple($entity_ids);
foreach ($entities as $id => $entity) {
// Retrieve the fittest revision, if needed.
if ($entity instanceof RevisionableInterface && $entity
->getEntityType()
->isRevisionable()) {
$entity = $this
->getLatestTranslationAffectedRevision($entity, $langcode);
}
// Retrieve the fittest translation, if needed.
if ($entity instanceof TranslatableInterface) {
$entity = $this
->getTranslationFromContext($entity, $langcode);
}
$active[$id] = $entity;
}
return $active;
}
/**
* {@inheritdoc}
*/
public function getCanonical($entity_type_id, $entity_id, array $contexts = NULL) {
return current($this
->getCanonicalMultiple($entity_type_id, [
$entity_id,
], $contexts)) ?: NULL;
}
/**
* {@inheritdoc}
*/
public function getCanonicalMultiple($entity_type_id, array $entity_ids, array $contexts = NULL) {
$entities = $this->entityTypeManager
->getStorage($entity_type_id)
->loadMultiple($entity_ids);
if (!$entities || !$this->languageManager
->isMultilingual()) {
return $entities;
}
if (!isset($contexts)) {
$contexts = $this->contextRepository
->getAvailableContexts();
}
// @todo Consider deprecating the legacy context operation altogether in
// https://www.drupal.org/node/3031124.
$legacy_context = [];
$key = static::CONTEXT_ID_LEGACY_CONTEXT_OPERATION;
if (isset($contexts[$key])) {
$legacy_context['operation'] = $contexts[$key]
->getContextValue();
}
$canonical = [];
$langcode = $this
->getContentLanguageFromContexts($contexts);
foreach ($entities as $id => $entity) {
$canonical[$id] = $this
->getTranslationFromContext($entity, $langcode, $legacy_context);
}
return $canonical;
}
/**
* Retrieves the current content language from the specified contexts.
*
* @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
* An array of context items.
*
* @return string|null
* A language code or NULL if no language context was provided.
*/
protected function getContentLanguageFromContexts(array $contexts) {
// Content language might not be configurable, in which case we need to fall
// back to a configurable language type.
foreach ([
LanguageInterface::TYPE_CONTENT,
LanguageInterface::TYPE_INTERFACE,
] as $language_type) {
$context_id = '@language.current_language_context:' . $language_type;
if (isset($contexts[$context_id])) {
return $contexts[$context_id]
->getContextValue()
->getId();
}
}
return $this->languageManager
->getDefaultLanguage()
->getId();
}
/**
* 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.
*/
protected function getLatestTranslationAffectedRevision(RevisionableInterface $entity, $langcode) {
$revision = NULL;
$storage = $this->entityTypeManager
->getStorage($entity
->getEntityTypeId());
if ($entity instanceof TranslatableRevisionableInterface && $entity
->isTranslatable()) {
/** @var \Drupal\Core\Entity\TranslatableRevisionableStorageInterface $storage */
$revision_id = $storage
->getLatestTranslationAffectedRevisionId($entity
->id(), $langcode);
// If the latest translation-affecting revision was a default revision, it
// is fine to load the latest revision instead, because in this case the
// latest revision, regardless of it being default or pending, will always
// contain the most up-to-date values for the specified translation. This
// provides a BC behavior when the route is defined by a module always
// expecting the latest revision to be loaded and to be the default
// revision. In this particular case the latest revision is always going
// to be the default revision, since pending revisions would not be
// supported.
$revision = $revision_id ? $this
->loadRevision($entity, $revision_id) : NULL;
if (!$revision || $revision
->wasDefaultRevision() && !$revision
->isDefaultRevision()) {
$revision = NULL;
}
}
// Fall back to the latest revisions if no affected revision for the current
// content language could be found. This is acceptable as it means the
// entity is not translated. This is the correct logic also on monolingual
// sites.
if (!isset($revision)) {
$revision_id = $storage
->getLatestRevisionId($entity
->id());
$revision = $this
->loadRevision($entity, $revision_id);
}
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.
*/
protected function loadRevision(RevisionableInterface $entity, $revision_id) {
// 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);
}
return $entity;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityRepository:: |
protected | property | The context repository service. | |
EntityRepository:: |
protected | property | The entity type manager. | |
EntityRepository:: |
protected | property | The language manager. | |
EntityRepository:: |
public | function |
Retrieves the active entity variant matching the specified context. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
public | function |
Retrieves the active entity variants matching the specified context. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
public | function |
Retrieves the canonical entity variant matching the specified context. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
public | function |
Retrieves the canonical entity variants matching the specified context. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
protected | function | Retrieves the current content language from the specified contexts. | |
EntityRepository:: |
protected | function | Returns the latest revision translation of the specified entity. | |
EntityRepository:: |
public | function |
Gets the entity translation to be used in the given context. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
public | function |
Loads an entity by the config target identifier. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
public | function |
Loads an entity by UUID. Overrides EntityRepositoryInterface:: |
|
EntityRepository:: |
protected | function | Loads the specified entity revision. | |
EntityRepository:: |
public | function | Constructs a new EntityRepository. | |
EntityRepositoryInterface:: |
constant |