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

View::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
3
namespace Drupal\graphql_views\Plugin\GraphQL\Fields;
4
5
use Drupal\Component\Utility\Html;
6
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
7
use Drupal\Core\Entity\EntityInterface;
8
use Drupal\Core\Entity\EntityTypeManagerInterface;
9
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
10
use Drupal\graphql\GraphQL\Execution\ResolveContext;
11
use Drupal\graphql\Plugin\GraphQL\Fields\FieldPluginBase;
12
use GraphQL\Type\Definition\ResolveInfo;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
15
/**
16
 * Expose views as root fields.
17
 *
18
 * @GraphQLField(
19
 *   id = "view",
20
 *   secure = true,
21
 *   parents = {"Root"},
22
 *   provider = "views",
23
 *   deriver = "Drupal\graphql_views\Plugin\Deriver\Fields\ViewDeriver"
24
 * )
25
 */
26
class View extends FieldPluginBase implements ContainerFactoryPluginInterface {
27
  use DependencySerializationTrait;
28
29
  /**
30
   * The entity type manager.
31
   *
32
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
33
   */
34
  protected $entityTypeManager;
35
36
  /**
37
   * {@inheritdoc}
38
   */
39
  public function __construct(
40
    array $configuration,
41
    $pluginId,
42
    $pluginDefinition,
43
    EntityTypeManagerInterface $entityTypeManager
44
  ) {
45
    $this->entityTypeManager = $entityTypeManager;
46
    parent::__construct($configuration, $pluginId, $pluginDefinition);
47
  }
48
49
  /**
50
   * {@inheritdoc}
51
   */
52
  public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
53
    return new static(
54
      $configuration,
55
      $pluginId,
56
      $pluginDefinition,
57
      $container->get('entity_type.manager')
58
    );
59
  }
60
61
  /**
62
   * {@inheritdoc}
63
   */
64
  public function resolveValues($value, array $args, ResolveContext $context, ResolveInfo $info) {
65
    $storage = $this->entityTypeManager->getStorage('view');
66
    $definition = $this->getPluginDefinition();
67
68
    /** @var \Drupal\views\Entity\View $view */
69
    if ($view = $storage->load($definition['view'])) {
70
      $executable = $view->getExecutable();
71
      $executable->setDisplay($definition['display']);
72
73
      // Set view contextual filters.
74
      /* @see \Drupal\graphql_views\ViewDeriverHelperTrait::getArgumentsInfo() */
75
      if (!empty($definition['arguments_info'])) {
76
        $arguments = $this->extractContextualFilters($value, $args, $executable);
77
        $executable->setArguments($arguments);
78
      }
79
      // See if we can fetch the pageSize from the context.
80
      $limit_mode = $executable->getDisplay()->getOption('limit_mode');
81
      if ($limit_mode == 'token') {
82
        if (($token_string = $executable->getDisplay()->getOption('default_limit')) && ($entity_type = $executable->getDisplay()->getOption('entity_type'))) {
83
          $token_handler = \Drupal::service('graphql_views.token_handler');
84
          // Now do the token replacement.
85
          if (($pageSizeValue = current($token_handler->getArgumentsFromTokenString($token_string, $entity_type, $value))) && is_numeric($pageSizeValue)) {
86
              $executable->setItemsPerPage((int) $pageSizeValue);
87
          }
88
        }
89
      }
90
      $filters = $executable->getDisplay()->getOption('filters');;
91
      $input = $this->extractExposedInput($value, $args, $filters);
92
      $executable->setExposedInput($input);
93
94
      // This is a workaround for the Taxonomy Term filter which requires a full
95
      // exposed form to be sent OR the display being an attachment to just
96
      // accept input values.
97
      $executable->is_attachment = TRUE;
98
      $executable->exposed_raw_input = $input;
99
100
      if (!empty($definition['paged'])) {
101
        // Set paging parameters.
102
        $executable->setItemsPerPage($args['pageSize']);
103
        $executable->setCurrentPage($args['page']);
104
      }
105
106
      if (isset($args['offset']) && !empty($args['offset'])) {
107
        $executable->setOffset($args['offset']);
108
      }
109
110
      $result = $executable->render($definition['display']);
111
      /** @var \Drupal\Core\Cache\CacheableMetadata $cache */
112
      if ($cache = $result['cache']) {
113
        $cache->setCacheContexts(
114
          array_filter($cache->getCacheContexts(), function ($context) {
115
            // Don't emit the url cache contexts.
116
            return $context !== 'url' && strpos($context, 'url.') !== 0;
117
          })
118
        );
119
      }
120
      yield $result;
121
    }
122
  }
