Completed
Pull Request — master (#1)
by Indra
02:41
created

FilterSubscriber::onKernelResponse()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 3
nop 1
dl 0
loc 14
ccs 0
cts 11
cp 0
crap 30
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the MiddlewareBundle
5
 *
6
 * (c) Indra Gunawan <[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 Indragunawan\MiddlewareBundle\EventSubscriber;
13
14
use Doctrine\Common\Annotations\Reader;
15
use Doctrine\Common\Util\ClassUtils;
16
use Indragunawan\MiddlewareBundle\Annotation\AfterFilter;
17
use Indragunawan\MiddlewareBundle\Annotation\BeforeFilter;
18
use Indragunawan\MiddlewareBundle\Middleware;
19
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
21
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
22
use Symfony\Component\HttpKernel\KernelEvents;
23
24
/**
25
 * @author Indra Gunawan <[email protected]>
26
 */
27
final class FilterSubscriber implements EventSubscriberInterface
28
{
29
    /**
30
     * @var Reader
31
     */
32
    private $reader;
33
34
    /**
35
     * @var Middleware
36
     */
37
    private $middleware;
38
39
    public function __construct(Reader $reader, Middleware $middleware)
40
    {
41
        $this->reader = $reader;
42
        $this->middleware = $middleware;
43
    }
44
45
    /**
46
     * @param FilterControllerEvent $event
47
     */
48
    public function onKernelController(FilterControllerEvent $event)
49
    {
50
        $controller = $event->getController();
51
52
        if (!\is_array($controller) && method_exists($controller, '__invoke')) {
53
            $controller = [$controller, '__invoke'];
54
        }
55
56
        if (!\is_array($controller)) {
57
            return;
58
        }
59
60
        $className = ClassUtils::getClass($controller[0]);
61
        $filters = $this->getClassAnnotations($className, $controller[1], BeforeFilter::class);
62
        $middlewares = $this->middleware->getMiddlewares('before_filter', $filters);
63
64
        foreach ($middlewares as $middleware) {
65
            $middleware->onBeforeFilter($event->getRequest(), [$className, $controller[1]], $event->getRequestType());
66
        }
67
    }
68
69
    /**
70
     * @param FilterResponseEvent $event
71
     */
72
    public function onKernelResponse(FilterResponseEvent $event)
73
    {
74
        // in request attributes '_controller' we trust
75
        $controller = $event->getRequest()->attributes->get('_controller');
76
        // $controller value should like 'App\Controller\HomepageController::index'
77
        $controller = explode('::', $controller);
78
        if (!\is_array($controller) || 2 !== \count($controller) || !class_exists($controller[0])) {
0 ignored issues
show
introduced by
The condition is_array($controller) is always true.
Loading history...
79
            return;
80
        }
81
82
        $filters = $this->getClassAnnotations($controller[0], $controller[1], AfterFilter::class);
83
        $middlewares = $this->middleware->getMiddlewares('after_filter', $filters);
84
        foreach ($middlewares as $middleware) {
85
            $middleware->onAfterFilter($event->getRequest(), $event->getResponse(), $controller, $event->getRequestType());
86
        }
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public static function getSubscribedEvents()
93
    {
94
        return [
95
            KernelEvents::CONTROLLER => ['onKernelController', -255], //expect priority -255 is the last
96
            KernelEvents::RESPONSE => ['onKernelResponse', 255], //expect priority 255 is the first
97
        ];
98
    }
99
100
    /**
101
     * @param string $className
102
     * @param string $method
103
     * @param string $annotationClass
104
     *
105
     * @return array
106
     */
107
    private function getClassAnnotations(string $className, string $method, string $annotationClass): array
108
    {
109
        $filters = [];
110
        $rejectedFilters = [];
111
        $classAnnotations = $this->reader->getClassAnnotations(new \ReflectionClass($className));
112
113
        foreach ($classAnnotations as $annotation) {
114
            if ($annotation instanceof $annotationClass) {
115
                if ($annotation->isSupportsMethod($method)) {
116
                    $filters = array_merge($filters, array_diff($annotation->getNames(), $rejectedFilters));
117
                } else {
118
                    $rejectedFilters = array_merge($rejectedFilters, $annotation->getNames());
119
                }
120
            }
121
        }
122
123
        return array_unique($filters);
124
    }
125
}
126