EntityLoadByUuid.php 5.96 KB
Newer Older
pmelab's avatar
pmelab committed
1
2
3
4
5
<?php

namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Entity;

use Drupal\Core\Entity\EntityRepositoryInterface;
6
use Drupal\Core\Entity\EntityTypeManagerInterface;
pmelab's avatar
pmelab committed
7
8
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
9
use Drupal\Core\Session\AccountInterface;
pmelab's avatar
pmelab committed
10
use Drupal\graphql\GraphQL\Buffers\EntityUuidBuffer;
11
use Drupal\graphql\GraphQL\Execution\FieldContext;
pmelab's avatar
pmelab committed
12
13
14
15
16
use Drupal\graphql\Plugin\GraphQL\DataProducer\DataProducerPluginBase;
use GraphQL\Deferred;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
17
18
 * Loads an entity by UUID.
 *
pmelab's avatar
pmelab committed
19
20
 * @DataProducer(
 *   id = "entity_load_by_uuid",
21
22
 *   name = @Translation("Load entity by uuid"),
 *   description = @Translation("Loads a single entity by uuid."),
pmelab's avatar
pmelab committed
23
24
25
26
 *   produces = @ContextDefinition("entity",
 *     label = @Translation("Entity")
 *   ),
 *   consumes = {
27
 *     "type" = @ContextDefinition("string",
pmelab's avatar
pmelab committed
28
29
 *       label = @Translation("Entity type")
 *     ),
30
 *     "uuid" = @ContextDefinition("string",
pmelab's avatar
pmelab committed
31
32
 *       label = @Translation("Unique identifier")
 *     ),
33
 *     "language" = @ContextDefinition("string",
34
 *       label = @Translation("Entity language"),
pmelab's avatar
pmelab committed
35
36
 *       required = FALSE
 *     ),
37
 *     "bundles" = @ContextDefinition("string",
pmelab's avatar
pmelab committed
38
39
40
 *       label = @Translation("Entity bundle(s)"),
 *       multiple = TRUE,
 *       required = FALSE
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 *     ),
 *     "access" = @ContextDefinition("boolean",
 *       label = @Translation("Check access"),
 *       required = FALSE,
 *       default_value = TRUE
 *     ),
 *     "access_user" = @ContextDefinition("entity:user",
 *       label = @Translation("User"),
 *       required = FALSE,
 *       default_value = NULL
 *     ),
 *     "access_operation" = @ContextDefinition("string",
 *       label = @Translation("Operation"),
 *       required = FALSE,
 *       default_value = "view"
pmelab's avatar
pmelab committed
56
57
58
59
60
61
62
63
64
 *     )
 *   }
 * )
 */
class EntityLoadByUuid extends DataProducerPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The entity type manager service.
   *
65
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
pmelab's avatar
pmelab committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
   */
  protected $entityTypeManager;

  /**
   * The entity repository service.
   *
   * @var \Drupal\Core\Entity\EntityRepositoryInterface
   */
  protected $entityRepository;

  /**
   * The entity buffer service.
   *
   * @var \Drupal\graphql\GraphQL\Buffers\EntityUuidBuffer
   */
  protected $entityBuffer;

  /**
   * {@inheritdoc}
   *
   * @codeCoverageIgnore
   */
  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('entity.repository'),
      $container->get('graphql.buffer.entity_uuid')
    );
  }

  /**
   * EntityLoad constructor.
   *
   * @param array $configuration
   *   The plugin configuration array.
   * @param string $pluginId
   *   The plugin id.
   * @param array $pluginDefinition
   *   The plugin definition array.
108
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
pmelab's avatar
pmelab committed
109
110
111
112
113
114
115
116
117
   *   The entity type manager service.
   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entityRepository
   *   The entity repository service.
   * @param \Drupal\graphql\GraphQL\Buffers\EntityUuidBuffer $entityBuffer
   *   The entity buffer service.
   *
   * @codeCoverageIgnore
   */
  public function __construct(
118
    array $configuration,
pmelab's avatar
pmelab committed
119
    $pluginId,
120
    array $pluginDefinition,
121
    EntityTypeManagerInterface $entityTypeManager,
pmelab's avatar
pmelab committed
122
123
124
125
126
127
128
129
130
131
    EntityRepositoryInterface $entityRepository,
    EntityUuidBuffer $entityBuffer
  ) {
    parent::__construct($configuration, $pluginId, $pluginDefinition);
    $this->entityTypeManager = $entityTypeManager;
    $this->entityRepository = $entityRepository;
    $this->entityBuffer = $entityBuffer;
  }

  /**
132
133
   * Resolver.
   *
134
135
   * @param string $type
   * @param string $uuid
136
   * @param string|null $language
137
   * @param array|null $bundles
138
139
140
   * @param bool|null $access
   * @param \Drupal\Core\Session\AccountInterface|null $accessUser
   * @param string|null $accessOperation
141
   * @param \Drupal\graphql\GraphQL\Execution\FieldContext $context
pmelab's avatar
pmelab committed
142
143
144
   *
   * @return \GraphQL\Deferred
   */
145
  public function resolve($type, $uuid, ?string $language, ?array $bundles, ?bool $access, ?AccountInterface $accessUser, ?string $accessOperation, FieldContext $context) {
pmelab's avatar
pmelab committed
146
147
    $resolver = $this->entityBuffer->add($type, $uuid);

148
    return new Deferred(function () use ($type, $language, $bundles, $resolver, $context, $access, $accessUser, $accessOperation) {
pmelab's avatar
pmelab committed
149
      if (!$entity = $resolver()) {
150
151
152
        // If there is no entity with this id, add the list cache tags so that
        // the cache entry is purged whenever a new entity of this type is
        // saved.
pmelab's avatar
pmelab committed
153
154
155
        $type = $this->entityTypeManager->getDefinition($type);
        /** @var \Drupal\Core\Entity\EntityTypeInterface $type */
        $tags = $type->getListCacheTags();
156
        $context->addCacheTags($tags);
pmelab's avatar
pmelab committed
157
158
159
        return NULL;
      }

160
161
162
163
164
165
166
167
168
169
170
171
      $context->addCacheableDependency($entity);
      if (isset($bundles) && !in_array($entity->bundle(), $bundles)) {
        // If the entity is not among the allowed bundles, don't return it.
        return NULL;
      }

      // Get the correct translation.
      if (isset($language) && $language != $entity->language()->getId() && $entity instanceof TranslatableInterface) {
        $entity = $entity->getTranslation($language);
        $entity->addCacheContexts(["static:language:{$language}"]);
      }

172
173
174
      // Check if the passed user (or current user if none is passed) has access
      // to the entity, if not return NULL.
      if ($access) {
175
        /** @var \Drupal\Core\Access\AccessResultInterface $accessResult */
176
177
        $accessResult = $entity->access($accessOperation, $accessUser, TRUE);
        $context->addCacheableDependency($accessResult);
Radoslav Terezka's avatar
Radoslav Terezka committed
178
        if (!$accessResult->isAllowed()) {
179
180
181
182
          return NULL;
        }
      }

pmelab's avatar
pmelab committed
183
184
185
      return $entity;
    });
  }
186

pmelab's avatar
pmelab committed
187
}