Context::setConfigOfSorters()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Oro\Bundle\ApiBundle\Processor;
4
5
use Oro\Component\ChainProcessor\ParameterBag;
6
use Oro\Component\ChainProcessor\ParameterBagInterface;
7
use Oro\Bundle\ApiBundle\Collection\CaseInsensitiveParameterBag;
8
use Oro\Bundle\ApiBundle\Collection\Criteria;
9
use Oro\Bundle\ApiBundle\Config\ConfigExtraInterface;
10
use Oro\Bundle\ApiBundle\Config\ConfigExtraSectionInterface;
11
use Oro\Bundle\ApiBundle\Config\EntityDefinitionConfig;
12
use Oro\Bundle\ApiBundle\Config\FiltersConfig;
13
use Oro\Bundle\ApiBundle\Config\FiltersConfigExtra;
14
use Oro\Bundle\ApiBundle\Config\SortersConfig;
15
use Oro\Bundle\ApiBundle\Config\SortersConfigExtra;
16
use Oro\Bundle\ApiBundle\Filter\FilterCollection;
17
use Oro\Bundle\ApiBundle\Filter\FilterValueAccessorInterface;
18
use Oro\Bundle\ApiBundle\Filter\NullFilterValueAccessor;
19
use Oro\Bundle\ApiBundle\Metadata\EntityMetadata;
20
use Oro\Bundle\ApiBundle\Metadata\MetadataExtraInterface;
21
use Oro\Bundle\ApiBundle\Model\Error;
22
use Oro\Bundle\ApiBundle\Provider\ConfigProvider;
23
use Oro\Bundle\ApiBundle\Provider\MetadataProvider;
24
use Oro\Bundle\ApiBundle\Util\ConfigUtil;
25
26
/**
27
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
28
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
29
 */
