Skip to content
Snippets Groups Projects

Provide a version parameter to entity by id queries to provide the latest or...

Files

<?php
declare(strict_types=1);
namespace Drupal\graphql_compose\Plugin\GraphQL\DataProducer;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\Entity\RevisionableStorageInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Entity\TranslatableRevisionableStorageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\graphql\GraphQL\Execution\FieldContext;
use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
use Drupal\graphql_compose\Plugin\GraphQLCompose\SchemaType\VersionType;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* The entity version fallback.
*
* @DataProducer(
* id = "entity_version_fallback",
* name = @Translation("Entity revision fallback"),
* description = @Translation("Returns the entity by version (i.e. latest or working-copy) with optional fallback."),
* produces = @ContextDefinition("entity",
* label = @Translation("Versioned entity")
* ),
* consumes = {
* "entity" = @ContextDefinition("entity",
* label = @Translation("Entity")
* ),
* "version" = @ContextDefinition("string",
* label = @Translation("version"),
* required = FALSE
* ),
* "langcode" = @ContextDefinition("string",
* label = @Translation("langcode"),
* required = FALSE
* ),
* "fallback" = @ContextDefinition("boolean",
* label = @Translation("Return same entity as fallback"),
* required = FALSE
* )
* }
* )
*/
class EntityVersionFallback extends DataProducerPluginBase implements ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a EntityTranslationRevisionFallback.
*
* @param array $configuration
* The plugin configuration.
* @param string $plugin_id
* The plugin id.
* @param array $plugin_definition
* The plugin definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->languageManager = $language_manager;
}
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('language_manager')
);
}
/**
* Returns the entity for a given revision and translation.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
* @param string|null $version
* The version.
* @param string|null $langcode
* The entity langcode.
* @param bool|null $fallback
* Flag to indicate whether to fallback to original entity.
* @param \Drupal\graphql\GraphQL\Execution\FieldContext $context
* The GraphQL context.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* The revised entity.
*/
public function resolve(EntityInterface $entity, ?string $version, ?string $langcode, ?bool $fallback, FieldContext $context) {
// If the version value is null or 'working-copy' just return the entity.
if ($version !== VersionType::WORKING_COPY) {
return $entity;
}
if ($entity instanceof RevisionableInterface && $entity->getEntityType()->isRevisionable()) {
if ($version_id = $this->getRevisionId($entity, $langcode)) {
$entity = $this->getRevisionStorage($entity)->loadRevision($version_id);
if ($langcode && $entity instanceof TranslatableInterface && $entity->hasTranslation($langcode)) {
$entity = $entity->getTranslation($langcode);
}
$entity->addCacheContexts(["static:version:{$version_id}"]);
/** @var \Drupal\Core\Access\AccessResultInterface $accessResult */
$accessResult = $entity->access('view', NULL, TRUE);
$context->addCacheableDependency($accessResult);
if (!$accessResult->isAllowed()) {
return NULL;
}
$context->setContextValue('version', $version_id);
return $entity;
}
}
// Fallback to the current entity.
if ($fallback) {
return $entity;
}
return NULL;
}
/**
* Get the revision id for an entity.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The revisable entity.
* @param string|null $langcode
* The entity langcode.
*
* @return int|string|null
* Returns the revision id OTHERWISE null.
*/
protected function getRevisionId(EntityInterface $entity, ?string $langcode) : int|string|null {
$entity_storage = $this->getRevisionStorage($entity);
$version_id = NULL;
if ($entity_storage instanceof RevisionableStorageInterface) {
$entity_id = $entity->id();
if ($entity_storage instanceof TranslatableRevisionableStorageInterface) {
$version_id = $entity_storage->getLatestTranslationAffectedRevisionId(
$entity_id,
$langcode ?? $this->languageManager->getDefaultLanguage()->getId(),
);
}
else {
$version_id = $entity_storage->getLatestRevisionId($entity_id);
}
}
return $version_id;
}
/**
* Provides the storage interface.
*
* @param \Drupal\Core\Entity\RevisionableInterface $entity
* The entity.
*
* @return \Drupal\Core\Entity\RevisionableStorageInterface
* The revisionable storage interface.
*/
protected function getRevisionStorage(RevisionableInterface $entity) : RevisionableStorageInterface {
return $this->entityTypeManager->getStorage($entity->getEntityTypeId());
}
}
Loading