4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\HttpKernel\Profiler;
14 use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
15 use Symfony\Component\HttpFoundation\Request;
16 use Symfony\Component\HttpFoundation\Response;
17 use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
18 use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
19 use Psr\Log\LoggerInterface;
24 * @author Fabien Potencier <fabien@symfony.com>
29 * @var ProfilerStorageInterface
34 * @var DataCollectorInterface[]
36 private $collectors = array();
39 * @var LoggerInterface
46 private $enabled = true;
51 * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance
52 * @param LoggerInterface $logger A LoggerInterface instance
54 public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null)
56 $this->storage = $storage;
57 $this->logger = $logger;
61 * Disables the profiler.
63 public function disable()
65 $this->enabled = false;
69 * Enables the profiler.
71 public function enable()
73 $this->enabled = true;
77 * Loads the Profile for the given Response.
79 * @param Response $response A Response instance
81 * @return Profile|false A Profile instance
83 public function loadProfileFromResponse(Response $response)
85 if (!$token = $response->headers->get('X-Debug-Token')) {
89 return $this->loadProfile($token);
93 * Loads the Profile for the given token.
95 * @param string $token A token
97 * @return Profile A Profile instance
99 public function loadProfile($token)
101 return $this->storage->read($token);
107 * @param Profile $profile A Profile instance
111 public function saveProfile(Profile $profile)
114 foreach ($profile->getCollectors() as $collector) {
115 if ($collector instanceof LateDataCollectorInterface) {
116 $collector->lateCollect();
120 if (!($ret = $this->storage->write($profile)) && null !== $this->logger) {
121 $this->logger->warning('Unable to store the profiler information.', array('configured_storage' => get_class($this->storage)));
128 * Purges all data from the storage.
130 public function purge()
132 $this->storage->purge();
136 * Exports the current profiler data.
138 * @param Profile $profile A Profile instance
140 * @return string The exported data
142 * @deprecated since Symfony 2.8, to be removed in 3.0.
144 public function export(Profile $profile)
146 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
148 return base64_encode(serialize($profile));
152 * Imports data into the profiler storage.
154 * @param string $data A data string as exported by the export() method
156 * @return Profile|false A Profile instance
158 * @deprecated since Symfony 2.8, to be removed in 3.0.
160 public function import($data)
162 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
164 $profile = unserialize(base64_decode($data));
166 if ($this->storage->read($profile->getToken())) {
170 $this->saveProfile($profile);
176 * Finds profiler tokens for the given criteria.
178 * @param string $ip The IP
179 * @param string $url The URL
180 * @param string $limit The maximum number of tokens to return
181 * @param string $method The request method
182 * @param string $start The start date to search from
183 * @param string $end The end date to search to
185 * @return array An array of tokens
187 * @see http://php.net/manual/en/datetime.formats.php for the supported date/time formats
189 public function find($ip, $url, $limit, $method, $start, $end)
191 return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end));
195 * Collects data for the given Response.
197 * @param Request $request A Request instance
198 * @param Response $response A Response instance
199 * @param \Exception $exception An exception instance if the request threw one
201 * @return Profile|null A Profile instance or null if the profiler is disabled
203 public function collect(Request $request, Response $response, \Exception $exception = null)
205 if (false === $this->enabled) {
209 $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6));
210 $profile->setTime(time());
211 $profile->setUrl($request->getUri());
212 $profile->setMethod($request->getMethod());
213 $profile->setStatusCode($response->getStatusCode());
215 $profile->setIp($request->getClientIp());
216 } catch (ConflictingHeadersException $e) {
217 $profile->setIp('Unknown');
220 $response->headers->set('X-Debug-Token', $profile->getToken());
222 foreach ($this->collectors as $collector) {
223 $collector->collect($request, $response, $exception);
225 // we need to clone for sub-requests
226 $profile->addCollector(clone $collector);
233 * Gets the Collectors associated with this profiler.
235 * @return array An array of collectors
237 public function all()
239 return $this->collectors;
243 * Sets the Collectors associated with this profiler.
245 * @param DataCollectorInterface[] $collectors An array of collectors
247 public function set(array $collectors = array())
249 $this->collectors = array();
250 foreach ($collectors as $collector) {
251 $this->add($collector);
258 * @param DataCollectorInterface $collector A DataCollectorInterface instance
260 public function add(DataCollectorInterface $collector)
262 $this->collectors[$collector->getName()] = $collector;
266 * Returns true if a Collector for the given name exists.
268 * @param string $name A collector name
272 public function has($name)
274 return isset($this->collectors[$name]);
278 * Gets a Collector by name.
280 * @param string $name A collector name
282 * @return DataCollectorInterface A DataCollectorInterface instance
284 * @throws \InvalidArgumentException if the collector does not exist
286 public function get($name)
288 if (!isset($this->collectors[$name])) {
289 throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));
292 return $this->collectors[$name];
295 private function getTimestamp($value)
297 if (null === $value || '' == $value) {
302 $value = new \DateTime(is_numeric($value) ? '@'.$value : $value);
303 } catch (\Exception $e) {
307 return $value->getTimestamp();