30
class Context extends ApiContext
31
{
32
    /** FQCN of an entity */
33
    const CLASS_NAME = 'class';
34
35
    /** a prefix for all configuration sections */
36
    const CONFIG_PREFIX = 'config_';
37
38
    /** a list of requests for configuration data */
39
    const CONFIG_EXTRAS = 'configExtras';
40
41
    /** metadata of an entity */
42
    const METADATA = 'metadata';
43
44
    /** a list of requests for additional metadata info */
45
    const METADATA_EXTRAS = 'metadataExtras';
46
47
    /** a query is used to get result data */
48
    const QUERY = 'query';
49
50
    /** the Criteria object is used to add additional restrictions to a query is used to get result data */
51
    const CRITERIA = 'criteria';
52
53
    /** the response status code */
54
    const RESPONSE_STATUS_CODE = 'responseStatusCode';
55
56
    /**
57
     * this header can be used to request additional data like "total count"
58
     * that will be returned in a response headers
59
     */
60
    const INCLUDE_HEADER = 'X-Include';
61
62
    /** a list of filters is used to add additional restrictions to a query is used to get result data */
63
    const FILTERS = 'filters';
64
65
    /** @var FilterValueAccessorInterface */
66
    private $filterValues;
67
68
    /** @var Error[] */
69
    private $errors;
70
71
    /** @var ConfigProvider */
72
    protected $configProvider;
73
74
    /** @var MetadataProvider */
75
    protected $metadataProvider;
76
77
    /** @var ParameterBagInterface */
78
    private $requestHeaders;
79
80
    /** @var ParameterBagInterface */
81
    private $responseHeaders;
82
83
    /**
84
     * @param ConfigProvider   $configProvider
85
     * @param MetadataProvider $metadataProvider
86
     */
87
    public function __construct(ConfigProvider $configProvider, MetadataProvider $metadataProvider)
88
    {
89
        parent::__construct();
90
        $this->configProvider   = $configProvider;
91
        $this->metadataProvider = $metadataProvider;
92
    }
93
94
    /**
95
     * Checks whether a configuration of filters for an entity exists.
96
     *
97
     * @return bool
98
     */
99
    public function hasConfigOfFilters()
100
    {
101
        return $this->hasConfigOf(FiltersConfigExtra::NAME);
102
    }
103
104
    /**
105
     * Gets a configuration of filters for an entity.
106
     *
107
     * @return FiltersConfig|null
108
     */
109
    public function getConfigOfFilters()
110
    {
111
        return $this->getConfigOf(FiltersConfigExtra::NAME);
112
    }
113
114
    /**
115
     * Sets a configuration of filters for an entity.
116
     *
117
     * @param FiltersConfig|null $config
118
     */
119
    public function setConfigOfFilters(FiltersConfig $config = null)
120
    {
121
        $this->setConfigOf(FiltersConfigExtra::NAME, $config);
122
    }
123
124
    /**
125
     * Checks whether a configuration of sorters for an entity exists.
126
     *
127
     * @return bool
128
     */
129
    public function hasConfigOfSorters()
130
    {
131
        return $this->hasConfigOf(SortersConfigExtra::NAME);
132
    }
133
134
    /**
135
     * Gets a configuration of sorters for an entity.
136
     *
137
     * @return SortersConfig|null
138
     */
139
    public function getConfigOfSorters()
140
    {
141
        return $this->getConfigOf(SortersConfigExtra::NAME);
142
    }
143
144
    /**
145
     * Sets a configuration of sorters for an entity.
146
     *
147
     * @param SortersConfig|null $config
148
     */
149
    public function setConfigOfSorters(SortersConfig $config = null)
150
    {
151
        $this->setConfigOf(SortersConfigExtra::NAME, $config);
152
    }
153
154
    /**
155
     * Gets a list of filters is used to add additional restrictions to a query is used to get result data.
156
     *
157
     * @return FilterCollection
158
     */
159
    public function getFilters()
160
    {
161
        if (!$this->has(self::FILTERS)) {
162
            $this->set(self::FILTERS, new FilterCollection());
163
        }
164
165
        return $this->get(self::FILTERS);
166
    }
167
168
    /**
169
     * Gets a collection of the FilterValue objects that contains all incoming filters.
170
     *
171
     * @return FilterValueAccessorInterface
172
     */
173
    public function getFilterValues()
174
    {
175
        if (null === $this->filterValues) {
176
            $this->filterValues = new NullFilterValueAccessor();
177
        }
178
179
        return $this->filterValues;
180
    }
181
182
    /**
183
     * Sets an object that will be used to accessing incoming filters.
184
     *
185
     * @param FilterValueAccessorInterface $accessor
186
     */
187
    public function setFilterValues(FilterValueAccessorInterface $accessor)
188
    {
189
        $this->filterValues = $accessor;
190
    }
191
192
    /**
193
     * Gets a key of a main section of an entity configuration.
194
     *
195
     * @return string
196
     */
197
    protected function getConfigKey()
198
    {
199
        return self::CONFIG_PREFIX . ConfigUtil::DEFINITION;
200
    }
201
202
    /**
203
     * Loads an entity configuration.
204
     */
205
    protected function loadConfig()
206
    {
207
        $entityClass = $this->getClassName();
208
        if (empty($entityClass)) {
209
            throw new \RuntimeException(
210
                'A class name must be set in the context before a configuration is loaded.'
211
            );
212
        }
213
214
        // load config by a config provider
215
        $config = $this->configProvider->getConfig(
216
            $entityClass,
217
            $this->getVersion(),
218
            $this->getRequestType(),
219
            $this->getConfigExtras()
220
        );
221
222
        // add loaded config sections to the context
223
        if (!$config->isEmpty()) {
224
            foreach ($config as $key => $value) {
225
                $this->set(self::CONFIG_PREFIX . $key, $value);
226
            }
227
        }
228
229
        // make sure that all config sections, including a main section, are added to the context
230
        // even if a section was not returned by the config provider
231
        $key = $this->getConfigKey();
232
        if (!$this->has($key)) {
233
            $this->set($key, null);
234
        }
235
        $this->ensureAllConfigSectionsSet();
236
    }
237
238
    /**
239
     * Makes sure that all config sections are added to the context.
240
     */
241
    protected function ensureAllConfigSectionsSet()
242
    {
243
        $configExtras = $this->getConfigExtras();
244
        foreach ($configExtras as $configExtra) {
245
            if ($configExtra instanceof ConfigExtraSectionInterface) {
246
                $key = self::CONFIG_PREFIX . $configExtra->getName();
247
                if (!$this->has($key)) {
248
                    $this->set($key, null);
249
                }
250
            }
251
        }
252
    }
253
254
    /**
255
     * Loads an entity metadata.
256
     */
257
    protected function loadMetadata()
258
    {
259
        $entityClass = $this->getClassName();
260
        if (empty($entityClass)) {
261
            throw new \RuntimeException(
262
                'A class name must be set in the context before metadata are loaded.'
263
            );
264
        }
265
266
        // load metadata by a metadata provider
267
        $metadata = $this->metadataProvider->getMetadata(
268
            $entityClass,
269
            $this->getVersion(),
270
            $this->getRequestType(),
271
            $this->getMetadataExtras(),
272
            $this->getConfig()
273
        );
274
275
        // add loaded metadata to the context
276
        $this->set(self::METADATA, $metadata);
277
    }
278
279
    /**
280
     * Gets request headers.
281
     *
282
     * @return ParameterBagInterface
283
     */
284
    public function getRequestHeaders()
285
    {
286
        if (null === $this->requestHeaders) {
287
            $this->requestHeaders = new CaseInsensitiveParameterBag();
288
        }
289
290
        return $this->requestHeaders;
291
    }
292
293
    /**
294
     * Sets an object that will be used to accessing request headers.
295
     *
296
     * @param ParameterBagInterface $parameterBag
297
     */
298
    public function setRequestHeaders(ParameterBagInterface $parameterBag)
299
    {
300
        $this->requestHeaders = $parameterBag;
301
    }
302
303
    /**
304
     * Gets response headers.
305
     *
306
     * @return ParameterBagInterface
307
     */
308
    public function getResponseHeaders()
309
    {
310
        if (null === $this->responseHeaders) {
311
            $this->responseHeaders = new ParameterBag();
312
        }
313
314
        return $this->responseHeaders;
315
    }
316
317
    /**
318
     * Sets an object that will be used to accessing response headers.
319
     *
320
     * @param ParameterBagInterface $parameterBag
321
     */
322
    public function setResponseHeaders(ParameterBagInterface $parameterBag)
323
    {
324
        $this->responseHeaders = $parameterBag;
325
    }
326
327
    /**
328
     * Gets the response status code.
329
     *
330
     * @return int|null
331
     */
332
    public function getResponseStatusCode()
333
    {
334
        return $this->get(self::RESPONSE_STATUS_CODE);
335
    }
336
337
    /**
338
     * Sets the response status code.
339
     *
340
     * @param $statusCode
341
     */
342
    public function setResponseStatusCode($statusCode)
343
    {
344
        $this->set(self::RESPONSE_STATUS_CODE, $statusCode);
345
    }
346
347
    /**
348
     * Gets FQCN of an entity.
349
     *
350
     * @return string
351
     */
352
    public function getClassName()
353
    {
354
        return $this->get(self::CLASS_NAME);
355
    }
356
357
    /**
358
     * Sets FQCN of an entity.
359
     *
360
     * @param string $className
361
     */
362
    public function setClassName($className)
363
    {
364
        $this->set(self::CLASS_NAME, $className);
365
    }
366
367
    /**
368
     * Checks whether a configuration of an entity exists.
369
     *
370
     * @return bool
371
     */
372
    public function hasConfig()
373
    {
374
        return $this->has($this->getConfigKey());
375
    }
376
377
    /**
378
     * Gets a configuration of an entity.
379
     *
380
     * @return EntityDefinitionConfig|null
381
     */
382
    public function getConfig()
383
    {
384
        $key = $this->getConfigKey();
385
        if (!$this->has($key)) {
386
            $this->loadConfig();
387
        }
388
389
        return $this->get($key);
390
    }
391
392
    /**
393
     * Sets a configuration of an entity.
394
     *
395
     * @param EntityDefinitionConfig|null $definition
396
     */
397
    public function setConfig(EntityDefinitionConfig $definition = null)
398
    {
399
        $this->set($this->getConfigKey(), $definition);
400
401
        // make sure that all config sections are added to the context
402
        $this->ensureAllConfigSectionsSet();
403
    }
404
405
    /**
406
     * Checks whether a configuration of the given section exists.
407
     *
408
     * @param string $configSection
409
     *
410
     * @return bool
411
     *
412
     * @throws \InvalidArgumentException if undefined configuration section is specified
413
     */
414
    public function hasConfigOf($configSection)
415
    {
416
        $this->assertConfigSection($configSection);
417
418
        return $this->has(self::CONFIG_PREFIX . $configSection);
419
    }
420
421
    /**
422
     * Gets a configuration from the given section.
423
     *
424
     * @param string $configSection
425
     *
426
     * @return mixed
427
     *
428
     * @throws \InvalidArgumentException if undefined configuration section is specified
429
     */
430 View Code Duplication
    public function getConfigOf($configSection)
431
    {
432
        $this->assertConfigSection($configSection);
433
434
        $key = self::CONFIG_PREFIX . $configSection;
435
        if (!$this->has($key)) {
436
            if (!$this->has($this->getConfigKey())) {
437
                $this->loadConfig();
438
            } else {
439
                $this->setConfigOf($configSection, null);
440
            }
441
        }
442
443
        return $this->get($key);
444
    }
445
446
    /**
447
     * Sets a configuration for the given section.
448
     *
449
     * @param string $configSection
450
     * @param mixed  $config
451
     *
452
     * @throws \InvalidArgumentException if undefined configuration section is specified
453
     */
454 View Code Duplication
    public function setConfigOf($configSection, $config)
455
    {
456
        $this->assertConfigSection($configSection);
457
458
        $this->set(self::CONFIG_PREFIX . $configSection, $config);
459
460
        // make sure that all config sections, including a main section, are added to the context
461
        $key = $this->getConfigKey();
462
        if (!$this->has($key)) {
463
            $this->set($key, null);
464
        }
465
        $this->ensureAllConfigSectionsSet();
466
    }
467
468
    /**
469
     * Gets a list of requests for configuration data.
470
     *
471
     * @return ConfigExtraInterface[]
472
     */
473
    public function getConfigExtras()
474
    {
475
        $extras = $this->get(self::CONFIG_EXTRAS);
476
477
        return null !== $extras
478
            ? $extras
479
            : [];
480
    }
481
482
    /**
483
     * Sets a list of requests for configuration data.
484
     *
485
     * @param ConfigExtraInterface[] $extras
486
     *
487
     * @throws \InvalidArgumentException if $extras has invalid elements
488
     */
489 View Code Duplication
    public function setConfigExtras(array $extras)
490
    {
491
        foreach ($extras as $configExtra) {
492
            if (!$configExtra instanceof ConfigExtraInterface) {
493
                throw new \InvalidArgumentException(
494
                    'Expected an array of "Oro\Bundle\ApiBundle\Config\ConfigExtraInterface".'
495
                );
496
            }
497
        }
498
499
        if (empty($extras)) {
500
            $this->remove(self::CONFIG_EXTRAS);
501
        } else {
502
            $this->set(self::CONFIG_EXTRAS, $extras);
503
        }
504
    }
505
506
    /**
507
     * Checks whether some configuration data is requested.
508
     *
509
     * @param string $extraName
510
     *
511
     * @return bool
512
     */
513
    public function hasConfigExtra($extraName)
514
    {
515
        $configExtras = $this->getConfigExtras();
516
        foreach ($configExtras as $configExtra) {
517
            if ($configExtra->getName() === $extraName) {
518
                return true;
519
            }
520
        }
521
522
        return false;
523
    }
524
525
    /**
526
     * Adds a request for some configuration data.
527
     *
528
     * @param ConfigExtraInterface $extra
529
     *
530
     * @throws \InvalidArgumentException if a config extra with the same name already exists
531
     */
532
    public function addConfigExtra(ConfigExtraInterface $extra)
533
    {
534
        if ($this->hasConfigExtra($extra->getName())) {
535
            throw new \InvalidArgumentException(
536
                sprintf('The "%s" config extra already exists.', $extra->getName())
537
            );
538
        }
539
        $extras   = $this->getConfigExtras();
540
        $extras[] = $extra;
541
        $this->setConfigExtras($extras);
542
    }
543
544
    /**
545
     * Removes a request for some configuration data.
546
     *
547
     * @param string $extraName
548
     */
549
    public function removeConfigExtra($extraName)
550
    {
551
        $configExtras = $this->getConfigExtras();
552
        $keys         = array_keys($configExtras);
553
        foreach ($keys as $key) {
554
            if ($configExtras[$key]->getName() === $extraName) {
555
                unset($configExtras[$key]);
556
            }
557
        }
558
        $this->setConfigExtras(array_values($configExtras));
559
    }
560
561
    /**
562
     * Checks whether metadata of an entity exists.
563
     *
564
     * @return bool
565
     */
566
    public function hasMetadata()
567
    {
568
        return $this->has(self::METADATA);
569
    }
570
571
    /**
572
     * Gets metadata of an entity.
573
     *
574
     * @return EntityMetadata|null
575
     */
576
    public function getMetadata()
577
    {
578
        if (!$this->has(self::METADATA)) {
579
            $this->loadMetadata();
580
        }
581
582
        return $this->get(self::METADATA);
583
    }
584
585
    /**
586
     * Sets metadata of an entity.
587
     *
588
     * @param EntityMetadata|null $metadata
589
     */
590
    public function setMetadata(EntityMetadata $metadata = null)
591
    {
592
        $this->set(self::METADATA, $metadata);
593
    }
594
595
    /**
596
     * Gets a list of requests for additional metadata info.
597
     *
598
     * @return MetadataExtraInterface[]
599
     */
600
    public function getMetadataExtras()
601
    {
602
        $extras = $this->get(self::METADATA_EXTRAS);
603
604
        return null !== $extras
605
            ? $extras
606
            : [];
607
    }
608
609
    /**
610
     * Sets a list of requests for additional metadata info.
611
     *
612
     * @param MetadataExtraInterface[] $extras
613
     *
614
     * @throws \InvalidArgumentException if $extras has invalid elements
615
     */
616 View Code Duplication
    public function setMetadataExtras(array $extras)
617
    {
618
        foreach ($extras as $configExtra) {
619
            if (!$configExtra instanceof MetadataExtraInterface) {
620
                throw new \InvalidArgumentException(
621
                    'Expected an array of "Oro\Bundle\ApiBundle\Metadata\MetadataExtraInterface".'
622
                );
623
            }
624
        }
625
626
        if (empty($extras)) {
627
            $this->remove(self::METADATA_EXTRAS);
628
        } else {
629
            $this->set(self::METADATA_EXTRAS, $extras);
630
        }
631
    }
632
633
    /**
634
     * Checks whether some additional metadata info is requested.
635
     *
636
     * @param string $extraName
637
     *
638
     * @return bool
639
     */
640
    public function hasMetadataExtra($extraName)
641
    {
642
        $metadataExtras = $this->getMetadataExtras();
643
        foreach ($metadataExtras as $metadataExtra) {
644
            if ($metadataExtra->getName() === $extraName) {
645
                return true;
646
            }
647
        }
648
649
        return false;
650
    }
651
652
    /**
653
     * Adds a request for some additional metadata info.
654
     *
655
     * @param MetadataExtraInterface $extra
656
     *
657
     * @throws \InvalidArgumentException if a metadata extra with the same name already exists
658
     */
659
    public function addMetadataExtra(MetadataExtraInterface $extra)
660
    {
661
        if ($this->hasMetadataExtra($extra->getName())) {
662
            throw new \InvalidArgumentException(
663
                sprintf('The "%s" metadata extra already exists.', $extra->getName())
664
            );
665
        }
666
        $extras   = $this->getMetadataExtras();
667
        $extras[] = $extra;
668
        $this->setMetadataExtras($extras);
669
    }
670
671
    /**
672
     * Removes a request for some additional metadata info.
673
     *
674
     * @param string $extraName
675
     */
676
    public function removeMetadataExtra($extraName)
677
    {
678
        $metadataExtras = $this->getMetadataExtras();
679
        $keys           = array_keys($metadataExtras);
680
        foreach ($keys as $key) {
681
            if ($metadataExtras[$key]->getName() === $extraName) {
682
                unset($metadataExtras[$key]);
683
            }
684
        }
685
        $this->setMetadataExtras(array_values($metadataExtras));
686
    }
687
688
    /**
689
     * Checks whether a query is used to get result data exists.
690
     *
691
     * @return bool
692
     */
693
    public function hasQuery()
694
    {
695
        return $this->has(self::QUERY);
696
    }
697
698
    /**
699
     * Gets a query is used to get result data.
700
     *
701
     * @return mixed
702
     */
703
    public function getQuery()
704
    {
705
        return $this->get(self::QUERY);
706
    }
707
708
    /**
709
     * Sets a query is used to get result data.
710
     *
711
     * @param mixed $query
712
     */
713
    public function setQuery($query)
714
    {
715
        $this->set(self::QUERY, $query);
716
    }
717
718
    /**
719
     * Gets the Criteria object is used to add additional restrictions to a query is used to get result data.
720
     *
721
     * @return Criteria
722
     */
723
    public function getCriteria()
724
    {
725
        return $this->get(self::CRITERIA);
726
    }
727
728
    /**
729
     * Sets the Criteria object is used to add additional restrictions to a query is used to get result data.
730
     *
731
     * @param Criteria $criteria
732
     */
733
    public function setCriteria($criteria)
734
    {
735
        $this->set(self::CRITERIA, $criteria);
736
    }
737
738
    /**
739
     * Whether any error happened during the processing of an action.
740
     *
741
     * @return bool
742
     */
743
    public function hasErrors()
744
    {
745
        return !empty($this->errors);
746
    }
747
748
    /**
749
     * Gets all errors happened during the processing of an action.
750
     *
751
     * @return Error[]
752
     */
753
    public function getErrors()
754
    {
755
        return null !== $this->errors
756
            ? $this->errors
757
            : [];
758
    }
759
760
    /**
761
     * Registers an error.
762
     *
763
     * @param Error $error
764
     */
765
    public function addError(Error $error)
766
    {
767
        if (null === $this->errors) {
768
            $this->errors = [];
769
        }
770
        $this->errors[] = $error;
771
    }
772
773
    /**
774
     * Removes all errors.
775
     */
776
    public function resetErrors()
777
    {
778
        $this->errors = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array<integer,object<Oro...ApiBundle\Model\Error>> of property $errors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
779
    }
780
781
    /**
782
     * @param string $configSection
783
     *
784
     * @throws \InvalidArgumentException if undefined configuration section is specified
785
     */
786
    protected function assertConfigSection($configSection)
787
    {
788
        $valid        = false;
789
        $configExtras = $this->getConfigExtras();
790
        foreach ($configExtras as $configExtra) {
791
            if ($configExtra instanceof ConfigExtraSectionInterface && $configSection === $configExtra->getName()) {
792
                $valid = true;
793
                break;
794
            }
795
        }
796
        if (!$valid) {
797
            throw new \InvalidArgumentException(sprintf('Undefined configuration section: "%s".', $configSection));
798
        }
799
    }
800
}
801