SchemaPluginBase::processFields()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 8
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Drupal\graphql\Plugin\GraphQL\Schemas;
4
5
use Drupal\Component\Plugin\PluginBase;
0 ignored issues
show
Bug introduced by
The type Drupal\Component\Plugin\PluginBase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Drupal\Core\Cache\CacheableDependencyInterface;
0 ignored issues
show
Bug introduced by
The type Drupal\Core\Cache\CacheableDependencyInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Drupal\Core\Language\LanguageManagerInterface;
0 ignored issues
show
Bug introduced by
The type Drupal\Core\Language\LanguageManagerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
0 ignored issues
show
Bug introduced by
The type Drupal\Core\Plugin\ContainerFactoryPluginInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Drupal\Core\Session\AccountProxyInterface;
0 ignored issues
show
Bug introduced by
The type Drupal\Core\Session\AccountProxyInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Drupal\graphql\GraphQL\Execution\ResolveContext;
11
use Drupal\graphql\GraphQL\QueryProvider\QueryProviderInterface;
12
use Drupal\graphql\Plugin\FieldPluginManager;
13
use Drupal\graphql\Plugin\MutationPluginManager;
14
use Drupal\graphql\Plugin\SchemaBuilderInterface;
15
use Drupal\graphql\Plugin\SchemaPluginInterface;
16
use Drupal\graphql\Plugin\SubscriptionPluginManager;
17
use Drupal\graphql\Plugin\TypePluginManagerAggregator;
18
use GraphQL\Error\DebugFlag;
19
use GraphQL\Language\AST\DocumentNode;
20
use GraphQL\Server\OperationParams;
21
use GraphQL\Server\ServerConfig;
22
use GraphQL\Type\Definition\ObjectType;
23
use GraphQL\Type\Definition\ResolveInfo;
24
use GraphQL\Type\Schema;
25
use GraphQL\Type\SchemaConfig;
26
use GraphQL\Validator\DocumentValidator;
27
use Psr\Log\LoggerInterface;
0 ignored issues
show
Bug introduced by
The type Psr\Log\LoggerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Symfony\Component\DependencyInjection\ContainerInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...tion\ContainerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
30
abstract class SchemaPluginBase extends PluginBase implements SchemaPluginInterface, SchemaBuilderInterface, ContainerFactoryPluginInterface, CacheableDependencyInterface {
31
32
  /**
33
   * The field plugin manager.
34
   *
35
   * @var \Drupal\graphql\Plugin\FieldPluginManager
36
   */
37
  protected $fieldManager;
38
39
  /**
40
   * The mutation plugin manager.
41
   *
42
   * @var \Drupal\graphql\Plugin\MutationPluginManager
43
   */
44
  protected $mutationManager;
45
46
  /**
47
   * The subscription plugin manager.
48
   *
49
   * @var \Drupal\graphql\Plugin\SubscriptionPluginManager
50
   */
51
  protected $subscriptionManager;
52
53
  /**
54
   * The type manager aggregator service.
55
   *
56
   * @var \Drupal\graphql\Plugin\TypePluginManagerAggregator
57
   */
58
  protected $typeManagers;
59
60
  /**
61
   * Static cache of field definitions.
62
   *
63
   * @var array
64
   */
65
  protected $fields = [];
66
67
  /**
68
   * Static cache of mutation definitions.
69
   *
70
   * @var array
71
   */
72
  protected $mutations = [];
73
74
  /**
75
   * Static cache of subscription definitions.
76
   *
77
   * @var array
78
   */
79
  protected $subscriptions = [];
80
81
  /**
82
   * Static cache of type instances.
83
   *
84
   * @var array
85
   */
86
  protected $types = [];
87
88
  /**
89
   * The service parameters.
90
   *
91
   * @var array
92
   */
93
  protected $parameters;
94
95
  /**
96
   * The query provider service.
97
   *
98
   * @var \Drupal\graphql\GraphQL\QueryProvider\QueryProviderInterface
99
   */
100
  protected $queryProvider;
101
102
  /**
103
   * The current user.
104
   *
105
   * @var \Drupal\Core\Session\AccountProxyInterface
106
   */
107
  protected $currentUser;
108
109
  /**
110
   * The logger service.
111
   *
112
   * @var \Psr\Log\LoggerInterface
113
   */
114
  protected $logger;
115
116
  /**
117
   * @var \Drupal\Core\Language\LanguageManagerInterface
118
   */
119
  protected $languageManager;
120
121
  /**
122
   * {@inheritdoc}
123
   */
124
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
125
    return new static(
126
      $configuration,
127
      $plugin_id,
128
      $plugin_definition,
129
      $container->get('plugin.manager.graphql.field'),
130
      $container->get('plugin.manager.graphql.mutation'),
131
      $container->get('plugin.manager.graphql.subscription'),
132
      $container->get('graphql.type_manager_aggregator'),
133
      $container->get('graphql.query_provider'),
134
      $container->get('current_user'),
135
      $container->get('logger.channel.graphql'),
136
      $container->get('language_manager'),
137
      $container->getParameter('graphql.config')
138
    );
139
  }
