Completed
Pull Request — 8.x-3.x (#399)
by Philipp
02:23
created

ViewDeriverBase::getArgumentsInfo()   D

Complexity

Conditions 9
Paths 6

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 22
nc 6
nop 1
dl 0
loc 34
rs 4.909
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\graphql_core\Plugin\Deriver;
4
5
use Drupal\Component\Plugin\Derivative\DeriverBase;
6
use Drupal\Component\Plugin\PluginManagerInterface;
7
use Drupal\Component\Utility\NestedArray;
8
use Drupal\Core\Entity\EntityTypeManagerInterface;
9
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
10
use Drupal\graphql\Plugin\views\row\GraphQLEntityRow;
11
use Drupal\graphql\Plugin\views\row\GraphQLFieldRow;
12
use Drupal\graphql\Utility\StringHelper;
13
use Drupal\views\Plugin\views\display\DisplayPluginInterface;
14
use Drupal\views\ViewEntityInterface;
15
use Symfony\Component\DependencyInjection\ContainerInterface;
16
17
/**
18
 * Base class for graphql view derivers.
19
 */
20
abstract class ViewDeriverBase extends DeriverBase implements ContainerDeriverInterface {
21
  /**
22
   * The entity type manager.
23
   *
24
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
25
   */
26
  protected $entityTypeManager;
27
28
  /**
29
   * The interface plugin manager to search for return type candidates.
30
   *
31
   * @var \Drupal\Component\Plugin\PluginManagerInterface
32
   */
33
  protected $interfacePluginManager;
34
35
  /**
36
   * An key value pair of data tables and the entities they belong to.
37
   *
38
   * @var string[]
39
   */
40
  protected $dataTables;
41
42
  /**
43
   * {@inheritdoc}
44
   */
45
  public static function create(ContainerInterface $container, $basePluginId) {
46
    return new static(
47
      $container->get('entity_type.manager'),
48
      $container->get('plugin.manager.graphql.interface')
49
    );
50
  }
51
52
  /**
53
   * Creates a ViewDeriver object.
54
   *
55
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
56
   *   An entity type manager instance.
57
   * @param \Drupal\Component\Plugin\PluginManagerInterface $interfacePluginManager
58
   *   The plugin manager for graphql interfaces.
59
   */
60
  public function __construct(
61
    EntityTypeManagerInterface $entityTypeManager,
62
    PluginManagerInterface $interfacePluginManager
63
  ) {
64
    $this->interfacePluginManager = $interfacePluginManager;
65
    $this->entityTypeManager = $entityTypeManager;
66
  }
67
68
  /**
69
   * Check if a pager is configured.
70
   *
71
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
72
   *   The display configuration.
73
   *
74
   * @return bool
75
   *   Flag indicating if the view is configured with a pager.
76
   */
77
  protected function isPaged(DisplayPluginInterface $display) {
78
    $pagerOptions = $display->getOption('pager');
79
    return isset($pagerOptions['type']) && in_array($pagerOptions['type'], ['full', 'mini']);
80
  }
81
82
  /**
83
   * Get the configured default limit.
84
   *
85
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
86
   *   The display configuration.
87
   *
88
   * @return int
89
   *   The default limit.
90
   */
91
  protected function getPagerLimit(DisplayPluginInterface $display) {
92
    $pagerOptions = $display->getOption('pager');
93
    return NestedArray::getValue($pagerOptions, [
94
      'options', 'items_per_page',
95
    ]) ?: 0;
96
  }
97
98
  /**
99
   * Get the configured default offset.
100
   *
101
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
102
   *   The display configuration.
103
   *
104
   * @return int
105
   *   The default offset.
106
   */
107
  protected function getPagerOffset(DisplayPluginInterface $display) {
108
    $pagerOptions = $display->getOption('pager');
109
    return NestedArray::getValue($pagerOptions, [
110
      'options', 'offset',
111
    ]) ?: 0;
112
  }
113
114
  /**
115
   * Retrieves the entity type id of an entity by its base or data table.
116
   *
117
   * @param string $table
118
   *   The base or data table of an entity.
119
   *
120
   * @return string
121
   *   The id of the entity type that the given base table belongs to.
122
   */
123
  protected function getEntityTypeByTable($table) {
124
    if (!isset($this->dataTables)) {
125
      $this->dataTables = [];
126
127
      foreach ($this->entityTypeManager->getDefinitions() as $entityTypeId => $entityType) {
128
        if ($dataTable = $entityType->getDataTable()) {
129
          $this->dataTables[$dataTable] = $entityType->id();
130
        }
131
        if ($baseTable = $entityType->getBaseTable()) {
132
          $this->dataTables[$baseTable] = $entityType->id();
133
        }
134
      }
135
    }
136
137
    return !empty($this->dataTables[$table]) ? $this->dataTables[$table] : NULL;
138
  }
139
140
  /**
141
   * Retrieves the type the view's rows resolve to.
142
   *
143
   * @param \Drupal\views\ViewEntityInterface $view
144
   *   The view entity.
145
   * @param $displayId
146
   *   The id of the current display.
147
   *
148
   * @return null|string
149
   *   The name of the type or NULL if the type could not be derived.
150
   */
151
  protected function getRowResolveType(ViewEntityInterface $view, $displayId) {
152
    /** @var \Drupal\graphql\Plugin\views\display\GraphQL $display */
153
    $display = $this->getViewDisplay($view, $displayId);
154
    $rowPlugin = $display->getPlugin('row');
155
156
    if ($rowPlugin instanceof GraphQLFieldRow) {
157
      return StringHelper::camelCase([$display->getGraphQLRowName()]);
158
    }
159
160
    if ($rowPlugin instanceof GraphQLEntityRow) {
161
      $executable = $view->getExecutable();
162
      $executable->setDisplay($displayId);
163
164
      if ($entityType = $executable->getBaseEntityType()) {
165
        $typeName = $entityType->id();
166
        $typeNameCamel = StringHelper::camelCase($typeName);
167
        if ($this->interfaceExists($typeNameCamel)) {
168
          $filters = $executable->getDisplay()->getOption('filters');
169
          $dataTable = $entityType->getDataTable();
170
          $bundleKey = $entityType->getKey('bundle');
171
172
          foreach ($filters as $filter) {
173
            $isBundleFilter = $filter['table'] == $dataTable && $filter['field'] == $bundleKey;
174
            $isSingleValued = is_array($filter['value']) && count($filter['value']) == 1;
175
            $isExposed = isset($filter['exposed']) && $filter['exposed'];
176
            if ($isBundleFilter && $isSingleValued && !$isExposed) {
177
              $bundle = reset($filter['value']);
178
              $typeName .= "_$bundle";
179
              break;
180
            }
181
          }
182
183
          return StringHelper::camelCase($typeName);
184
        }
185
      }
186
187
      return 'Entity';
188
    }
189
190
    return NULL;
191
  }
192
193
  /**
194
   * Check if a certain interface exists.
195
   *
196
   * @param string $interface
197
   *   The GraphQL interface name.
198
   *
199
   * @return bool
200
   *   Boolean flag indicating if the interface exists.
201
   */
202
  protected function interfaceExists($interface) {
203
    return (bool) array_filter($this->interfacePluginManager->getDefinitions(), function($definition) use ($interface) {
204
      return $definition['name'] === $interface;
205
    });
206
  }
207
208
  /**
209
   * Returns a view display object.
210
   *
211
   * @param \Drupal\views\ViewEntityInterface $view
212
   *   The view object.
213
   * @param string $displayId
214
   *   The display ID to use.
215
   *
216
   * @return \Drupal\views\Plugin\views\display\DisplayPluginInterface
217
   *   The view display object.
218
   */
219
  protected function getViewDisplay(ViewEntityInterface $view, $displayId) {
220
    $viewExecutable = $view->getExecutable();
221
    $viewExecutable->setDisplay($displayId);
222
    return $viewExecutable->getDisplay();
223
  }
224
225
  /**
226
   * Returns a view style object.
227
   *
228
   * @param \Drupal\views\ViewEntityInterface $view
229
   *   The view object.
230
   * @param string $displayId
231
   *   The display ID to use.
232
   *
233
   * @return \Drupal\views\Plugin\views\style\StylePluginBase
234
   *   The view style object.
235
   */
236
  protected function getViewStyle(ViewEntityInterface $view, $displayId) {
237
    $viewExecutable = $view->getExecutable();
238
    $viewExecutable->setDisplay($displayId);
239
    return $viewExecutable->getStyle();
240
  }
241
242
  /**
243
   * Returns cache metadata plugin definitions.
244
   *
245
   * @param \Drupal\views\ViewEntityInterface $view
246
   *   The view object.
247
   *
248
   * @return array
249
   *   The cache metadata definitions for the plugin definition.
250
   */
251
  protected function getCacheMetadataDefinition(ViewEntityInterface $view) {
252
    return [
253
      'schema_cache_tags' => $view->getCacheTags(),
254
      'schema_cache_contexts' => $view->getCacheContexts(),
255
      'schema_cache_max_age' => $view->getCacheMaxAge(),
256
    ];
257
  }
258
259
  /**
260
   * Returns information about view arguments (contextual filters).
261
   *
262
   * @param array $viewArguments
263
   *   The "arguments" option of a view display.
264
   *
265
   * @return array
266
   *   Arguments information keyed by the argument ID. Subsequent array keys:
267
   *     - index: argument index.
268
   *     - entity_type: target entity type.
269
   *     - bundles: target bundles (can be empty).
270
   */
271
  protected function getArgumentsInfo(array $viewArguments) {
272
    $argumentsInfo = [];
273
274
    $index = 0;
275
    foreach ($viewArguments as $argumentId => $argument) {
276
      $info = [
277
        'index' => $index,
278
        'entity_type' => NULL,
279
        'bundles' => [],
280
      ];
281
282
      if (isset($argument['entity_type']) && isset($argument['entity_field'])) {
283
        $entityType = $this->entityTypeManager->getDefinition($argument['entity_type']);
284
        if ($entityType) {
285
          $idField = $entityType->getKey('id');
286
          if ($idField === $argument['entity_field']) {
287
            $info['entity_type'] = $argument['entity_type'];
288
            if (
289
              $argument['specify_validation'] &&
290
              strpos($argument['validate']['type'], 'entity:') === 0 &&
291
              !empty($argument['validate_options']['bundles'])
292
            ) {
293
              $info['bundles'] = $argument['validate_options']['bundles'];
294
            }
295
          }
296
        }
297
      }
298
299
      $argumentsInfo[$argumentId] = $info;
300
      $index++;
301
    }
302
303
    return $argumentsInfo;
304
  }
305
}
306