Completed
Push — master ( 597f04...339b29 )
by Kévin
9s
created

OperationMethodResolver::getOperationRoute()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 15
rs 8.8571
cc 5
eloc 8
nc 3
nop 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\Exception\RuntimeException;
15
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
16
use Symfony\Component\Routing\Route;
17
use Symfony\Component\Routing\RouterInterface;
18
19
/**
20
 * Resolves the HTTP method associated with an operation, extended for Symfony routing.
21
 *
22
 * @author Kévin Dunglas <[email protected]>
23
 * @author Teoh Han Hui <[email protected]>
24
 */
25
final class OperationMethodResolver implements OperationMethodResolverInterface
26
{
27
    private $router;
28
    private $resourceMetadataFactory;
29
30
    public function __construct(RouterInterface $router, ResourceMetadataFactoryInterface $resourceMetadataFactory)
31
    {
32
        $this->router = $router;
33
        $this->resourceMetadataFactory = $resourceMetadataFactory;
34
    }
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function getCollectionOperationMethod(string $resourceClass, string $operationName) : string
40
    {
41
        return $this->getOperationMethod($resourceClass, $operationName, true);
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function getItemOperationMethod(string $resourceClass, string $operationName) : string
48
    {
49
        return $this->getOperationMethod($resourceClass, $operationName, false);
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    public function getCollectionOperationRoute(string $resourceClass, string $operationName) : Route
56
    {
57
        return $this->getOperationRoute($resourceClass, $operationName, true);
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function getItemOperationRoute(string $resourceClass, string $operationName) : Route
64
    {
65
        return $this->getOperationRoute($resourceClass, $operationName, false);
66
    }
67
68
    /**
69
     * @param string $resourceClass
70
     * @param string $operationName
71
     * @param bool   $collection
72
     *
73
     * @throws RuntimeException
74
     *
75
     * @return string
76
     */
77
    private function getOperationMethod(string $resourceClass, string $operationName, bool $collection) : string
78
    {
79
        $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
80
81
        if ($collection) {
82
            $method = $resourceMetadata->getCollectionOperationAttribute($operationName, 'method');
83
        } else {
84
            $method = $resourceMetadata->getItemOperationAttribute($operationName, 'method');
85
        }
86
87
        if (null !== $method) {
88
            return $method;
89
        }
90
91
        if ($collection) {
92
            $routeName = $resourceMetadata->getCollectionOperationAttribute($operationName, 'route_name');
93
        } else {
94
            $routeName = $resourceMetadata->getItemOperationAttribute($operationName, 'route_name');
95
        }
96
97
        if (null === $routeName) {
98
            throw new RuntimeException(sprintf('Either a "route_name" or a "method" operation attribute must exist for the operation "%s" of the resource "%s".', $operationName, $resourceClass));
99
        }
100
101
        /*
102
         * @var Route
103
         */
104
        foreach ($this->router->getRouteCollection() as $name => $route) {
105
            if ($routeName === $name) {
106
                $methods = $route->getMethods();
107
108
                if (empty($methods)) {
109
                    return 'GET';
110
                }
111
112
                return $methods[0];
113
            }
114
        }
115
116
        throw new RuntimeException(sprintf('Route "%s" not found for the operation "%s" of the resource "%s".', $routeName, $operationName, $resourceClass));
117
    }
118
119
    /**
120
     * @param string $resourceClass
121
     * @param string $operationName
122
     * @param bool   $collection
123
     *
124
     * @throws RuntimeException
125
     *
126
     * @return Route
127
     */
128
    private function getOperationRoute(string $resourceClass, string $operationName, bool $collection) : Route
129
    {
130
        $operationNameKey = sprintf('_%s_operation_name', $collection ? 'collection' : 'item');
131
132
        foreach ($this->router->getRouteCollection()->all() as $routeName => $route) {
133
            $currentResourceClass = $route->getDefault('_resource_class');
134
            $currentOperationName = $route->getDefault($operationNameKey);
135
136
            if ($resourceClass === $currentResourceClass && $operationName === $currentOperationName) {
137
                return $route;
138
            }
139
        }
140
141
        throw new RuntimeException(sprintf('No route found for operation "%s" for type "%s".', $operationName, $resourceClass));
142
    }
143
}
144