Completed
Pull Request — 8.x-1.x (#20)
by
unknown
01:16
created

GraphQL::getGraphQLRowName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * @file
5
 * Contains \Drupal\graphql\Plugin\views\display
6
 */
7
8
namespace Drupal\graphql_views\Plugin\views\display;
9
10
use Drupal\Component\Utility\SafeMarkup;
11
use Drupal\Core\Cache\CacheableMetadata;
12
use Drupal\graphql\Utility\StringHelper;
13
use Drupal\views\Plugin\views\display\DisplayPluginBase;
14
use Drupal\Core\Form\FormStateInterface;
15
16
/**
17
 * Provides a display plugin for GraphQL views.
18
 *
19
 * @ViewsDisplay(
20
 *   id = "graphql",
21
 *   title = @Translation("GraphQL"),
22
 *   help = @Translation("Creates a GraphQL entity list display."),
23
 *   admin = @Translation("GraphQL"),
24
 *   graphql_display = TRUE,
25
 *   returns_response = TRUE
26
 * )
27
 */
28
class GraphQL extends DisplayPluginBase {
29
  /**
30
   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAJAX.
31
   */
32
  protected $usesAJAX = FALSE;
33
34
  /**
35
   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesPager.
36
   */
37
  protected $usesPager = FALSE;
38
39
  /**
40
   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesMore.
41
   */
42
  protected $usesMore = FALSE;
43
44
  /**
45
   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesAreas.
46
   */
47
  protected $usesAreas = FALSE;
48
49
  /**
50
   * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::$usesOptions.
51
   */
52
  protected $usesOptions = TRUE;
53
54
  /**
55
   * {@inheritdoc}
56
   */
57
  public function getType() {
58
    return 'graphql';
59
  }
60
61
  /**
62
   * {@inheritdoc}
63
   */
64
  public function usesFields() {
65
    return TRUE;
66
  }
67
68
  /**
69
   * {@inheritdoc}
70
   */
71
  public function usesExposed() {
72
    return TRUE;
73
  }
74
75
  /**
76
   * {@inheritdoc}
77
   */
78
  public function displaysExposed() {
79
    return FALSE;
80
  }
81
82
  /**
83
   * {@inheritdoc}
84
   */
85
  protected function defineOptions() {
86
    $options = parent::defineOptions();
87
88
    // Allow to attach the view to entity types / bundles.
89
    // Similar to the EVA module.
90
    $options['entity_type']['default'] = '';
91
    $options['bundles']['default'] = [];
92
    // Allow to manually provide arguments or using tokens.
93
    $options['argument_mode']['default'] = 'none';
94
    $options['default_argument']['default'] = '';
95
    // Allow to manually provide limit or using tokens.
96
    $options['limit_mode']['default'] = 'none';
97
    $options['default_limit']['default'] = '';
98
99
    // Set the default plugins to 'graphql'.
100
    $options['style']['contains']['type']['default'] = 'graphql';
101
    $options['exposed_form']['contains']['type']['default'] = 'graphql';
102
    $options['row']['contains']['type']['default'] = 'graphql_entity';
103
104
    $options['defaults']['default']['style'] = FALSE;
105
    $options['defaults']['default']['exposed_form'] = FALSE;
106
    $options['defaults']['default']['row'] = FALSE;
107
108
    // Remove css/exposed form settings, as they are not used for the data display.
109
    unset($options['exposed_block']);
110
    unset($options['css_class']);
111
112
    $options['graphql_query_name'] = ['default' => ''];
113
    return $options;
114
  }
115
116
  /**
117
   * Get the user defined query name or the default one.
118
   *
119
   * @return string
120
   *   Query name.
121
   */
122
  public function getGraphQLQueryName() {
123
    return $this->getGraphQLName();
124
  }
125
126
  /**
127
   * Gets the result name.
128
   *
129
   * @return string
130
   *   Result name.
131
   */
132
  public function getGraphQLResultName() {
133
    return $this->getGraphQLName('result', TRUE);
134
  }
135
136
  /**
137
   * Gets the row name.
138
   *
139
   * @return string
140
   *   Row name.
141
   */
142
  public function getGraphQLRowName() {
143
    return $this->getGraphQLName('row', TRUE);
144
  }
145
146
  /**
147
   * Gets the filter input name..
148
   *
149
   * @return string
150
   *   Result name.
151
   */
152
  public function getGraphQLFilterInputName() {
153
    return $this->getGraphQLName('filter_input', TRUE);
154
  }
155
156
  /**
157
   * Gets the contextual filter input name.
158
   *
159
   * @return string
160
   *   Result name.
161
   */
162
  public function getGraphQLContextualFilterInputName() {
163
    return $this->getGraphQLName('contextual_filter_input', TRUE);
164
  }
165
166
  /**
167
   * Returns the formatted name.
168
   *
169
   * @param string|null $suffix
170
   *   Id suffix, eg. row, result.
171
   * @param bool $type
172
   *   Whether to use camel- or snake case. Uses camel case if TRUE. Defaults to
173
   *   FALSE.
174
   *
175
   * @return string The id.
176
   *   The id.
177
   */
178
  public function getGraphQLName($suffix = NULL, $type = FALSE) {
179
    $queryName = strip_tags($this->getOption('graphql_query_name'));
180
181
    if (empty($queryName)) {
182
      $viewId = $this->view->id();
183
      $displayId = $this->display['id'];
184
      $parts = [$viewId, $displayId, 'view', $suffix];
185
      return $type ? call_user_func_array([StringHelper::class, 'camelCase'], $parts) : call_user_func_array([StringHelper::class, 'propCase'], $parts);
186
    }
187
188
    $parts = array_filter([$queryName, $suffix]);
189
    return $type ? call_user_func_array([StringHelper::class, 'camelCase'], $parts) : call_user_func_array([StringHelper::class, 'propCase'], $parts);
190
  }
191
192
  /**
193
   * {@inheritdoc}
194
   */
195
  public function optionsSummary(&$categories, &$options) {
196
    parent::optionsSummary($categories, $options);
197
198
    unset($categories['title']);
199
    unset($categories['pager'], $categories['exposed'], $categories['access']);
200
201
    unset($options['show_admin_links'], $options['analyze-theme'], $options['link_display']);
202
    unset($options['show_admin_links'], $options['analyze-theme'], $options['link_display']);
203
204
    unset($options['title'], $options['access']);
205
    unset($options['exposed_block'], $options['css_class']);
206
    unset($options['query'], $options['group_by']);
207
208
    $categories['graphql'] = [
209
      'title' => $this->t('GraphQL'),
210
      'column' => 'second',
211
      'build' => [
212
        '#weight' => -10,
213
      ],
214
    ];
215
216
    $options['graphql_query_name'] = [
217
      'category' => 'graphql',
218
      'title' => $this->t('Query name'),
219
      'value' => views_ui_truncate($this->getGraphQLQueryName(), 24),
220
    ];
221
222
    if ($entity_type = $this->getOption('entity_type')) {
223
      $entity_info = \Drupal::entityManager()->getDefinition($entity_type);
224
      $type_name = $entity_info->get('label');
225
226
      $bundle_names = [];
227
      $bundle_info = \Drupal::entityManager()->getBundleInfo($entity_type);
228
      foreach ($this->getOption('bundles') as $bundle) {
229
        $bundle_names[] = $bundle_info[$bundle]['label'];
230
      }
231
    }
232
233
    $options['entity_type'] = [
234
      'category' => 'graphql',
235
      'title' => $this->t('Entity type'),
236
      'value' => empty($type_name) ? $this->t('None') : $type_name,
237
    ];
238
239
    $options['bundles'] = [
240
      'category' => 'graphql',
241
      'title' => $this->t('Bundles'),
242
      'value' => empty($bundle_names) ? $this->t('All') : implode(', ', $bundle_names),
243
    ];
244
245
    $argument_mode = $this->getOption('argument_mode');
246
    $options['arguments'] = [
247
      'category' => 'graphql',
248
      'title' => $this->t('Arguments'),
249
      'value' => empty($argument_mode) ? $this->t('GraphqlQuery') : \Drupal\Component\Utility\Html::escape($argument_mode),
250
    ];
251
252
    $limit_mode = $this->getOption('limit_mode');
253
    $options['limit'] = [
254
      'category' => 'graphql',
255
      'title' => $this->t('Limit'),
256
      'value' => empty($limit_mode) ? $this->t('GraphqlQuery') : \Drupal\Component\Utility\Html::escape($limit_mode),
257
    ];
258
259
  }
260
261
  /**
262
   * {@inheritdoc}
263
   */
264
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
265
    parent::buildOptionsForm($form, $form_state);
266
267
    switch ($form_state->get('section')) {
268
      case 'graphql_query_name':
269
        $form['#title'] .= $this->t('Query name');
270
        $form['graphql_query_name'] = [
271
          '#type' => 'textfield',
272
          '#description' => $this->t('This will be the graphQL query name.'),
273
          '#default_value' => $this->getGraphQLQueryName(),
274
        ];
275
        break;
276
277
      case 'entity_type':
278
        $entity_info = \Drupal::entityManager()->getDefinitions();
279
        $entity_names = [NULL => $this->t('None')];
280
        foreach ($entity_info as $type => $info) {
281
          // is this a content/front-facing entity?
282
          if ($info instanceof \Drupal\Core\Entity\ContentEntityType) {
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Entity\ContentEntityType does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
283
            $entity_names[$type] = $info->get('label');
284
          }
285
        }
286
287
        $form['#title'] .= $this->t('Entity type');
288
        $form['entity_type'] = [
289
          '#type' => 'radios',
290
          '#required' => FALSE,
291
          '#title' => $this->t('Attach this display to the following entity type'),
292
          '#options' => $entity_names,
293
          '#default_value' => $this->getOption('entity_type'),
294
        ];
295
        break;
296
297
      case 'bundles':
298
        $options = [];
299
        $entity_type = $this->getOption('entity_type');
300
        foreach (\Drupal::entityManager()->getBundleInfo($entity_type) as $bundle => $info) {
301
          $options[$bundle] = $info['label'];
302
        }
303
        $form['#title'] .= $this->t('Bundles');
304
        $form['bundles'] = [
305
          '#type' => 'checkboxes',
306
          '#title' => $this->t('Attach this display to the following bundles.  If no bundles are selected, the display will be attached to all.'),
307
          '#options' => $options,
308
          '#default_value' => $this->getOption('bundles'),
309
        ];
310
        break;
311
312 View Code Duplication
      case 'arguments':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
313
        $form['#title'] .= $this->t('Arguments');
314
        $default = $this->getOption('argument_mode');
315
        $options = [
316
          'None' => $this->t("No special handling"),
317
          'token' => $this->t("Use tokens from the entity the view is attached to"),
318
        ];
319
320
        $form['argument_mode'] = [
321
          '#type' => 'radios',
322
          '#title' => $this->t("How should this display populate the view's arguments?"),
323
          '#options' => $options,
324
          '#default_value' => $default,
325
        ];
326
327
        $form['token'] = [
328
          '#type' => 'fieldset',
329
          '#title' => $this->t('Token replacement'),
330
          '#collapsible' => TRUE,
331
          '#states' => [
332
            'visible' => [
333
              ':input[name=argument_mode]' => ['value' => 'token'],
334
            ],
335
          ],
336
        ];
337
338
        $form['token']['default_argument'] = [
339
          '#title' => $this->t('Arguments'),
340
          '#type' => 'textfield',
341
          '#maxlength' => 1024,
342
          '#default_value' => $this->getOption('default_argument'),
343
          '#description' => $this->t('You may use token replacement to provide arguments based on the current entity. Separate arguments with "/".'),
344
        ];
345
346
        // Add a token browser.
347
        if (\Drupal::service('module_handler')->moduleExists('token') && $entity_type = $this->getOption('entity_type')) {
348
          $token_types = [$entity_type => $entity_type];
349
          $token_mapper = \Drupal::service('token.entity_mapper');
350
          if (!empty($token_types)) {
351
            $token_types = array_map(function ($type) use ($token_mapper) {
352
              return $token_mapper->getTokenTypeForEntityType($type);
353
            }, (array) $token_types);
354
          }
355
          $form['token']['browser'] = [
356
            '#theme' => 'token_tree_link',
357
            '#token_types' => $token_types,
358
            '#recursion_limit' => 5,
359
            '#global_types' => TRUE,
360
            '#show_nested' => FALSE,
361
          ];
362
        }
363
        break;
364
365 View Code Duplication
      case 'limit':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
366
        $form['#title'] .= $this->t('Limit');
367
        $default = $this->getOption('limit_mode');
368
        $options = [
369
          'None' => $this->t("No special handling"),
370
          'token' => $this->t("Use tokens from the entity the view is attached to"),
371
        ];
372
373
        $form['limit_mode'] = [
374
          '#type' => 'radios',
375
          '#title' => $this->t("How should this display populate the view's result limit?"),
376
          '#options' => $options,
377
          '#default_value' => $default,
378
        ];
379
380
        $form['token'] = [
381
          '#type' => 'fieldset',
382
          '#title' => $this->t('Token replacement'),
383
          '#collapsible' => TRUE,
384
          '#states' => [
385
            'visible' => [
386
              ':input[name=limit_mode]' => ['value' => 'token'],
387
            ],
388
          ],
389
        ];
390
391
        $form['token']['default_limit'] = [
392
          '#title' => $this->t('Limit'),
393
          '#type' => 'textfield',
394
          '#maxlength' => 1024,
395
          '#default_value' => $this->getOption('default_limit'),
396
          '#description' => $this->t('You may use token replacement to provide the limit based on the current entity.'),
397
        ];
398
399
        // Add a token browser.
400
        if (\Drupal::service('module_handler')->moduleExists('token') && $entity_type = $this->getOption('entity_type')) {
401
          $token_types = [$entity_type => $entity_type];
402
          $token_mapper = \Drupal::service('token.entity_mapper');
403
          if (!empty($token_types)) {
404
            $token_types = array_map(function ($type) use ($token_mapper) {
405
              return $token_mapper->getTokenTypeForEntityType($type);
406
            }, (array) $token_types);
407
          }
408
          $form['token']['browser'] = [
409
            '#theme' => 'token_tree_link',
410
            '#token_types' => $token_types,
411
            '#recursion_limit' => 5,
412
            '#global_types' => TRUE,
413
            '#show_nested' => FALSE,
414
          ];
415
        }
416
        break;
417
    }
418
  }
419
420
  /**
421
   * {@inheritdoc}
422
   */
423
  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
424
    parent::submitOptionsForm($form, $form_state);
425
    $section = $form_state->get('section');
426
    switch ($section) {
427
      case 'graphql_query_name':
428
        $this->setOption($section, $form_state->getValue($section));
429
        break;
430
      case 'entity_type':
431
        $new_entity = $form_state->getValue('entity_type');
432
        $old_entity = $this->getOption('entity_type');
433
        $this->setOption('entity_type', $new_entity);
434
435
        if ($new_entity != $old_entity) {
436
          // Each entity has its own list of bundles and view modes. If there's
437
          // only one on the new type, we can select it automatically. Otherwise
438
          // we need to wipe the options and start over.
439
          $new_entity_info = \Drupal::entityManager()->getDefinition($new_entity);
0 ignored issues
show
Unused Code introduced by
$new_entity_info is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
440
          $new_bundles_keys = \Drupal::entityManager()->getBundleInfo($new_entity);
441
          $new_bundles = array();
442
          if (count($new_bundles_keys) == 1) {
443
            $new_bundles[] = $new_bundles_keys[0];
444
          }
445
          $this->setOption('bundles', $new_bundles);
446
        }
447
        break;
448
      case 'bundles':
449
        $this->setOption('bundles', array_values(array_filter($form_state->getValue('bundles'))));
450
        break;
451
      case 'arguments':
452
        $this->setOption('argument_mode', $form_state->getValue('argument_mode'));
453
        if ($form_state->getValue('argument_mode') == 'token') {
454
          $this->setOption('default_argument', $form_state->getValue('default_argument'));
455
        }
456
        else {
457
          $this->setOption('default_argument', NULL);
458
        }
459
        break;
460
      case 'limit':
461
        $this->setOption('limit_mode', $form_state->getValue('limit_mode'));
462
        if ($form_state->getValue('limit_mode') == 'token') {
463
          $this->setOption('default_limit', $form_state->getValue('default_limit'));
464
        }
465
        else {
466
          $this->setOption('default_limit', NULL);
467
        }
468
        break;
469
    }
470
  }
471
472
  /**
473
   * {@inheritdoc}
474
   */
475
  public function execute() {
476
    return $this->view->execute();
477
  }
478
479
  /**
480
   * {@inheritdoc}
481
   */
482
  public function render() {
483
    $rows = (!empty($this->view->result) || $this->view->style_plugin->evenEmpty()) ? $this->view->style_plugin->render($this->view->result) : [];
484
485
    // Apply the cache metadata from the display plugin. This comes back as a
486
    // cache render array so we have to transform it back afterwards.
487
    $this->applyDisplayCacheabilityMetadata($this->view->element);
488
489
    return [
490
      'view' => $this->view,
491
      'rows' => $rows,
492
      'cache' => CacheableMetadata::createFromRenderArray($this->view->element),
493
    ];
494
  }
495
}
496