Completed
Push — develop ( e72854...0832ef )
by Daniel
06:46
created

CollectionModifier::process()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 67
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 67
rs 7.6008
c 0
b 0
f 0
cc 9
nc 8
nop 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Silverback\ApiComponentBundle\DataModifier;
4
5
use ApiPlatform\Core\Api\OperationType;
6
use ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator;
7
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
8
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
9
use ApiPlatform\Core\PathResolver\OperationPathResolverInterface;
10
use Psr\Container\ContainerInterface;
11
use Silverback\ApiComponentBundle\Entity\Component\Collection\Collection;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\RequestStack;
14
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
15
16
class CollectionModifier extends AbstractModifier
17
{
18
    private $resourceMetadataFactory;
19
    private $operationPathResolver;
20
    private $itemNormalizer;
21
    private $requestStack;
22
23
    public function __construct(
24
        ContainerInterface $container,
25
        ResourceMetadataFactoryInterface $resourceMetadataFactory,
26
        OperationPathResolverInterface $operationPathResolver,
27
        NormalizerInterface $itemNormalizer,
28
        RequestStack $requestStack
29
    )
30
    {
31
        parent::__construct($container);
32
        $this->resourceMetadataFactory = $resourceMetadataFactory;
33
        $this->operationPathResolver = $operationPathResolver;
34
        $this->itemNormalizer = $itemNormalizer;
35
        $this->requestStack = $requestStack;
36
    }
37
38
    /**
39
     * @param Collection $collectionEntity
40
     * @param array $context
41
     * @param null|string $format
42
     * @return object|void
43
     */
44
    public function process($collectionEntity, array $context = array(), ?string $format = null)
45
    {
46
        $resourceMetadata = $this->resourceMetadataFactory->create($collectionEntity->getResource());
47
        $requestUri = null;
48
49
        $collectionOperations = $resourceMetadata->getCollectionOperations();
50
        if ($collectionOperations) {
51
            $collectionOperations = array_change_key_case($collectionOperations, CASE_LOWER);
52
            $baseRoute = trim(trim($resourceMetadata->getAttribute('route_prefix', '')), '/');
53
            $methods = ['post', 'get'];
54
            foreach ($methods as $method) {
55
                if (array_key_exists($method, $collectionOperations)) {
56
                    $path = $baseRoute . $this->operationPathResolver->resolveOperationPath(
57
                            $resourceMetadata->getShortName(),
0 ignored issues
show
Bug introduced by
It seems like $resourceMetadata->getShortName() can also be of type null; however, parameter $resourceShortName of ApiPlatform\Core\PathRes...:resolveOperationPath() 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

57
                            /** @scrutinizer ignore-type */ $resourceMetadata->getShortName(),
Loading history...
58
                            $collectionOperations[$method],
59
                            OperationType::COLLECTION,
60
                            $method);
0 ignored issues
show
Unused Code introduced by
The call to ApiPlatform\Core\PathRes...:resolveOperationPath() has too many arguments starting with $method. ( Ignorable by Annotation )

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

60
                    $path = $baseRoute . $this->operationPathResolver->/** @scrutinizer ignore-call */ resolveOperationPath(

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...
61
                    $finalPath = preg_replace('/{_format}$/', $format, $path);
62
                    $collectionEntity->addCollectionRoute(
63
                        $method,
64
                        $finalPath
65
                    );
66
                    if ($method === 'get') {
67
                        $requestUri = $finalPath;
68
                    }
69
                }
70
            }
71
        }
72
        $collectionResourceAttributes = $resourceMetadata->getAttributes();
0 ignored issues
show
Unused Code introduced by
The assignment to $collectionResourceAttributes is dead and can be removed.
Loading history...
73
74
        /** @var ContextAwareCollectionDataProviderInterface $dataProvider */
75
        $dataProvider = $this->container->get(ContextAwareCollectionDataProviderInterface::class);
76
        $dataProviderContext = [
77
            'filters' => [
78
                'pagination' => true,
79
                '_page' => 1
80
            ]];
81
        $request = $apiPagination = null;
82
        if ($collectionEntity->getPerPage() && ($request = $this->requestStack->getCurrentRequest())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $collectionEntity->getPerPage() of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
83
            $apiPagination = $request->attributes->get('_api_pagination');
84
            $originalPerPage = $apiPagination['itemsPerPage'];
85
            $apiPagination['itemsPerPage'] = $collectionEntity->getPerPage();
86
            $request->attributes->set('_api_pagination', $apiPagination);
87
            $apiPagination['itemsPerPage'] = $originalPerPage;
88
        }
89
90
        /** @var Paginator $collection */
91
        $collection = $dataProvider->getCollection($collectionEntity->getResource(), Request::METHOD_GET, $dataProviderContext);
92
93
        if ($request && $apiPagination) {
94
            $request->attributes->set('_api_pagination', $apiPagination);
95
        }
96
97
        $forcedContext = [
98
            'resource_class' => Collection::class,
99
            'request_uri' => $requestUri,
100
            'jsonld_has_context' => false,
101
            'api_sub_level' => null
102
        ];
103
        $mergedContext = array_merge($context, $forcedContext);
104
        $normalizedCollection = $this->itemNormalizer->normalize(
105
            $collection,
106
            $format,
107
            $mergedContext
108
        );
109
110
        $collectionEntity->setCollection($normalizedCollection);
0 ignored issues
show
Bug introduced by
It seems like $normalizedCollection can also be of type boolean and double and integer and string; however, parameter $collection of Silverback\ApiComponentB...ection::setCollection() does only seem to accept Traversable|array, 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

110
        $collectionEntity->setCollection(/** @scrutinizer ignore-type */ $normalizedCollection);
Loading history...
111
    }
112
113
    public function supportsData($data): bool
114
    {
115
        return $data instanceof Collection;
116
    }
117
118
    public static function getSubscribedServices(): array
119
    {
120
        return [
121
            '?' . ContextAwareCollectionDataProviderInterface::class,
122
            RequestStack::class
123
        ];
124
    }
125
}
126