Completed
Pull Request — 2.0 (#1080)
by
unknown
19:44
created

IriConverter   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 9
dl 0
loc 96
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getItemFromIri() 0 18 4
A getIriFromItem() 0 9 1
A getIriFromResourceClass() 0 8 2
A generateIdentifiersUrl() 0 12 3
A __construct() 0 16 2
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\Bridge\Symfony\Routing;
15
16
use ApiPlatform\Core\Api\IdentifiersExtractor;
17
use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
18
use ApiPlatform\Core\Api\IriConverterInterface;
19
use ApiPlatform\Core\Api\UrlGeneratorInterface;
20
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
21
use ApiPlatform\Core\Exception\InvalidArgumentException;
22
use ApiPlatform\Core\Exception\ItemNotFoundException;
23
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
24
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
25
use ApiPlatform\Core\Util\ClassInfoTrait;
26
use Symfony\Component\PropertyAccess\PropertyAccess;
27
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
28
use Symfony\Component\Routing\Exception\ExceptionInterface as RoutingExceptionInterface;
29
use Symfony\Component\Routing\RouterInterface;
30
31
/**
32
 * {@inheritdoc}
33
 *
34
 * @author Kévin Dunglas <[email protected]>
35
 */
36
final class IriConverter implements IriConverterInterface
37
{
38
    use ClassInfoTrait;
39
40
    private $propertyNameCollectionFactory;
41
    private $propertyMetadataFactory;
42
    private $itemDataProvider;
43
    private $routeNameResolver;
44
    private $router;
45
    private $propertyAccessor;
46
    private $identifiersExtractor;
47
48
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null)
49
    {
50
        $this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
51
        $this->propertyMetadataFactory = $propertyMetadataFactory;
52
        $this->itemDataProvider = $itemDataProvider;
53
        $this->routeNameResolver = $routeNameResolver;
54
        $this->router = $router;
55
        $this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
56
57
        if (null === $identifiersExtractor) {
58
            @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...
59
            $this->identifiersExtractor = new IdentifiersExtractor($this->propertyNameCollectionFactory, $this->propertyMetadataFactory, $this->propertyAccessor);
60
        } else {
61
            $this->identifiersExtractor = $identifiersExtractor;
62
        }
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function getItemFromIri(string $iri, array $context = [])
69
    {
70
        try {
71
            $parameters = $this->router->match($iri);
72
        } catch (RoutingExceptionInterface $e) {
73
            throw new InvalidArgumentException(sprintf('No route matches "%s".', $iri), $e->getCode(), $e);
74
        }
75
76
        if (!isset($parameters['_api_resource_class'], $parameters['id'])) {
77
            throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
78
        }
79
80
        if ($item = $this->itemDataProvider->getItem($parameters['_api_resource_class'], $parameters['id'], null, $context)) {
81
            return $item;
82
        }
83
84
        throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function getIriFromItem($item, int $referenceType = UrlGeneratorInterface::ABS_PATH): string
91
    {
92
        $resourceClass = $this->getObjectClass($item);
93
        $routeName = $this->routeNameResolver->getRouteName($resourceClass, false);
94
95
        $identifiers = $this->generateIdentifiersUrl($this->identifiersExtractor->getIdentifiersFromItem($item));
96
97
        return $this->router->generate($routeName, ['id' => implode(';', $identifiers)], $referenceType);
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function getIriFromResourceClass(string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH): string
104
    {
105
        try {
106
            return $this->router->generate($this->routeNameResolver->getRouteName($resourceClass, true), [], $referenceType);
107
        } catch (RoutingExceptionInterface $e) {
108
            throw new InvalidArgumentException(sprintf('Unable to generate an IRI for "%s".', $resourceClass), $e->getCode(), $e);
109
        }
110
    }
111
112
    /**
113
     * Generate the identifier url.
114
     *
115
     * @param array $identifiers
116
     *
117
     * @return string[]
118
     */
119
    private function generateIdentifiersUrl(array $identifiers): array
120
    {
121
        if (1 === count($identifiers)) {
122
            return [rawurlencode((string) array_values($identifiers)[0])];
123
        }
124
125
        foreach ($identifiers as $name => $value) {
126
            $identifiers[$name] = sprintf('%s=%s', $name, $value);
127
        }
128
129
        return $identifiers;
130
    }
131
}
132