Completed
Pull Request — master (#997)
by Antoine
04:08
created

IriConverter::getIdentifiersFromItem()   D

Complexity

Conditions 9
Paths 10

Size

Total Lines 43
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 4.909
c 0
b 0
f 0
cc 9
eloc 23
nc 10
nop 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A IriConverter::generateIdentifiersUrl() 0 12 3
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
namespace ApiPlatform\Core\Bridge\Symfony\Routing;
13
14
use ApiPlatform\Core\Api\IdentifiersExtractor;
15
use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
16
use ApiPlatform\Core\Api\IriConverterInterface;
17
use ApiPlatform\Core\Api\UrlGeneratorInterface;
18
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
19
use ApiPlatform\Core\Exception\InvalidArgumentException;
20
use ApiPlatform\Core\Exception\ItemNotFoundException;
21
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
22
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
23
use ApiPlatform\Core\Util\ClassInfoTrait;
24
use Symfony\Component\PropertyAccess\PropertyAccess;
25
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
26
use Symfony\Component\Routing\Exception\ExceptionInterface as RoutingExceptionInterface;
27
use Symfony\Component\Routing\RouterInterface;
28
29
/**
30
 * {@inheritdoc}
31
 *
32
 * @author Kévin Dunglas <[email protected]>
33
 */
34
final class IriConverter implements IriConverterInterface
35
{
36
    use ClassInfoTrait;
37
38
    private $propertyNameCollectionFactory;
39
    private $propertyMetadataFactory;
40
    private $itemDataProvider;
41
    private $routeNameResolver;
42
    private $router;
43
    private $propertyAccessor;
44
    private $identifiersExtractor;
45
46
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null)
47
    {
48
        $this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
49
        $this->propertyMetadataFactory = $propertyMetadataFactory;
50
        $this->itemDataProvider = $itemDataProvider;
51
        $this->routeNameResolver = $routeNameResolver;
52
        $this->router = $router;
53
        $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
54
55
        if (null === $identifiersExtractor) {
56
            @trigger_error('Not injecting ItemIdentifiersExtractor is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3');
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
57
            $this->identifiersExtractor = new IdentifiersExtractor($this->propertyNameCollectionFactory, $this->propertyMetadataFactory, $this->propertyAccessor);
58
        } else {
59
            $this->identifiersExtractor = $identifiersExtractor;
60
        }
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function getItemFromIri(string $iri, array $context = [])
67
    {
68
        try {
69
            $parameters = $this->router->match($iri);
70
        } catch (RoutingExceptionInterface $e) {
71
            throw new InvalidArgumentException(sprintf('No route matches "%s".', $iri), $e->getCode(), $e);
72
        }
73
74
        if (!isset($parameters['_api_resource_class'], $parameters['id'])) {
75
            throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
76
        }
77
78
        if ($item = $this->itemDataProvider->getItem($parameters['_api_resource_class'], $parameters['id'], null, $context)) {
79
            return $item;
80
        }
81
82
        throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88
    public function getIriFromItem($item, int $referenceType = UrlGeneratorInterface::ABS_PATH): string
89
    {
90
        $resourceClass = $this->getObjectClass($item);
91
        $routeName = $this->routeNameResolver->getRouteName($resourceClass, false);
92
93
        $identifiers = $this->generateIdentifiersUrl($this->itemIdentifiersExtractor->getIdentifiersFromItem($item));
0 ignored issues
show
Bug introduced by
The property itemIdentifiersExtractor does not seem to exist. Did you mean identifiersExtractor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
94
95
        return $this->router->generate($routeName, ['id' => implode(';', $identifiers)], $referenceType);
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function getIriFromResourceClass(string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string
102
    {
103
        try {
104
            return $this->router->generate($this->routeNameResolver->getRouteName($resourceClass, true), [], $referenceType);
105
        } catch (RoutingExceptionInterface $e) {
106
            throw new InvalidArgumentException(sprintf('Unable to generate an IRI for "%s".', $resourceClass), $e->getCode(), $e);
107
        }
108
    }
109
110
    /**
111
     * Generate the identifier url.
112
     *
113
     * @param array $identifiers
114
     *
115
     * @return string[]
116
     */
117
    private function generateIdentifiersUrl(array $identifiers): array
118
    {
119
        if (1 === count($identifiers)) {
120
            return [rawurlencode(array_values($identifiers)[0])];
121
        }
122
123
        foreach ($identifiers as $name => $value) {
124
            $identifiers[$name] = sprintf('%s=%s', $name, $value);
125
        }
126
127
        return $identifiers;
128
    }
129
}
130