ReadListener   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 84
rs 10
c 0
b 0
f 0
wmc 18

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
F onKernelRequest() 0 59 17
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\EventListener;
15
16
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
17
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
18
use ApiPlatform\Core\DataProvider\OperationDataProviderTrait;
19
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
20
use ApiPlatform\Core\Exception\InvalidIdentifierException;
21
use ApiPlatform\Core\Exception\RuntimeException;
22
use ApiPlatform\Core\Identifier\IdentifierConverterInterface;
23
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
24
use ApiPlatform\Core\Metadata\Resource\ToggleableOperationAttributeTrait;
25
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
26
use ApiPlatform\Core\Util\CloneTrait;
27
use ApiPlatform\Core\Util\RequestAttributesExtractor;
28
use ApiPlatform\Core\Util\RequestParser;
29
use Symfony\Component\HttpKernel\Event\RequestEvent;
30
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
31
32
/**
33
 * Retrieves data from the applicable data provider and sets it as a request parameter called data.
34
 *
35
 * @author Kévin Dunglas <[email protected]>
36
 */
37
final class ReadListener
38
{
39
    use CloneTrait;
40
    use OperationDataProviderTrait;
41
    use ToggleableOperationAttributeTrait;
42
43
    public const OPERATION_ATTRIBUTE_KEY = 'read';
44
45
    private $serializerContextBuilder;
46
47
    public function __construct(CollectionDataProviderInterface $collectionDataProvider, ItemDataProviderInterface $itemDataProvider, SubresourceDataProviderInterface $subresourceDataProvider = null, SerializerContextBuilderInterface $serializerContextBuilder = null, IdentifierConverterInterface $identifierConverter = null, ResourceMetadataFactoryInterface $resourceMetadataFactory = null)
48
    {
49
        $this->collectionDataProvider = $collectionDataProvider;
50
        $this->itemDataProvider = $itemDataProvider;
51
        $this->subresourceDataProvider = $subresourceDataProvider;
52
        $this->serializerContextBuilder = $serializerContextBuilder;
53
        $this->identifierConverter = $identifierConverter;
54
        $this->resourceMetadataFactory = $resourceMetadataFactory;
55
    }
56
57
    /**
58
     * Calls the data provider and sets the data attribute.
59
     *
60
     * @throws NotFoundHttpException
61
     */
62
    public function onKernelRequest(RequestEvent $event): void
63
    {
64
        $request = $event->getRequest();
65
        if (
66
            !($attributes = RequestAttributesExtractor::extractAttributes($request))
67
            || !$attributes['receive']
68
            || $request->isMethod('POST') && isset($attributes['collection_operation_name'])
69
            || $this->isOperationAttributeDisabled($attributes, self::OPERATION_ATTRIBUTE_KEY)
70
        ) {
71
            return;
72
        }
73
74
        if (null === $filters = $request->attributes->get('_api_filters')) {
75
            $queryString = RequestParser::getQueryString($request);
76
            $filters = $queryString ? RequestParser::parseRequestParams($queryString) : null;
77
        }
78
79
        $context = null === $filters ? [] : ['filters' => $filters];
80
        if ($this->serializerContextBuilder) {
81
            // Builtin data providers are able to use the serialization context to automatically add join clauses
82
            $context += $normalizationContext = $this->serializerContextBuilder->createFromRequest($request, true, $attributes);
83
            $request->attributes->set('_api_normalization_context', $normalizationContext);
84
        }
85
86
        if (isset($attributes['collection_operation_name'])) {
87
            $request->attributes->set('data', $this->getCollectionData($attributes, $context));
88
89
            return;
90
        }
91
92
        $data = [];
93
94
        if ($this->identifierConverter) {
95
            $context[IdentifierConverterInterface::HAS_IDENTIFIER_CONVERTER] = true;
96
        }
97
98
        try {
99
            $identifiers = $this->extractIdentifiers($request->attributes->all(), $attributes);
100
101
            if (isset($attributes['item_operation_name'])) {
102
                $data = $this->getItemData($identifiers, $attributes, $context);
103
            } elseif (isset($attributes['subresource_operation_name'])) {
104
                // Legacy
105
                if (null === $this->subresourceDataProvider) {
106
                    throw new RuntimeException('No subresource data provider.');
107
                }
108
109
                $data = $this->getSubresourceData($identifiers, $attributes, $context);
110
            }
111
        } catch (InvalidIdentifierException $e) {
112
            throw new NotFoundHttpException('Invalid identifier value or configuration.', $e);
113
        }
114
115
        if (null === $data) {
116
            throw new NotFoundHttpException('Not Found');
117
        }
118
119
        $request->attributes->set('data', $data);
120
        $request->attributes->set('previous_data', $this->clone($data));
121
    }
122
}
123