f73f3252414711fab4d72b3d8efa8132aeaa9d6f
[yaffs-website] / vendor / symfony / http-kernel / EventListener / ProfilerListener.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
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 Symfony\Component\HttpKernel\EventListener;
13
14 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
15 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
16 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
17 use Symfony\Component\HttpKernel\Event\PostResponseEvent;
18 use Symfony\Component\HttpKernel\KernelEvents;
19 use Symfony\Component\HttpKernel\Profiler\Profiler;
20 use Symfony\Component\HttpFoundation\RequestMatcherInterface;
21 use Symfony\Component\HttpFoundation\RequestStack;
22 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
23
24 /**
25  * ProfilerListener collects data for the current request by listening to the kernel events.
26  *
27  * @author Fabien Potencier <fabien@symfony.com>
28  */
29 class ProfilerListener implements EventSubscriberInterface
30 {
31     protected $profiler;
32     protected $matcher;
33     protected $onlyException;
34     protected $onlyMasterRequests;
35     protected $exception;
36     protected $requests = array();
37     protected $profiles;
38     protected $requestStack;
39     protected $parents;
40
41     /**
42      * Constructor.
43      *
44      * @param Profiler                     $profiler           A Profiler instance
45      * @param RequestStack                 $requestStack       A RequestStack instance
46      * @param RequestMatcherInterface|null $matcher            A RequestMatcher instance
47      * @param bool                         $onlyException      true if the profiler only collects data when an exception occurs, false otherwise
48      * @param bool                         $onlyMasterRequests true if the profiler only collects data when the request is a master request, false otherwise
49      */
50     public function __construct(Profiler $profiler, $requestStack = null, $matcher = null, $onlyException = false, $onlyMasterRequests = false)
51     {
52         if ($requestStack instanceof RequestMatcherInterface || (null !== $matcher && !$matcher instanceof RequestMatcherInterface) || $onlyMasterRequests instanceof RequestStack) {
53             $tmp = $onlyMasterRequests;
54             $onlyMasterRequests = $onlyException;
55             $onlyException = $matcher;
56             $matcher = $requestStack;
57             $requestStack = func_num_args() < 5 ? null : $tmp;
58
59             @trigger_error('The '.__METHOD__.' method now requires a RequestStack to be given as second argument as '.__CLASS__.'::onKernelRequest method will be removed in 3.0.', E_USER_DEPRECATED);
60         } elseif (!$requestStack instanceof RequestStack) {
61             @trigger_error('The '.__METHOD__.' method now requires a RequestStack instance as '.__CLASS__.'::onKernelRequest method will be removed in 3.0.', E_USER_DEPRECATED);
62         }
63
64         if (null !== $requestStack && !$requestStack instanceof RequestStack) {
65             throw new \InvalidArgumentException('RequestStack instance expected.');
66         }
67         if (null !== $matcher && !$matcher instanceof RequestMatcherInterface) {
68             throw new \InvalidArgumentException('Matcher must implement RequestMatcherInterface.');
69         }
70
71         $this->profiler = $profiler;
72         $this->matcher = $matcher;
73         $this->onlyException = (bool) $onlyException;
74         $this->onlyMasterRequests = (bool) $onlyMasterRequests;
75         $this->profiles = new \SplObjectStorage();
76         $this->parents = new \SplObjectStorage();
77         $this->requestStack = $requestStack;
78     }
79
80     /**
81      * Handles the onKernelException event.
82      *
83      * @param GetResponseForExceptionEvent $event A GetResponseForExceptionEvent instance
84      */
85     public function onKernelException(GetResponseForExceptionEvent $event)
86     {
87         if ($this->onlyMasterRequests && !$event->isMasterRequest()) {
88             return;
89         }
90
91         $this->exception = $event->getException();
92     }
93
94     /**
95      * @deprecated since version 2.4, to be removed in 3.0.
96      */
97     public function onKernelRequest(GetResponseEvent $event)
98     {
99         if (null === $this->requestStack) {
100             $this->requests[] = $event->getRequest();
101         }
102     }
103
104     /**
105      * Handles the onKernelResponse event.
106      *
107      * @param FilterResponseEvent $event A FilterResponseEvent instance
108      */
109     public function onKernelResponse(FilterResponseEvent $event)
110     {
111         $master = $event->isMasterRequest();
112         if ($this->onlyMasterRequests && !$master) {
113             return;
114         }
115
116         if ($this->onlyException && null === $this->exception) {
117             return;
118         }
119
120         $request = $event->getRequest();
121         $exception = $this->exception;
122         $this->exception = null;
123
124         if (null !== $this->matcher && !$this->matcher->matches($request)) {
125             return;
126         }
127
128         if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) {
129             return;
130         }
131
132         $this->profiles[$request] = $profile;
133
134         if (null !== $this->requestStack) {
135             $this->parents[$request] = $this->requestStack->getParentRequest();
136         } elseif (!$master) {
137             // to be removed when requestStack is required
138             array_pop($this->requests);
139
140             $this->parents[$request] = end($this->requests);
141         }
142     }
143
144     public function onKernelTerminate(PostResponseEvent $event)
145     {
146         // attach children to parents
147         foreach ($this->profiles as $request) {
148             // isset call should be removed when requestStack is required
149             if (isset($this->parents[$request]) && null !== $parentRequest = $this->parents[$request]) {
150                 if (isset($this->profiles[$parentRequest])) {
151                     $this->profiles[$parentRequest]->addChild($this->profiles[$request]);
152                 }
153             }
154         }
155
156         // save profiles
157         foreach ($this->profiles as $request) {
158             $this->profiler->saveProfile($this->profiles[$request]);
159         }
160
161         $this->profiles = new \SplObjectStorage();
162         $this->parents = new \SplObjectStorage();
163         $this->requests = array();
164     }
165
166     public static function getSubscribedEvents()
167     {
168         return array(
169             // kernel.request must be registered as early as possible to not break
170             // when an exception is thrown in any other kernel.request listener
171             KernelEvents::REQUEST => array('onKernelRequest', 1024),
172             KernelEvents::RESPONSE => array('onKernelResponse', -100),
173             KernelEvents::EXCEPTION => 'onKernelException',
174             KernelEvents::TERMINATE => array('onKernelTerminate', -1024),
175         );
176     }
177 }