RequestAttributesFactory::createAttributes()   A
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 39
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 39
ccs 18
cts 18
cp 1
rs 9.0777
c 0
b 0
f 0
cc 6
nc 7
nop 1
crap 6
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 23
    public function __construct(CacheItemPoolInterface $routeMetadataCache, UrlGeneratorInterface $urlGenerator)
45
    {
46 23
        $this->routeMetadataCache = $routeMetadataCache;
47 23
        $this->generatorContext = $urlGenerator->getContext();
48 23
    }
49
50
    /**
51
     * @see \Symfony\Component\Routing\Matcher\UrlMatcher::getAttributes
52
     * @see \Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest
53
     *
54
     * {@inheritdoc}
55
     */
56 14
    public function createAttributes(RouteContextInterface $routeContext)
57
    {
58 14
        $cacheKey = spl_object_hash($routeContext);
59
60 14
        if (isset($this->internalCache[$cacheKey])) {
61 1
            return $this->internalCache[$cacheKey];
62
        }
63
64 14
        $routeMetadata = $this->getRouteMetadata($routeContext->getName());
65
66 13
        $parameters = $routeContext->getParameters();
67
68 13
        $defaults = $routeMetadata->getDefaults();
69
70
        // Special default parameters returned (if present): _format, _fragment, _locale
71
72
        // See \Symfony\Component\Routing\Matcher\UrlMatcher::mergeDefaults
73 13
        foreach ($parameters as $key => $value) {
74 7
            if (is_int($key) || null === $value) {
75 1
                unset($parameters[$key]);
76
            }
77
        }
78
79 13
        $variables = array_flip($routeMetadata->getVariables());
80
81 13
        $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 13
        $parameters = array_intersect_key($parameters, $variables);
86
87 13
        $attributes = array_replace($defaults, $parameters);
88
89 13
        if ($diff = array_diff_key($variables, $attributes)) {
90 1
            $missing = implode('", "', array_keys($diff));
91 1
            throw new RuntimeException(sprintf('Some mandatory parameters are missing ("%s") to get attributes for route.', $missing));
92
        }
93
94 12
        return $this->internalCache[$cacheKey] = new ParameterBag($attributes);
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100 14
    public function getAttributeNames(RouteMetadata $routeMetadata)
101
    {
102 14
        $names = array_merge($routeMetadata->getVariables(), array_keys($routeMetadata->getDefaults()));
103 14
        $names = array_unique($names);
104
105 14
        return $names;
106
    }
107
108
    /**
109
     * @param string $routeName
110
     *
111
     * @return RouteMetadata
112
     *
113
     * @throws RuntimeException
114
     */
115 14
    private function getRouteMetadata($routeName)
116
    {
117 14
        $cacheKey = CacheFactory::getValidCacheKey($routeName);
118 14
        $cacheItem = $this->routeMetadataCache->getItem($cacheKey);
119
120 14
        if (!$cacheItem->isHit()) {
121 1
            throw new RuntimeException(sprintf('Cannot get RouteMetadata for route "%s".', $routeName));
122
        }
123
124 13
        return $cacheItem->get();
125
    }
126
}
127