Passed
Pull Request — master (#64)
by Daniel
10:36
created

CollectionOutputDataTransformer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
nc 1
nop 8
dl 0
loc 10
ccs 0
cts 9
cp 0
crap 2
rs 10
c 1
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[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 Silverback\ApiComponentsBundle\DataTransformer;
15
16
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
17
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
18
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
19
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
20
use ApiPlatform\Core\Util\AttributesExtractor;
21
use ApiPlatform\Core\Util\RequestParser;
22
use Silverback\ApiComponentsBundle\Entity\Component\Collection;
23
use Silverback\ApiComponentsBundle\Exception\OutOfBoundsException;
24
use Silverback\ApiComponentsBundle\Helper\Collection\CollectionHelper;
25
use Silverback\ApiComponentsBundle\Serializer\SerializeFormatResolver;
26
use Symfony\Component\HttpFoundation\Request;
27
use Symfony\Component\HttpFoundation\RequestStack;
28
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
29
30
/**
31
 * @author Daniel West <[email protected]>
32
 */
33
class CollectionOutputDataTransformer implements DataTransformerInterface
34
{
35
    private CollectionHelper $iriConverter;
36
    private CollectionDataProviderInterface $collectionDataProvider;
37
    private RequestStack $requestStack;
38
    private SerializerContextBuilderInterface $serializerContextBuilder;
39
    private NormalizerInterface $itemNormalizer;
40
    private SerializeFormatResolver $serializeFormatResolver;
41
    private string $itemsPerPageParameterName;
42
    private string $paginationEnabledParameterName;
43
44
    public function __construct(CollectionHelper $iriConverter, CollectionDataProviderInterface $collectionDataProvider, RequestStack $requestStack, SerializerContextBuilderInterface $serializerContextBuilder, NormalizerInterface $itemNormalizer, SerializeFormatResolver $serializeFormatResolver, string $itemsPerPageParameterName, string $paginationEnabledParameterName)
45
    {
46
        $this->iriConverter = $iriConverter;
47
        $this->collectionDataProvider = $collectionDataProvider;
48
        $this->requestStack = $requestStack;
49
        $this->serializerContextBuilder = $serializerContextBuilder;
50
        $this->itemNormalizer = $itemNormalizer;
51
        $this->serializeFormatResolver = $serializeFormatResolver;
52
        $this->itemsPerPageParameterName = $itemsPerPageParameterName;
53
        $this->paginationEnabledParameterName = $paginationEnabledParameterName;
54
    }
55
56
    public function supportsTransformation($data, string $to, array $context = []): bool
57
    {
58
        return $data instanceof Collection && Collection::class === $to;
59
    }
60
61
    /**
62
     * @param Collection $object
63
     */
64
    public function transform($object, string $to, array $context = [])
65
    {
66
        $parameters = $this->iriConverter->getRouterParametersFromIri($object->getResourceIri());
0 ignored issues
show
Bug introduced by
It seems like $object->getResourceIri() can also be of type null; however, parameter $iri of Silverback\ApiComponents...uterParametersFromIri() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

66
        $parameters = $this->iriConverter->getRouterParametersFromIri(/** @scrutinizer ignore-type */ $object->getResourceIri());
Loading history...
67
        $attributes = AttributesExtractor::extractAttributes($parameters);
68
        $request = $this->requestStack->getMasterRequest();
69
70
        if (!$this->collectionDataProvider instanceof ContextAwareCollectionDataProviderInterface) {
71
            $collectionData = $this->collectionDataProvider->getCollection($attributes['resource_class'], $attributes['collection_operation_name']);
72
        } else {
73
            $filters = [];
74
            if ($perPage = $object->getPerPage()) {
75
                $filters[$this->itemsPerPageParameterName] = $perPage;
76
            }
77
            if ($requestFilters = $this->getFilters($request)) {
78
                $filters = array_merge($filters, $requestFilters);
79
            }
80
            if (isset($filters[$this->itemsPerPageParameterName]) && $filters[$this->itemsPerPageParameterName] <= 0) {
81
                $filters[$this->paginationEnabledParameterName] = false;
82
            }
83
84
            $collectionContext = ['filters' => $filters];
85
            $restoreNormalizationContext = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $restoreNormalizationContext is dead and can be removed.
Loading history...
86
            if ($request) {
87
                // Comment copied from ApiPlatform\Core\EventListener\ReadListener
88
                // Builtin data providers are able to use the serialization context to automatically add join clauses
89
                $normalizationContext = $this->serializerContextBuilder->createFromRequest(
90
                    $request,
91
                    true,
92
                    $attributes
93
                );
94
                $collectionContext += $normalizationContext;
95
            }
96
97
            $collectionData = $this->collectionDataProvider->getCollection($attributes['resource_class'], Request::METHOD_GET, $collectionContext);
0 ignored issues
show
Unused Code introduced by
The call to ApiPlatform\Core\DataPro...erface::getCollection() has too many arguments starting with $collectionContext. ( Ignorable by Annotation )

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

97
            /** @scrutinizer ignore-call */ 
98
            $collectionData = $this->collectionDataProvider->getCollection($attributes['resource_class'], Request::METHOD_GET, $collectionContext);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
98
        }
99
100
        // Pagination disabled
101
        if (\is_array($collectionData)) {
102
            $collection = $collectionData;
103
        } else {
104
            if (!$collectionData instanceof \Traversable) {
105
                dump('data', $collectionData);
106
                throw new OutOfBoundsException('$collectionData should be Traversable');
107
            }
108
            $collection = iterator_count($collectionData) ? $collectionData : null;
109
        }
110
111
        $format = $request ? $this->serializeFormatResolver->getFormatFromRequest($request) : null;
112
        $normalizerContext = [
113
            'resource_class' => $attributes['resource_class'],
114
            'request_uri' => $object->getResourceIri(),
115
            'jsonld_has_context' => false,
116
            'api_sub_level' => null,
117
            'subresource_operation_name' => Request::METHOD_GET,
118
        ];
119
        $normalizedCollection = $this->itemNormalizer->normalize($collection, $format, $normalizerContext);
120
121
        $object->setCollection($normalizedCollection);
122
123
        return $object;
124
    }
125
126
    private function getFilters(?Request $request)
127
    {
128
        if (!$request) {
129
            return null;
130
        }
131
        $queryString = RequestParser::getQueryString($request);
132
133
        return $queryString ? RequestParser::parseRequestParams($queryString) : null;
134
    }
135
}
136