Completed
Branch master (c0d8ef)
by Yaroslav
06:36
created

RequestAttributesFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 *
5
 * (c) Yaroslav Honcharuk <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Yarhon\RouteGuardBundle\Routing;
12
13
use Psr\Cache\CacheItemPoolInterface;
14
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
use Symfony\Component\HttpFoundation\ParameterBag;
16
use Symfony\Component\Routing\RequestContext;
17
use Yarhon\RouteGuardBundle\Cache\CacheFactory;
18
use Yarhon\RouteGuardBundle\Exception\RuntimeException;
19
20
/**
21
 * @author Yaroslav Honcharuk <[email protected]>
22
 */
23
class RequestAttributesFactory implements RequestAttributesFactoryInterface
24
{
25
    /**
26
     * @var CacheItemPoolInterface
27
     */
28
    private $routeMetadataCache;
29
30
    /**
31
     * @var RequestContext
32
     */
33
    private $generatorContext;
34
35
    /**
36
     * @var array
37
     */
38
    private $internalCache = [];
39
40
    /**
41
     * @param CacheItemPoolInterface $routeMetadataCache
42
     * @param UrlGeneratorInterface  $urlGenerator
43
     */
44 19
    public function __construct(CacheItemPoolInterface $routeMetadataCache, UrlGeneratorInterface $urlGenerator)
45
    {
46 19
        $this->routeMetadataCache = $routeMetadataCache;
47 19
        $this->generatorContext = $urlGenerator->getContext();
48 19
    }
49
50
    /**
51
     * @see \Symfony\Component\Routing\Matcher\UrlMatcher::getAttributes
52
     * @see \Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest
53
     *
54
     * {@inheritdoc}
55
     */
56 11
    public function createAttributes(RouteContextInterface $routeContext)
57
    {
58 11
        $cacheKey = spl_object_hash($routeContext);
59
60 11
        if (isset($this->internalCache[$cacheKey])) {
61 1
            return $this->internalCache[$cacheKey];
62
        }
63
64 11
        $routeMetadata = $this->getRouteMetadata($routeContext->getName());
65
66 10
        $parameters = $routeContext->getParameters();
67
68 10
        $defaults = $routeMetadata->getDefaults();
69
70
        // Special default parameters returned (if present): _format, _fragment, _locale
71
72
        // See \Symfony\Component\Routing\Matcher\UrlMatcher::mergeDefaults
73 10
        foreach ($parameters as $key => $value) {
74 5
            if (is_int($key) || null === $value) {
75 5
                unset($parameters[$key]);
76
            }
77
        }
78
79 10
        $variables = array_flip($routeMetadata->getVariables());
80
81 10
        $parameters = array_replace($this->generatorContext->getParameters(), $parameters);
82
83
        // We should add only parameters being used as route variables, others wouldn't be presented in generated url,
84
        // and therefore wouldn't be returned by the UrlMatcher as request attributes.
85 10
        $parameters = array_intersect_key($parameters, $variables);
86
87 10
        $attributes = array_replace($defaults, $parameters);
88
89 10
        if ($diff = array_diff_key($variables, $attributes)) {
90 1
            $missing = implode('", "', array_keys($diff));
91
            // TODO: don't throw this exception, because url generator would do this instead?
92 1
            throw new RuntimeException(sprintf('Some mandatory parameters are missing ("%s") to get attributes for route.', $missing));
93
        }
94
95 9
        return $this->internalCache[$cacheKey] = new ParameterBag($attributes);
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 5
    public function getAttributeNames(RouteMetadata $routeMetadata)
102
    {
103 5
        $names = array_merge($routeMetadata->getVariables(), array_keys($routeMetadata->getDefaults()));
104 5
        $names = array_unique($names);
105
106 5
        return $names;
107
    }
108
109
    /**
110
     * @param string $routeName
111
     *
112
     * @return RouteMetadata
113
     *
114
     * @throws RuntimeException
115
     */
116 11
    private function getRouteMetadata($routeName)
117
    {
118 11
        $cacheKey = CacheFactory::getValidCacheKey($routeName);
119 11
        $cacheItem = $this->routeMetadataCache->getItem($cacheKey);
120
121 11
        if (!$cacheItem->isHit()) {
122 1
            throw new RuntimeException(sprintf('Cannot get RouteMetadata for route "%s".', $routeName));
123
        }
124
125 10
        return $cacheItem->get();
126
    }
127
}
128