140
141
  /**
142
   * SchemaPluginBase constructor.
143
   *
144
   * @param array $configuration
145
   *   The plugin configuration array.
146
   * @param string $pluginId
147
   *   The plugin id.
148
   * @param array $pluginDefinition
149
   *   The plugin definition array.
150
   * @param \Drupal\graphql\Plugin\FieldPluginManager $fieldManager
151
   *   The field plugin manager.
152
   * @param \Drupal\graphql\Plugin\MutationPluginManager $mutationManager
153
   *   The mutation plugin manager.
154
   * @param \Drupal\graphql\Plugin\SubscriptionPluginManager $subscriptionManager
155
   *   The subscription plugin manager.
156
   * @param \Drupal\graphql\Plugin\TypePluginManagerAggregator $typeManagers
157
   *   The type manager aggregator service.
158
   * @param \Drupal\graphql\GraphQL\QueryProvider\QueryProviderInterface $queryProvider
159
   *   The query provider service.
160
   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
161
   *   The current user.
162
   * @param \Psr\Log\LoggerInterface $logger
163
   *   The logger service.
164
   * @param \Drupal\Core\Language\LanguageManagerInterface $languageManager
165
   *   The language manager service.
166
   * @param array $parameters
167
   *   The service parameters.
168
   */
169
  public function __construct(
170
    $configuration,
171
    $pluginId,
172
    $pluginDefinition,
173
    FieldPluginManager $fieldManager,
174
    MutationPluginManager $mutationManager,
175
    SubscriptionPluginManager $subscriptionManager,
176
    TypePluginManagerAggregator $typeManagers,
177
    QueryProviderInterface $queryProvider,
178
    AccountProxyInterface $currentUser,
179
    LoggerInterface $logger,
180
    LanguageManagerInterface $languageManager,
181
    array $parameters
182
  ) {
183
    parent::__construct($configuration, $pluginId, $pluginDefinition);
184
    $this->fieldManager = $fieldManager;
185
    $this->mutationManager = $mutationManager;
186
    $this->subscriptionManager = $subscriptionManager;
187
    $this->typeManagers = $typeManagers;
188
    $this->queryProvider = $queryProvider;
189
    $this->currentUser = $currentUser;
190
    $this->parameters = $parameters;
191
    $this->logger = $logger;
192
    $this->languageManager = $languageManager;
193
  }
194
195
  /**
196
   * {@inheritdoc}
197
   */
198
  public function getSchema() {
199
    $config = new SchemaConfig();
200
201
    if ($this->hasMutations()) {
202
      $config->setMutation(new ObjectType([
203
        'name' => 'Mutation',
204
        'fields' => function () {
205
          return $this->getMutations();
206
        },
207
      ]));
208
    }
209
210
    if ($this->hasSubscriptions()) {
211
      $config->setSubscription(new ObjectType([
212
        'name' => 'Subscription',
213
        'fields' => function () {
214
          return $this->getSubscriptions();
215
        },
216
      ]));
217
    }
218
219
    $config->setQuery(new ObjectType([
220
      'name' => 'Query',
221
      'fields' => function () {
222
        return $this->getFields('Root');
223
      },
224
    ]));
225
226
    $config->setTypes(function () {
227
      return $this->getTypes();
228
    });
229
230
    $config->setTypeLoader(function ($name) {
231
      return $this->getType($name);
232
    });
233
234
    return new Schema($config);
235
  }
