Completed
Push — master ( 3f1d1d...0341ae )
by Matze
05:15
created

ControllerCompilerPass::process()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5.0214

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 19
cts 21
cp 0.9048
rs 8.439
c 0
b 0
f 0
cc 5
eloc 20
nc 5
nop 1
crap 5.0214
1
<?php
2
3
namespace BrainExe\Core\DependencyInjection\CompilerPass;
4
5
use BrainExe\Core\Annotations\CompilerPass;
6
use BrainExe\Core\Annotations\Route as RouteAnnotation;
7
use BrainExe\Core\Application\ControllerResolver;
8
use BrainExe\Core\Application\SerializedRouteCollection;
9
use BrainExe\Core\Traits\FileCacheTrait;
10
use Exception;
11
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
12
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
13
use Symfony\Component\DependencyInjection\ContainerBuilder;
14
use Symfony\Component\DependencyInjection\Reference;
15
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
16
use Symfony\Component\Routing\Route;
17
18
/**
19
 * @CompilerPass(priority=5)
20
 */
21
class ControllerCompilerPass implements CompilerPassInterface
22
{
23
    use FileCacheTrait;
24
25
    const CONTROLLER_TAG = 'controller';
26
    const ROUTE_TAG      = 'route';
27
28
    /**
29
     * {@inheritdoc}
30
     */
31 2
    public function process(ContainerBuilder $container)
32
    {
33 2
        $controllers = $container->findTaggedServiceIds(self::ROUTE_TAG);
34
35 2
        $serialized = [];
36 2
        $controllerLocator = [];
37 2
        foreach ($controllers as $controllerId => $tag) {
38 2
            foreach ($tag as $routeRaw) {
39
                /** @var RouteAnnotation $route */
40 2
                $route = $routeRaw[0];
41
42 2
                $name = $route->getName();
43 2
                if (empty($name)) {
44
                    throw new Exception(sprintf('"name" is missing for @Route(%s)', $controllerId));
45 2
                } elseif (isset($serialized[$name])) {
46
                    throw new Exception(sprintf('Route name %s does already exits in %s', $name, $controllerId));
47
                }
48
49 2
                $serialized[$name] = serialize($this->createRoute($route));
50
            }
51
52 2
            $controller = $container->getDefinition($controllerId);
53 2
            $controller->clearTag(self::ROUTE_TAG);
54 2
            $controllerLocator[$controllerId] = new Reference($controllerId);
55
        }
56
57 2
        $controllerResolver = $container->getDefinition(ControllerResolver::class);
58 2
        $controllerResolver->setArguments([
59 2
            new ServiceLocatorArgument($controllerLocator)
60
        ]);
61 2
        $this->dumpMatcher($container, $serialized);
62 2
    }
63
64
    /**
65
     * @param RouteAnnotation $route
66
     * @return Route
67
     */
68 2
    private function createRoute(RouteAnnotation $route)
69
    {
70 2
        if ($route->isCsrf()) {
71 1
            $route->setOptions(['csrf' => true]);
72
        }
73
74 2
        return new Route(
75 2
            $route->getPath(),
76 2
            $route->getDefaults(),
77 2
            $route->getRequirements(),
78 2
            $route->getOptions(),
79 2
            $route->getHost(),
80 2
            $route->getSchemes(),
81 2
            $route->getMethods(),
82 2
            $route->getCondition()
83
        );
84
    }
85
86
    /**
87
     * @param ContainerBuilder $container
88
     * @param array $routes
89
     * @codeCoverageIgnore
90
     */
91
    protected function dumpMatcher(ContainerBuilder $container, array $routes)
92
    {
93
        ksort($routes);
94
95
        $this->dumpVariableToCache(SerializedRouteCollection::CACHE_FILE, $routes);
96
97
        /** @var SerializedRouteCollection $routerCollection */
98
        $routerCollection = $container->get('Core.RouteCollection');
99
100
        $routerFile  = sprintf('%scache/router_matcher.php', ROOT);
101
        $routeDumper = new PhpMatcherDumper($routerCollection);
102
        $content     = $routeDumper->dump();
103
        file_put_contents($routerFile, $content);
104
    }
105
}
106