Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

AdminBundle/EventListener/ToolbarListener.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\AdminBundle\EventListener;
4
5
use Kunstmaan\AdminBundle\Helper\AdminRouteHelper;
6
use Kunstmaan\AdminBundle\Helper\Toolbar\DataCollector;
7
use Symfony\Component\DependencyInjection\ContainerInterface;
8
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
12
use Symfony\Component\HttpKernel\Event\ResponseEvent;
13
use Symfony\Component\HttpKernel\HttpKernel;
14
use Symfony\Component\HttpKernel\KernelEvents;
15
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
17
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
18
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
19
use Twig\Environment;
20
21
class ToolbarListener implements EventSubscriberInterface
22
{
23
    const DISABLED = 1;
24
25
    const ENABLED = 2;
26
27
    /**
28
     * @var Environment
29
     */
30
    protected $twig;
31
32
    /**
33
     * @var UrlGeneratorInterface
34
     */
35
    protected $urlGenerator;
36
37
    /**
38
     * @var DataCollector
39
     */
40
    protected $dataCollector;
41
42
    /**
43
     * @var AuthorizationChecker
44
     */
45
    protected $authorizationChecker;
46
47
    /**
48
     * @var TokenStorageInterface
49
     */
50
    protected $tokenStorage;
51
52
    /**
53
     * @var bool
54
     */
55
    protected $enabled;
56
57
    /**
58
     * @var ContainerInterface
59
     */
60
    private $container;
61
62
    /**
63
     * @var AdminRouteHelper
64
     */
65
    protected $adminRouteHelper;
66
67
    /**
68
     * @var array
69
     */
70
    protected $providerKeys;
71
72
    /**
73
     * @var array
74
     */
75
    protected $adminFirewallName;
76
77
    /**
78
     * ToolbarListener constructor.
79
     *
80
     * @param Environment           $twig
81
     * @param UrlGeneratorInterface $urlGenerator
82
     * @param DataCollector         $dataCollector
83
     * @param AuthorizationChecker  $authorizationChecker
84
     * @param TokenStorageInterface $tokenStorage
85
     * @param bool                  $enabled
86
     * @param ContainerInterface    $container
87
     * @param AdminRouteHelper      $adminRouteHelper
88
     * @param array                 $providerKeys
89
     * @param string                $adminFirewallName
90
     */
91
    public function __construct(
92
        Environment $twig,
93
        UrlGeneratorInterface $urlGenerator,
94
        DataCollector $dataCollector,
95
        AuthorizationChecker $authorizationChecker,
96
        TokenStorageInterface $tokenStorage,
97
        $enabled,
98
        ContainerInterface $container,
99
        AdminRouteHelper $adminRouteHelper,
100
        array $providerKeys,
101
        $adminFirewallName = 'main'
102
    ) {
103
        $this->twig = $twig;
104
        $this->urlGenerator = $urlGenerator;
105
        $this->dataCollector = $dataCollector;
106
        $this->authorizationChecker = $authorizationChecker;
107
        $this->tokenStorage = $tokenStorage;
108
        $this->enabled = $enabled;
109
        $this->container = $container;
110
        $this->adminRouteHelper = $adminRouteHelper;
111
        $this->providerKeys = $providerKeys;
112
        $this->adminFirewallName = $adminFirewallName;
0 ignored issues
show
Documentation Bug introduced by
It seems like $adminFirewallName of type string is incompatible with the declared type array of property $adminFirewallName.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
113
    }
114
115
    /**
116
     * @return array
117
     */
118 3
    public static function getSubscribedEvents()
119
    {
120
        return [
121 3
            KernelEvents::RESPONSE => ['onKernelResponse', -125],
122
        ];
123
    }
124
125
    /**
126
     * @return bool
127
     */
128
    public function isEnabled()
129
    {
130
        return !$this->container->has('profiler') && $this->enabled;
131
    }
132
133
    /**
134
     * @param FilterResponseEvent|ResponseEvent $event
135
     */
136
    public function onKernelResponse($event)
137
    {
138 View Code Duplication
        if (!$event instanceof FilterResponseEvent && !$event instanceof ResponseEvent) {
139
            throw new \InvalidArgumentException(\sprintf('Expected instance of type %s, %s given', \class_exists(ResponseEvent::class) ? ResponseEvent::class : FilterResponseEvent::class, \is_object($event) ? \get_class($event) : \gettype($event)));
140
        }
141
142
        if (!$this->isEnabled() || HttpKernel::MASTER_REQUEST !== $event->getRequestType()) {
143
            return;
144
        }
145
146
        $response = $event->getResponse();
147
        $request = $event->getRequest();
148
        $session = $request->getSession();
149
        $url = $event->getRequest()->getRequestUri();
150
        $token = $this->tokenStorage->getToken();
151
152
        if (null !== $token && method_exists($token, 'getProviderKey')) {
153
            $key = $token->getProviderKey();
154
        } else {
155
            $key = $this->adminFirewallName;
156
        }
157
158
        // Only enable toolbar when the kunstmaan_admin.toolbar_firewall_names config value contains the current firewall name.
159
        if (!\in_array($key, $this->providerKeys, false)) {
160
            return false;
161
        }
162
163
        // Only enable toolbar when we can find an authenticated user in the session from the kunstmaan_admin.admin_firewall_name config value.
164
        $authenticated = false;
165
        /* @var PostAuthenticationGuardToken $token */
166
        if ($session->isStarted() && $session->has(sprintf('_security_%s', $this->adminFirewallName))) {
167
            $token = unserialize($session->get(sprintf('_security_%s', $this->adminFirewallName)));
168
            $authenticated = $token->isAuthenticated();
169
        }
170
171
        // Do not capture redirects or modify XML HTTP Requests
172
        if (!$authenticated || !$event->isMasterRequest() || $request->isXmlHttpRequest() || $this->adminRouteHelper->isAdminRoute($url)) {
173
            return;
174
        }
175
176 View Code Duplication
        if ($response->isRedirection() || ($response->headers->has('Content-Type') && false === strpos(
177
                    $response->headers->get('Content-Type'),
178
                    'html'
179
                ))
180
            || 'html' !== $request->getRequestFormat()
181
            || false !== stripos($response->headers->get('Content-Disposition'), 'attachment;')
182
        ) {
183
            return;
184
        }
185
186
        $this->injectToolbar($response, $request);
187
    }
188
189
    /**
190
     * Injects the admin toolbar into the given Response.
191
     *
192
     * @param Response $response A Response instance
193
     */
194
    protected function injectToolbar(Response $response, Request $request)
195
    {
196
        $content = $response->getContent();
197
        $pos = strripos($content, '</body>');
198
199
        if (false !== $pos) {
200
            $toolbar = "\n".str_replace(
201
                    "\n",
202
                    '',
203
                    $this->twig->render(
204
                        '@KunstmaanAdmin/Toolbar/toolbar.html.twig',
205
                        ['collectors' => $this->dataCollector->getDataCollectors()]
206
                    )
207
                )."\n";
208
            $content = substr($content, 0, $pos).$toolbar.substr($content, $pos);
209
            $response->setContent($content);
210
        }
211
    }
212
}
213