123
124
  /**
125
   * {@inheritdoc}
126
   */
127
  protected function getCacheDependencies(array $result, $value, array $args, ResolveContext $context, ResolveInfo $info) {
128
    return array_map(function ($item) {
129
      return $item['cache'];
130
    }, $result);
131
  }
132
133
  /**
134
   * Retrieves the contextual filter argument from the parent value or args.
135
   *
136
   * @param $value
137
   *   The resolved parent value.
138
   * @param $args
139
   *   The arguments provided to the field.
140
   * @param \Drupal\views\ViewExecutable $executable
141
   *   The view to execute.
142
   *
143
   * @return array
144
   *   An array of arguments containing the contextual filter value from the
145
   *   parent or provided args if any.
146
   */
147
  protected function extractContextualFilters($value, $args, $executable) {
148
    $definition = $this->getPluginDefinition();
149
    $arguments = [];
150
151
    // See if we can fetch the default arguments using the context.
152
    $arg_mode = $executable->getDisplay()->getOption('argument_mode');
153
154
    if ($arg_mode == 'token') {
155
      if (($token_string = $executable->getDisplay()->getOption('default_argument')) && ($entity_type = $executable->getDisplay()->getOption('entity_type'))) {
156
        $token_handler = \Drupal::service('graphql_views.token_handler');
157
        // Now do the token replacement.
158
        $token_values = $token_handler->getArgumentsFromTokenString($token_string, $entity_type, $value);
159
        $new_args = [];
160
        // We have to be careful to only replace arguments that have
161
        // tokens.
162
        foreach ($token_values as $key => $value) {
163
          $new_args[Html::escape($key)] = Html::escape($value);
164
        }
165
166
        //$view->args = $new_args;
167
        $arguments = $new_args;
168
      }
169
    }
170
171
    foreach ($definition['arguments_info'] as $argumentId => $argumentInfo) {
172
      if (isset($args['contextualFilter'][$argumentId])) {
173
        $arguments[$argumentInfo['index']] = $args['contextualFilter'][$argumentId];
174
      }
175
      elseif (
176
        $value instanceof EntityInterface &&
0 ignored issues
show
Bug introduced by
The class Drupal\Core\Entity\EntityInterface 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...
177
        $value->getEntityTypeId() === $argumentInfo['entity_type'] &&
178
        (empty($argumentInfo['bundles']) ||
179
          in_array($value->bundle(), $argumentInfo['bundles'], TRUE))
180
      ) {
181
        $arguments[$argumentInfo['index']] = $value->id();
182
      }
183
      elseif (!isset($arguments[$argumentInfo['index']])) {
184
        $arguments[$argumentInfo['index']] = NULL;
185
      }
186
    }
187
188
    return $arguments;
189
  }
190
191
  /**
192
   * Retrieves sort and filter arguments from the provided field args.
193
   *
194
   * @param $value
195
   *   The resolved parent value.
196
   * @param $args
197
   *   The array of arguments provided to the field.
198
   * @param $filters
199
   *   The available filters for the configured view.
200
   *
201
   * @return array
202
   *   The array of sort and filter arguments to execute the view with.
203
   */
204
  protected function extractExposedInput($value, $args, $filters) {
205
    // Prepare arguments for use as exposed form input.
206
    $input = array_filter([
207
      // Sorting arguments.
208
      'sort_by' => isset($args['sortBy']) ? $args['sortBy'] : NULL,
209
      'sort_order' => isset($args['sortDirection']) ? $args['sortDirection'] : NULL,
210
    ]);
211
212
    // If some filters are missing from the input, set them to an empty string
213
    // explicitly. Otherwise views module generates "Undefined index" notice.
214
    foreach ($filters as $filterKey => $filterRow) {
215
      if (!isset($filterRow['expose']['identifier'])) {
216
        continue;
217
      }
218
219
      $inputKey = $filterRow['expose']['identifier'];
220
      if (!isset($args['filter'][$inputKey])) {
221
        $input[$inputKey] = $filterRow['value'];
222
      } else {
223
        $input[$inputKey] = $args['filter'][$inputKey];
224
      }
225
    }
226
227
    return $input;
228
  }
229
230
}
231