236
237
  /**
238
   * {@inheritdoc}
239
   */
240
  public function validateSchema() {
241
    return NULL;
242
  }
243
244
  /**
245
   * {@inheritdoc}
246
   */
247
  public function getServer() {
248
    // If the current user has appropriate permissions, allow to bypass
249
    // the secure fields restriction.
250
    $globals['bypass field security'] = $this->currentUser->hasPermission('bypass graphql field security');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$globals was never initialized. Although not strictly required by PHP, it is generally a good practice to add $globals = array(); before regardless.
Loading history...
251
252
    // Create the server config.
253
    $config = ServerConfig::create();
254
255
    // Each document (e.g. in a batch query) gets its own resolve context. This
256
    // allows us to collect the cache metadata and contextual values (e.g.
257
    // inheritance for language) for each query separately.
258
    $config->setContext(function ($params, $document, $operation) use ($globals) {
0 ignored issues
show
Unused Code introduced by
The parameter $document is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

258
    $config->setContext(function ($params, /** @scrutinizer ignore-unused */ $document, $operation) use ($globals) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operation is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

258
    $config->setContext(function ($params, $document, /** @scrutinizer ignore-unused */ $operation) use ($globals) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

258
    $config->setContext(function (/** @scrutinizer ignore-unused */ $params, $document, $operation) use ($globals) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
259
      // Each document (e.g. in a batch query) gets its own resolve context. This
260
      // allows us to collect the cache metadata and contextual values (e.g.
261
      // inheritance for language) for each query separately.
262
      $context = new ResolveContext($globals, [
263
        'language' => $this->languageManager->getCurrentLanguage()->getId(),
264
      ]);
265
266
      $context->addCacheTags(['graphql']);
267
268
      // Always add the language_url cache context.
269
      $context->addCacheContexts([
270
        'languages:language_url',
271
        'languages:language_interface',
272
        'languages:language_content',
273
        'user.permissions',
274
      ]);
275
276
      return $context;
277
    });
278
279
    $config->setValidationRules(function (OperationParams $params, DocumentNode $document, $operation) {
0 ignored issues
show
Unused Code introduced by
The parameter $operation is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

279
    $config->setValidationRules(function (OperationParams $params, DocumentNode $document, /** @scrutinizer ignore-unused */ $operation) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $document is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

279
    $config->setValidationRules(function (OperationParams $params, /** @scrutinizer ignore-unused */ DocumentNode $document, $operation) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
280
      if (isset($params->queryId) && empty($params->getOriginalInput('query'))) {
281
        // Assume that pre-parsed documents are already validated. This allows
282
        // us to store pre-validated query documents e.g. for persisted queries
283
        // effectively improving performance by skipping run-time validation.
284
        return [];
285
      }
286
287
      return array_values(DocumentValidator::defaultRules());
288
    });
289
290
    $config->setPersistentQueryLoader([$this->queryProvider, 'getQuery']);
291
    $config->setQueryBatching(TRUE);
292
    $config->setDebugFlag($this->parameters['development'] ? DebugFlag::INCLUDE_DEBUG_MESSAGE : DebugFlag::NONE);
293
    $config->setSchema($this->getSchema());
294
295
    // Always log the errors.
296
    $config->setErrorsHandler(function (array $errors, callable $formatter) {
297
      /** @var \GraphQL\Error\Error $error */
298
      foreach ($errors as $error) {
299
        $this->logger->error($error->getMessage());
300
      }
301
302
      return array_map($formatter, $errors);
303
    });
304
305
    return $config;
306
  }
307
308
  /**
309
   * {@inheritdoc}
310
   */
311
  public function hasFields($type) {
312
    return isset($this->pluginDefinition['field_association_map'][$type]);
313
  }
314
315
  /**
316
   * {@inheritdoc}
317
   */
318
  public function hasMutations() {
319
    return !empty($this->pluginDefinition['mutation_map']);
320
  }
321
322
  /**
323
   * {@inheritdoc}
324
   */
325
  public function hasSubscriptions() {
326
    return !empty($this->pluginDefinition['subscription_map']);
327
  }
328
329
  /**
330
   * {@inheritdoc}
331
   */
332
  public function hasType($name) {
333
    return isset($this->pluginDefinition['type_map'][$name]);
334
  }
335
336
  /**
337
   * {@inheritdoc}
338
   */
339
  public function getFields($type) {
340
    $association = $this->pluginDefinition['field_association_map'];
341
    $fields = $this->pluginDefinition['field_map'];
342
343
    if (isset($association[$type])) {
344
      return $this->processFields(array_map(function ($id) use ($fields) {
345
        return $fields[$id];
346
      }, $association[$type]));
347
    }
348
349
    return [];
350
  }
351
352
  /**
353
   * {@inheritdoc}
354
   */
355
  public function getMutations() {
356
    return $this->processMutations($this->pluginDefinition['mutation_map']);
357
  }
358
359
  /**
360
   * {@inheritdoc}
361
   */
362
  public function getSubscriptions() {
363
    return $this->processSubscriptions($this->pluginDefinition['subscription_map']);
364
  }
365
366
  /**
367
   * {@inheritdoc}
368
   */
369
  public function getTypes() {
370
    return array_map(function ($name) {
371
      return $this->getType($name);
372
    }, array_keys($this->pluginDefinition['type_map']));
373
  }
374
375
  /**
376
   * {@inheritdoc}
377
   */
378
  public function getSubTypes($name) {
379
    $association = $this->pluginDefinition['type_association_map'];
380
    return $association[$name] ?? [];
381
  }
382
383
  /**
384
   * {@inheritdoc}
385
   */
386
  public function resolveType($name, $value, ResolveContext $context, ResolveInfo $info) {
387
    $association = $this->pluginDefinition['type_association_map'];
388
    $types = $this->pluginDefinition['type_map'];
389
    if (!isset($association[$name])) {
390
      return NULL;
391
    }
392
393
    foreach ($association[$name] as $type) {
394
      // @todo Try to avoid loading the type for the check. Consider to make it static!
395
      if (isset($types[$type]) && $instance = $this->buildType($types[$type])) {
396
        if ($instance->isTypeOf($value, $context, $info)) {
0 ignored issues
show
Bug introduced by
The method isTypeOf() does not exist on GraphQL\Type\Definition\Type. It seems like you code against a sub-type of GraphQL\Type\Definition\Type such as GraphQL\Type\Definition\ObjectType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

396
        if ($instance->/** @scrutinizer ignore-call */ isTypeOf($value, $context, $info)) {
Loading history...
397
          return $instance;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $instance returns the type GraphQL\Type\Definition\Type which is incompatible with the return type mandated by Drupal\graphql\Plugin\Sc...nterface::resolveType() of Drupal\graphql\Plugin\Gr...pes\TypePluginBase|null.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
398
        }
399
      }
400
    }
401
402
    return NULL;
403
  }
404
405
  /**
406
   * {@inheritdoc}
407
   */
408
  public function getType($name) {
409
    $types = $this->pluginDefinition['type_map'];
410
    $references = $this->pluginDefinition['type_reference_map'];
411
    if (isset($types[$name])) {
412
      return $this->buildType($this->pluginDefinition['type_map'][$name]);
413
    }
414
415
    do {
416
      if (isset($references[$name])) {
417
        return $this->buildType($types[$references[$name]]);
418
      }
419
    } while (($pos = strpos($name, ':')) !== FALSE && $name = substr($name, 0, $pos));
420
421
    throw new \LogicException(sprintf('Missing type %s.', $name));
422
  }
423
424
  /**
425
   * {@inheritdoc}
426
   */
427
  public function processMutations(array $mutations) {
428
    return array_map([$this, 'buildMutation'], $mutations);
429
  }
430
431
  /**
432
   * {@inheritdoc}
433
   */
434
  public function processSubscriptions(array $subscriptions) {
435
    return array_map([$this, 'buildSubscription'], $subscriptions);
436
  }
437
438
  /**
439
   * {@inheritdoc}
440
   */
441
  public function processFields(array $fields) {
442
    $processFields = array_map([$this, 'buildField'], $fields);
443
    foreach ($processFields as $key => $processField) {
444
      if ($processField === FALSE) {
445
        unset($processFields[$key]);
446
      }
447
    }
448
    return $processFields;
449
  }
450
451
  /**
452
   * {@inheritdoc}
453
   */
454
  public function processArguments(array $args) {
455
    return array_filter(array_map(function ($arg) {
456
      try {
457
        $type = $this->processType($arg['type']);
458
      }
459
      catch (\Exception $e) {
460
        // Allow optional arguments that are removed if the input type is
461
        // not defined.
462
        if (empty($arg['optional'])) {
463
          throw $e;
464
        }
465
466
        return NULL;
467
      }
468
469
      return [
470
        'type' => $type,
471
      ] + $arg;
472
    }, $args));
473
  }
474
475
  /**
476
   * {@inheritdoc}
477
   */
478
  public function processType(array $type) {
479
    [$type, $decorators] = $type;
480
481
    return array_reduce($decorators, function ($type, $decorator) {
482
      return $decorator($type);
483
    }, $this->getType($type));
484
  }
485
486
  /**
487
   * Retrieves the type instance for the given reference.
488
   *
489
   * @param array $type
490
   *   The type reference.
491
   *
492
   * @return \GraphQL\Type\Definition\Type
493
   *   The type instance.
494
   */
495
  protected function buildType($type) {
496
    if (!isset($this->types[$type['id']])) {
497
      $creator = [$type['class'], 'createInstance'];
498
      $manager = $this->typeManagers->getTypeManager($type['type']);
499
      $this->types[$type['id']] = $creator($this, $manager, $type['definition'], $type['id']);
500
    }
501
502
    return $this->types[$type['id']];
503
  }
504
505
  /**
506
   * Retrieves the field definition for a given field reference.
507
   *
508
   * @param array $field
509
   *   The type reference.
510
   *
511
   * @return array|bool
512
   *   The field definition.
513
   */
514
  protected function buildField($field) {
515
    $exceptions = [
516
      'layout_section',
517
      'shipment_item'
518
    ];
519
    if (in_array($field['definition']['type'][0], $exceptions, TRUE)) {
520
      return FALSE;
521
    }
522
523
    if (!isset($this->fields[$field['id']])) {
524
      $creator = [$field['class'], 'createInstance'];
525
      $this->fields[$field['id']] = $creator($this, $this->fieldManager, $field['definition'], $field['id']);
526
    }
527
528
    return $this->fields[$field['id']];
529
  }
530
531
  /**
532
   * Retrieves the mutation definition for a given field reference.
533
   *
534
   * @param array $mutation
535
   *   The mutation reference.
536
   *
537
   * @return array
538
   *   The mutation definition.
539
   */
540
  protected function buildMutation($mutation) {
541
    if (!isset($this->mutations[$mutation['id']])) {
542
      $creator = [$mutation['class'], 'createInstance'];
543
      $this->mutations[$mutation['id']] = $creator($this, $this->mutationManager, $mutation['definition'], $mutation['id']);
544
    }
545
546
    return $this->mutations[$mutation['id']];
547
  }
548
549
  /**
550
   * Retrieves the subscription definition for a given field reference.
551
   *
552
   * @param array $mutation
553
   *   The subscription reference.
554
   *
555
   * @return array
556
   *   The subscription definition.
557
   */
558
  protected function buildSubscription($subscription) {
559
    if (!isset($this->subscriptions[$subscription['id']])) {
560
      $creator = [$subscription['class'], 'createInstance'];
561
      $this->subscriptions[$subscription['id']] = $creator($this, $this->subscriptionManager, $subscription['definition'], $subscription['id']);
562
    }
563
564
    return $this->subscriptions[$subscription['id']];
565
  }
566
567
  /**
568
   * {@inheritdoc}
569
   */
570
  public function getCacheContexts() {
571
    return [];
572
  }
573
574
  /**
575
   * {@inheritdoc}
576
   */
577
  public function getCacheTags() {
578
    return $this->pluginDefinition['schema_cache_tags'];
579
  }
580
581
  /**
582
   * {@inheritdoc}
583
   */
584
  public function getCacheMaxAge() {
585
    return $this->pluginDefinition['schema_cache_max_age'];
586
  }
587
588
}
589