FilterSubscriber   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 101
ccs 0
cts 59
cp 0
rs 10
c 0
b 0
f 0
wmc 16

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A onKernelController() 0 18 5
A getSubscribedEvents() 0 5 1
A onKernelResponse() 0 18 5
A getClassAnnotations() 0 17 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the MiddlewareBundle
7
 *
8
 * (c) Indra Gunawan <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Indragunawan\MiddlewareBundle\EventSubscriber;
15
16
use Doctrine\Common\Annotations\Reader;
17
use Doctrine\Common\Util\ClassUtils;
18
use Indragunawan\MiddlewareBundle\Annotation\AfterFilter;
19
use Indragunawan\MiddlewareBundle\Annotation\BeforeFilter;
20
use Indragunawan\MiddlewareBundle\Middleware;
21
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
24
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
25
use Symfony\Component\HttpKernel\KernelEvents;
26
27
/**
28
 * @author Indra Gunawan <[email protected]>
29
 */
30
final class FilterSubscriber implements EventSubscriberInterface
31
{
32
    /**
33
     * @var Reader
34
     */
35
    private $reader;
36
37
    /**
38
     * @var Middleware
39
     */
40
    private $middleware;
41
42
    public function __construct(Reader $reader, Middleware $middleware)
43
    {
44
        $this->reader = $reader;
45
        $this->middleware = $middleware;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public static function getSubscribedEvents()
52
    {
53
        return [
54
            KernelEvents::CONTROLLER => ['onKernelController', 128],
55
            KernelEvents::RESPONSE => ['onKernelResponse', 128],
56
        ];
57
    }
58
59
    /**
60
     * @param FilterControllerEvent $event
61
     */
62
    public function onKernelController(FilterControllerEvent $event)
63
    {
64
        $controller = $event->getController();
65
66
        if (!\is_array($controller) && method_exists($controller, '__invoke')) {
67
            $controller = [$controller, '__invoke'];
68
        }
69
70
        if (!\is_array($controller)) {
71
            return;
72
        }
73
74
        $className = ClassUtils::getClass($controller[0]);
75
        $filters = $this->getClassAnnotations($className, $controller[1], BeforeFilter::class);
76
        $middlewares = $this->middleware->getMiddlewares('before_filter', $filters);
77
78
        foreach ($middlewares as $middleware) {
79
            $middleware->onBeforeFilter($event->getRequest(), [$className, $controller[1]], $event->getRequestType());
80
        }
81
    }
82
83
    /**
84
     * @param FilterResponseEvent $event
85
     */
86
    public function onKernelResponse(FilterResponseEvent $event)
87
    {
88
        // in request attributes '_controller' we trust
89
        $controller = $event->getRequest()->attributes->get('_controller');
90
        if (null === $controller) {
91
            return;
92
        }
93
94
        // $controller value should like 'App\Controller\HomepageController::index'
95
        $controller = explode('::', $controller);
96
        if (2 !== \count($controller) || !class_exists($controller[0])) {
97
            return;
98
        }
99
100
        $filters = $this->getClassAnnotations($controller[0], $controller[1], AfterFilter::class);
101
        $middlewares = $this->middleware->getMiddlewares('after_filter', $filters);
102
        foreach ($middlewares as $middleware) {
103
            $middleware->onAfterFilter($event->getRequest(), $event->getResponse(), $controller, $event->getRequestType());
104
        }
105
    }
106
107
    /**
108
     * @param string $className
109
     * @param string $method
110
     * @param string $annotationClass
111
     *
112
     * @return array
113
     */
114
    private function getClassAnnotations(string $className, string $method, string $annotationClass): array
115
    {
116
        $filters = [];
117
        $rejectedFilters = [];
118
        $classAnnotations = $this->reader->getClassAnnotations(new \ReflectionClass($className));
119
120
        foreach ($classAnnotations as $annotation) {
121
            if ($annotation instanceof $annotationClass) {
122
                if ($annotation->isSupportsMethod($method)) {
123
                    $filters = array_merge($filters, array_diff($annotation->getNames(), $rejectedFilters));
124
                } else {
125
                    $rejectedFilters = array_merge($rejectedFilters, $annotation->getNames());
126
                }
127
            }
128
        }
129
130
        return array_unique($filters);
131
    }
132
}
133