From f405ed6e08fe653fd4e38deaa940ec41de60b9ca Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Tue, 27 Sep 2016 22:54:08 -0400 Subject: [PATCH 1/9] started stubbing out the work to move the profiler out of the httpkernel --- .../Console/Profiler/FileProfilerStorage.php | 284 +++++++++++ .../Component/Console/Profiler/Profile.php | 292 ++++++++++++ .../Component/Console/Profiler/Profiler.php | 270 +++++++++++ .../Profiler/ProfilerStorageInterface.php | 59 +++ .../HttpFoundation/ResponseHeaderBag.php | 2 +- .../Component/Profiler/ConsoleCommandData.php | 75 +++ .../DataCollector/AjaxDataCollector.php | 35 ++ .../DataCollector/ConfigDataCollector.php | 296 ++++++++++++ .../Profiler/DataCollector/DataCollector.php | 103 ++++ .../DataCollector/DataCollectorInterface.php | 41 ++ .../DataCollector/DumpDataCollector.php | 328 +++++++++++++ .../DataCollector/EventDataCollector.php | 110 +++++ .../DataCollector/ExceptionDataCollector.php | 108 +++++ .../LateDataCollectorInterface.php | 25 + .../DataCollector/LoggerDataCollector.php | 186 ++++++++ .../DataCollector/MemoryDataCollector.php | 111 +++++ .../DataCollector/RequestDataCollector.php | 441 ++++++++++++++++++ .../DataCollector/RouterDataCollector.php | 112 +++++ .../DataCollector/TimeDataCollector.php | 147 ++++++ .../Component/Profiler/DataInterface.php | 37 ++ .../Profiler/FileProfilerStorage.php | 284 +++++++++++ src/Symfony/Component/Profiler/Profile.php | 292 ++++++++++++ src/Symfony/Component/Profiler/Profiler.php | 252 ++++++++++ .../Profiler/ProfilerStorageInterface.php | 59 +++ .../Component/Profiler/RequestData.php | 76 +++ 25 files changed, 4024 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Console/Profiler/FileProfilerStorage.php create mode 100644 src/Symfony/Component/Console/Profiler/Profile.php create mode 100644 src/Symfony/Component/Console/Profiler/Profiler.php create mode 100644 src/Symfony/Component/Console/Profiler/ProfilerStorageInterface.php create mode 100644 src/Symfony/Component/Profiler/ConsoleCommandData.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/DataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php create mode 100644 src/Symfony/Component/Profiler/DataInterface.php create mode 100644 src/Symfony/Component/Profiler/FileProfilerStorage.php create mode 100644 src/Symfony/Component/Profiler/Profile.php create mode 100644 src/Symfony/Component/Profiler/Profiler.php create mode 100644 src/Symfony/Component/Profiler/ProfilerStorageInterface.php create mode 100644 src/Symfony/Component/Profiler/RequestData.php diff --git a/src/Symfony/Component/Console/Profiler/FileProfilerStorage.php b/src/Symfony/Component/Console/Profiler/FileProfilerStorage.php new file mode 100644 index 0000000000000..bd8761f5dd8a8 --- /dev/null +++ b/src/Symfony/Component/Console/Profiler/FileProfilerStorage.php @@ -0,0 +1,284 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Profiler; + +/** + * Storage for profiler using files. + * + * @author Alexandre Salomé + */ +class FileProfilerStorage implements ProfilerStorageInterface +{ + /** + * Folder where profiler data are stored. + * + * @var string + */ + private $folder; + + /** + * Constructs the file storage using a "dsn-like" path. + * + * Example : "file:/path/to/the/storage/folder" + * + * @param string $dsn The DSN + * + * @throws \RuntimeException + */ + public function __construct($dsn) + { + if (0 !== strpos($dsn, 'file:')) { + throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn)); + } + $this->folder = substr($dsn, 5); + + if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) { + throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder)); + } + } + + /** + * {@inheritdoc} + */ + public function find($ip, $url, $limit, $method, $start = null, $end = null, $statusCode = null) + { + $file = $this->getIndexFilename(); + + if (!file_exists($file)) { + return array(); + } + + $file = fopen($file, 'r'); + fseek($file, 0, SEEK_END); + + $result = array(); + while (count($result) < $limit && $line = $this->readLineFromFile($file)) { + $values = str_getcsv($line); + list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode) = $values; + $csvTime = (int) $csvTime; + + if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) { + continue; + } + + if (!empty($start) && $csvTime < $start) { + continue; + } + + if (!empty($end) && $csvTime > $end) { + continue; + } + + $result[$csvToken] = array( + 'token' => $csvToken, + 'ip' => $csvIp, + 'method' => $csvMethod, + 'url' => $csvUrl, + 'time' => $csvTime, + 'parent' => $csvParent, + 'status_code' => $csvStatusCode, + ); + } + + fclose($file); + + return array_values($result); + } + + /** + * {@inheritdoc} + */ + public function purge() + { + $flags = \FilesystemIterator::SKIP_DOTS; + $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); + $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); + + foreach ($iterator as $file) { + if (is_file($file)) { + unlink($file); + } else { + rmdir($file); + } + } + } + + /** + * {@inheritdoc} + */ + public function read($token) + { + if (!$token || !file_exists($file = $this->getFilename($token))) { + return; + } + + return $this->createProfileFromData($token, unserialize(file_get_contents($file))); + } + + /** + * {@inheritdoc} + * + * @throws \RuntimeException + */ + public function write(Profile $profile) + { + $file = $this->getFilename($profile->getToken()); + + $profileIndexed = is_file($file); + if (!$profileIndexed) { + // Create directory + $dir = dirname($file); + if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) { + throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir)); + } + } + + // Store profile + $data = array( + 'token' => $profile->getToken(), + 'parent' => $profile->getParentToken(), + 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), + 'data' => $profile->getCollectors(), + 'ip' => $profile->getIp(), + 'method' => $profile->getMethod(), + 'url' => $profile->getUrl(), + 'time' => $profile->getTime(), + 'status_code' => $profile->getStatusCode(), + ); + + if (false === file_put_contents($file, serialize($data))) { + return false; + } + + if (!$profileIndexed) { + // Add to index + if (false === $file = fopen($this->getIndexFilename(), 'a')) { + return false; + } + + fputcsv($file, array( + $profile->getToken(), + $profile->getIp(), + $profile->getMethod(), + $profile->getUrl(), + $profile->getTime(), + $profile->getParentToken(), + $profile->getStatusCode(), + )); + fclose($file); + } + + return true; + } + + /** + * Gets filename to store data, associated to the token. + * + * @param string $token + * + * @return string The profile filename + */ + protected function getFilename($token) + { + // Uses 4 last characters, because first are mostly the same. + $folderA = substr($token, -2, 2); + $folderB = substr($token, -4, 2); + + return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; + } + + /** + * Gets the index filename. + * + * @return string The index filename + */ + protected function getIndexFilename() + { + return $this->folder.'/index.csv'; + } + + /** + * Reads a line in the file, backward. + * + * This function automatically skips the empty lines and do not include the line return in result value. + * + * @param resource $file The file resource, with the pointer placed at the end of the line to read + * + * @return mixed A string representing the line or null if beginning of file is reached + */ + protected function readLineFromFile($file) + { + $line = ''; + $position = ftell($file); + + if (0 === $position) { + return; + } + + while (true) { + $chunkSize = min($position, 1024); + $position -= $chunkSize; + fseek($file, $position); + + if (0 === $chunkSize) { + // bof reached + break; + } + + $buffer = fread($file, $chunkSize); + + if (false === ($upTo = strrpos($buffer, "\n"))) { + $line = $buffer.$line; + continue; + } + + $position += $upTo; + $line = substr($buffer, $upTo + 1).$line; + fseek($file, max(0, $position), SEEK_SET); + + if ('' !== $line) { + break; + } + } + + return '' === $line ? null : $line; + } + + protected function createProfileFromData($token, $data, $parent = null) + { + $profile = new Profile($token); + $profile->setIp($data['ip']); + $profile->setMethod($data['method']); + $profile->setUrl($data['url']); + $profile->setTime($data['time']); + $profile->setStatusCode($data['status_code']); + $profile->setCollectors($data['data']); + + if (!$parent && $data['parent']) { + $parent = $this->read($data['parent']); + } + + if ($parent) { + $profile->setParent($parent); + } + + foreach ($data['children'] as $token) { + if (!$token || !file_exists($file = $this->getFilename($token))) { + continue; + } + + $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile)); + } + + return $profile; + } +} diff --git a/src/Symfony/Component/Console/Profiler/Profile.php b/src/Symfony/Component/Console/Profiler/Profile.php new file mode 100644 index 0000000000000..1ea045a46f251 --- /dev/null +++ b/src/Symfony/Component/Console/Profiler/Profile.php @@ -0,0 +1,292 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Profiler; + +use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; + +/** + * Profile. + * + * @author Fabien Potencier + */ +class Profile +{ + private $token; + + /** + * @var DataCollectorInterface[] + */ + private $collectors = array(); + + private $ip; + private $method; + private $url; + private $time; + private $statusCode; + + /** + * @var Profile + */ + private $parent; + + /** + * @var Profile[] + */ + private $children = array(); + + /** + * Constructor. + * + * @param string $token The token + */ + public function __construct($token) + { + $this->token = $token; + } + + /** + * Sets the token. + * + * @param string $token The token + */ + public function setToken($token) + { + $this->token = $token; + } + + /** + * Gets the token. + * + * @return string The token + */ + public function getToken() + { + return $this->token; + } + + /** + * Sets the parent token. + * + * @param Profile $parent The parent Profile + */ + public function setParent(Profile $parent) + { + $this->parent = $parent; + } + + /** + * Returns the parent profile. + * + * @return Profile The parent profile + */ + public function getParent() + { + return $this->parent; + } + + /** + * Returns the parent token. + * + * @return null|string The parent token + */ + public function getParentToken() + { + return $this->parent ? $this->parent->getToken() : null; + } + + /** + * Returns the IP. + * + * @return string The IP + */ + public function getIp() + { + return $this->ip; + } + + /** + * Sets the IP. + * + * @param string $ip + */ + public function setIp($ip) + { + $this->ip = $ip; + } + + /** + * Returns the request method. + * + * @return string The request method + */ + public function getMethod() + { + return $this->method; + } + + public function setMethod($method) + { + $this->method = $method; + } + + /** + * Returns the URL. + * + * @return string The URL + */ + public function getUrl() + { + return $this->url; + } + + public function setUrl($url) + { + $this->url = $url; + } + + /** + * Returns the time. + * + * @return string The time + */ + public function getTime() + { + if (null === $this->time) { + return 0; + } + + return $this->time; + } + + public function setTime($time) + { + $this->time = $time; + } + + /** + * @param int $statusCode + */ + public function setStatusCode($statusCode) + { + $this->statusCode = $statusCode; + } + + /** + * @return int + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * Finds children profilers. + * + * @return Profile[] An array of Profile + */ + public function getChildren() + { + return $this->children; + } + + /** + * Sets children profiler. + * + * @param Profile[] $children An array of Profile + */ + public function setChildren(array $children) + { + $this->children = array(); + foreach ($children as $child) { + $this->addChild($child); + } + } + + /** + * Adds the child token. + * + * @param Profile $child The child Profile + */ + public function addChild(Profile $child) + { + $this->children[] = $child; + $child->setParent($this); + } + + /** + * Gets a Collector by name. + * + * @param string $name A collector name + * + * @return DataCollectorInterface A DataCollectorInterface instance + * + * @throws \InvalidArgumentException if the collector does not exist + */ + public function getCollector($name) + { + if (!isset($this->collectors[$name])) { + throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); + } + + return $this->collectors[$name]; + } + + /** + * Gets the Collectors associated with this profile. + * + * @return DataCollectorInterface[] + */ + public function getCollectors() + { + return $this->collectors; + } + + /** + * Sets the Collectors associated with this profile. + * + * @param DataCollectorInterface[] $collectors + */ + public function setCollectors(array $collectors) + { + $this->collectors = array(); + foreach ($collectors as $collector) { + $this->addCollector($collector); + } + } + + /** + * Adds a Collector. + * + * @param DataCollectorInterface $collector A DataCollectorInterface instance + */ + public function addCollector(DataCollectorInterface $collector) + { + $this->collectors[$collector->getName()] = $collector; + } + + /** + * Returns true if a Collector for the given name exists. + * + * @param string $name A collector name + * + * @return bool + */ + public function hasCollector($name) + { + return isset($this->collectors[$name]); + } + + public function __sleep() + { + return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode'); + } +} diff --git a/src/Symfony/Component/Console/Profiler/Profiler.php b/src/Symfony/Component/Console/Profiler/Profiler.php new file mode 100644 index 0000000000000..f31e243770cbf --- /dev/null +++ b/src/Symfony/Component/Console/Profiler/Profiler.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Profiler; + +use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; +use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; +use Psr\Log\LoggerInterface; + +/** + * Profiler. + * + * @author Fabien Potencier + */ +class Profiler +{ + /** + * @var ProfilerStorageInterface + */ + private $storage; + + /** + * @var DataCollectorInterface[] + */ + private $collectors = array(); + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var bool + */ + private $enabled = true; + + /** + * Constructor. + * + * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null) + { + $this->storage = $storage; + $this->logger = $logger; + } + + /** + * Disables the profiler. + */ + public function disable() + { + $this->enabled = false; + } + + /** + * Enables the profiler. + */ + public function enable() + { + $this->enabled = true; + } + + /** + * Loads the Profile for the given Response. + * + * @param Response $response A Response instance + * + * @return Profile|false A Profile instance + */ + public function loadProfileFromResponse(Response $response) + { + if (!$token = $response->headers->get('X-Debug-Token')) { + return false; + } + + return $this->loadProfile($token); + } + + /** + * Loads the Profile for the given token. + * + * @param string $token A token + * + * @return Profile A Profile instance + */ + public function loadProfile($token) + { + return $this->storage->read($token); + } + + /** + * Saves a Profile. + * + * @param Profile $profile A Profile instance + * + * @return bool + */ + public function saveProfile(Profile $profile) + { + // late collect + foreach ($profile->getCollectors() as $collector) { + if ($collector instanceof LateDataCollectorInterface) { + $collector->lateCollect(); + } + } + + if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { + $this->logger->warning('Unable to store the profiler information.', array('configured_storage' => get_class($this->storage))); + } + + return $ret; + } + + /** + * Purges all data from the storage. + */ + public function purge() + { + $this->storage->purge(); + } + + /** + * Finds profiler tokens for the given criteria. + * + * @param string $ip The IP + * @param string $url The URL + * @param string $limit The maximum number of tokens to return + * @param string $method The request method + * @param string $start The start date to search from + * @param string $end The end date to search to + * @param string $statusCode The request status code + * + * @return array An array of tokens + * + * @see http://php.net/manual/en/datetime.formats.php for the supported date/time formats + */ + public function find($ip, $url, $limit, $method, $start, $end, $statusCode = null) + { + return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end), $statusCode); + } + + /** + * Collects data for the given Response. + * + * @param Request $request A Request instance + * @param Response $response A Response instance + * @param \Exception $exception An exception instance if the request threw one + * + * @return Profile|null A Profile instance or null if the profiler is disabled + */ + public function collect(Request $request, Response $response, \Exception $exception = null) + { + if (false === $this->enabled) { + return; + } + + $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); + $profile->setTime(time()); + $profile->setUrl($request->getUri()); + $profile->setMethod($request->getMethod()); + $profile->setStatusCode($response->getStatusCode()); + try { + $profile->setIp($request->getClientIp()); + } catch (ConflictingHeadersException $e) { + $profile->setIp('Unknown'); + } + + $response->headers->set('X-Debug-Token', $profile->getToken()); + + foreach ($this->collectors as $collector) { + $collector->collect($request, $response, $exception); + + // we need to clone for sub-requests + $profile->addCollector(clone $collector); + } + + return $profile; + } + + /** + * Gets the Collectors associated with this profiler. + * + * @return array An array of collectors + */ + public function all() + { + return $this->collectors; + } + + /** + * Sets the Collectors associated with this profiler. + * + * @param DataCollectorInterface[] $collectors An array of collectors + */ + public function set(array $collectors = array()) + { + $this->collectors = array(); + foreach ($collectors as $collector) { + $this->add($collector); + } + } + + /** + * Adds a Collector. + * + * @param DataCollectorInterface $collector A DataCollectorInterface instance + */ + public function add(DataCollectorInterface $collector) + { + $this->collectors[$collector->getName()] = $collector; + } + + /** + * Returns true if a Collector for the given name exists. + * + * @param string $name A collector name + * + * @return bool + */ + public function has($name) + { + return isset($this->collectors[$name]); + } + + /** + * Gets a Collector by name. + * + * @param string $name A collector name + * + * @return DataCollectorInterface A DataCollectorInterface instance + * + * @throws \InvalidArgumentException if the collector does not exist + */ + public function get($name) + { + if (!isset($this->collectors[$name])) { + throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); + } + + return $this->collectors[$name]; + } + + private function getTimestamp($value) + { + if (null === $value || '' == $value) { + return; + } + + try { + $value = new \DateTime(is_numeric($value) ? '@'.$value : $value); + } catch (\Exception $e) { + return; + } + + return $value->getTimestamp(); + } +} diff --git a/src/Symfony/Component/Console/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/Console/Profiler/ProfilerStorageInterface.php new file mode 100644 index 0000000000000..ea72af2314f6f --- /dev/null +++ b/src/Symfony/Component/Console/Profiler/ProfilerStorageInterface.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Profiler; + +/** + * ProfilerStorageInterface. + * + * @author Fabien Potencier + */ +interface ProfilerStorageInterface +{ + /** + * Finds profiler tokens for the given criteria. + * + * @param string $ip The IP + * @param string $url The URL + * @param string $limit The maximum number of tokens to return + * @param string $method The request method + * @param int|null $start The start date to search from + * @param int|null $end The end date to search to + * + * @return array An array of tokens + */ + public function find($ip, $url, $limit, $method, $start = null, $end = null); + + /** + * Reads data associated with the given token. + * + * The method returns false if the token does not exist in the storage. + * + * @param string $token A token + * + * @return Profile The profile associated with token + */ + public function read($token); + + /** + * Saves a Profile. + * + * @param Profile $profile A Profile instance + * + * @return bool Write operation successful + */ + public function write(Profile $profile); + + /** + * Purges all data from the database. + */ + public function purge(); +} diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php index 2b630d8a72276..195e45822ef5a 100644 --- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php @@ -181,7 +181,7 @@ public function removeCookie($name, $path = '/', $domain = null) * * @param string $format * - * @return array + * @return array|Cookie[]|Cookie[][][] * * @throws \InvalidArgumentException When the $format is invalid */ diff --git a/src/Symfony/Component/Profiler/ConsoleCommandData.php b/src/Symfony/Component/Profiler/ConsoleCommandData.php new file mode 100644 index 0000000000000..e2cf5c418412b --- /dev/null +++ b/src/Symfony/Component/Profiler/ConsoleCommandData.php @@ -0,0 +1,75 @@ +exception = $exception; + $this->exitCode = $exitCode; + $this->command = $command; + } + + /** + * @return \Exception|\Throwable|null + */ + public function getException() + { + return $this->exception; + } + + /** + * @return null|string + */ + public function getUri() + { + return sprintf('command=>%s', $this->command->getName()); + } + + /** + * @return null|string + */ + public function getStatusCode() + { + return $this->exitCode; + } + + /** + * @return null|string + */ + public function getMethod() + { + return null; + } + + /** + * @return null|string + */ + public function getClientIp() + { + return null; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php new file mode 100644 index 0000000000000..b0460b1f100fd --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; + +/** + * AjaxDataCollector. + * + * @author Bart van den Burg + */ +class AjaxDataCollector extends DataCollector +{ + public function collectData(DataInterface $data, Profile $profile) + { + return $data instanceof RequestData; + } + + public function getName() + { + return 'ajax'; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php new file mode 100644 index 0000000000000..c9c16c720e7e8 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php @@ -0,0 +1,296 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; + +/** + * ConfigDataCollector. + * + * @author Fabien Potencier + */ +class ConfigDataCollector extends DataCollector +{ + /** + * @var KernelInterface + */ + private $kernel; + private $name; + private $version; + private $cacheVersionInfo = true; + + /** + * Constructor. + * + * @param string $name The name of the application using the web profiler + * @param string $version The version of the application using the web profiler + */ + public function __construct($name = null, $version = null) + { + $this->name = $name; + $this->version = $version; + } + + /** + * Sets the Kernel associated with this Request. + * + * @param KernelInterface $kernel A KernelInterface instance + */ + public function setKernel(KernelInterface $kernel = null) + { + $this->kernel = $kernel; + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + $this->data = array( + 'app_name' => $this->name, + 'app_version' => $this->version, + 'token' => $profile->getToken(), + 'symfony_version' => Kernel::VERSION, + 'symfony_state' => 'unknown', + 'name' => isset($this->kernel) ? $this->kernel->getName() : 'n/a', + 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', + 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', + 'php_version' => PHP_VERSION, + 'xdebug_enabled' => extension_loaded('xdebug'), + 'eaccel_enabled' => extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'), + 'apc_enabled' => extension_loaded('apc') && ini_get('apc.enabled'), + 'xcache_enabled' => extension_loaded('xcache') && ini_get('xcache.cacher'), + 'wincache_enabled' => extension_loaded('wincache') && ini_get('wincache.ocenabled'), + 'zend_opcache_enabled' => extension_loaded('Zend OPcache') && ini_get('opcache.enable'), + 'bundles' => array(), + 'sapi_name' => PHP_SAPI, + ); + + if (isset($this->kernel)) { + foreach ($this->kernel->getBundles() as $name => $bundle) { + $this->data['bundles'][$name] = $bundle->getPath(); + } + + $this->data['symfony_state'] = $this->determineSymfonyState(); + } + + return true; + } + + public function getApplicationName() + { + return $this->data['app_name']; + } + + public function getApplicationVersion() + { + return $this->data['app_version']; + } + + /** + * Gets the token. + * + * @return string The token + */ + public function getToken() + { + return $this->data['token']; + } + + /** + * Gets the Symfony version. + * + * @return string The Symfony version + */ + public function getSymfonyVersion() + { + return $this->data['symfony_version']; + } + + /** + * Returns the state of the current Symfony release. + * + * @return string One of: unknown, dev, stable, eom, eol + */ + public function getSymfonyState() + { + return $this->data['symfony_state']; + } + + public function setCacheVersionInfo($cacheVersionInfo) + { + $this->cacheVersionInfo = $cacheVersionInfo; + } + + /** + * Gets the PHP version. + * + * @return string The PHP version + */ + public function getPhpVersion() + { + return $this->data['php_version']; + } + + /** + * Gets the application name. + * + * @return string The application name + */ + public function getAppName() + { + return $this->data['name']; + } + + /** + * Gets the environment. + * + * @return string The environment + */ + public function getEnv() + { + return $this->data['env']; + } + + /** + * Returns true if the debug is enabled. + * + * @return bool true if debug is enabled, false otherwise + */ + public function isDebug() + { + return $this->data['debug']; + } + + /** + * Returns true if the XDebug is enabled. + * + * @return bool true if XDebug is enabled, false otherwise + */ + public function hasXDebug() + { + return $this->data['xdebug_enabled']; + } + + /** + * Returns true if EAccelerator is enabled. + * + * @return bool true if EAccelerator is enabled, false otherwise + */ + public function hasEAccelerator() + { + return $this->data['eaccel_enabled']; + } + + /** + * Returns true if APC is enabled. + * + * @return bool true if APC is enabled, false otherwise + */ + public function hasApc() + { + return $this->data['apc_enabled']; + } + + /** + * Returns true if Zend OPcache is enabled. + * + * @return bool true if Zend OPcache is enabled, false otherwise + */ + public function hasZendOpcache() + { + return $this->data['zend_opcache_enabled']; + } + + /** + * Returns true if XCache is enabled. + * + * @return bool true if XCache is enabled, false otherwise + */ + public function hasXCache() + { + return $this->data['xcache_enabled']; + } + + /** + * Returns true if WinCache is enabled. + * + * @return bool true if WinCache is enabled, false otherwise + */ + public function hasWinCache() + { + return $this->data['wincache_enabled']; + } + + /** + * Returns true if any accelerator is enabled. + * + * @return bool true if any accelerator is enabled, false otherwise + */ + public function hasAccelerator() + { + return $this->hasApc() || $this->hasZendOpcache() || $this->hasEAccelerator() || $this->hasXCache() || $this->hasWinCache(); + } + + public function getBundles() + { + return $this->data['bundles']; + } + + /** + * Gets the PHP SAPI name. + * + * @return string The environment + */ + public function getSapiName() + { + return $this->data['sapi_name']; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'config'; + } + + /** + * Tries to retrieve information about the current Symfony version. + * + * @return string One of: dev, stable, eom, eol + */ + private function determineSymfonyState() + { + $now = new \DateTime(); + $eom = \DateTime::createFromFormat('m/Y', Kernel::END_OF_MAINTENANCE)->modify('last day of this month'); + $eol = \DateTime::createFromFormat('m/Y', Kernel::END_OF_LIFE)->modify('last day of this month'); + + if ($now > $eol) { + $versionState = 'eol'; + } elseif ($now > $eom) { + $versionState = 'eom'; + } elseif ('' !== Kernel::EXTRA_VERSION) { + $versionState = 'dev'; + } else { + $versionState = 'stable'; + } + + return $versionState; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DataCollector.php new file mode 100644 index 0000000000000..1899bb298e0ef --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollector.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; +use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Component\VarDumper\Caster\LinkStub; +use Symfony\Component\VarDumper\Caster\StubCaster; +use Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Cloner\VarCloner; + +/** + * DataCollector. + * + * Children of this class must store the collected data in the data property. + * + * @author Fabien Potencier + * @author Bernhard Schussek + */ +abstract class DataCollector implements DataCollectorInterface, \Serializable +{ + protected $data = array(); + + /** + * @var ClonerInterface + */ + private $cloner; + + public function serialize() + { + return serialize($this->data); + } + + public function unserialize($data) + { + $this->data = unserialize($data); + } + + /** + * Converts the variable into a serializable Data instance. + * + * This array can be displayed in the template using + * the VarDumper component. + * + * @param mixed $var + * + * @return Data + */ + protected function cloneVar($var) + { + if (null === $this->cloner) { + $this->cloner = new VarCloner(); + $this->cloner->setMaxItems(250); + $this->cloner->addCasters(array( + Stub::class => function (Stub $v, array $a, Stub $s, $isNested) { + return $isNested ? $a : StubCaster::castStub($v, $a, $s, true); + }, + )); + } + + return $this->cloner->cloneVar($this->decorateVar($var)); + } + + private function decorateVar($var) + { + if (is_array($var)) { + if (isset($var[0], $var[1]) && is_callable($var)) { + return ClassStub::wrapCallable($var); + } + foreach ($var as $k => $v) { + if ($v !== $d = $this->decorateVar($v)) { + $var[$k] = $d; + } + } + + return $var; + } + if (is_string($var)) { + if (false !== strpos($var, '\\')) { + $c = (false !== $i = strpos($var, '::')) ? substr($var, 0, $i) : $var; + if (class_exists($c, false) || interface_exists($c, false) || trait_exists($c, false)) { + return new ClassStub($var); + } + } + if (false !== strpos($var, DIRECTORY_SEPARATOR) && file_exists($var)) { + return new LinkStub($var); + } + } + + return $var; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php new file mode 100644 index 0000000000000..a349ae52f0b5a --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; + +/** + * DataCollectorInterface. + * + * @author Fabien Potencier + */ +interface DataCollectorInterface +{ + /** + * Collects data for the given Request and Response. + * + * @param DataInterface $data + * @param Profile $profile + * @return + */ + public function collectData(DataInterface $data, Profile $profile); + + /** + * Returns the name of the collector. + * + * @return string The collector name + */ + public function getName(); +} diff --git a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php new file mode 100644 index 0000000000000..f917166f61938 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php @@ -0,0 +1,328 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\ConsoleCommandData; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Dumper\DataDumperInterface; + +/** + * @author Nicolas Grekas + */ +class DumpDataCollector extends DataCollector implements DataDumperInterface +{ + private $stopwatch; + private $fileLinkFormat; + private $dataCount = 0; + private $isCollected = true; + private $clonesCount = 0; + private $clonesIndex = 0; + private $rootRefs; + private $charset; + private $requestStack; + private $dumper; + private $dumperIsInjected; + + public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, $charset = null, RequestStack $requestStack = null, DataDumperInterface $dumper = null) + { + $fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); + if ($fileLinkFormat && !is_array($fileLinkFormat)) { + $i = max(strpos($fileLinkFormat, '%f'), strpos($fileLinkFormat, '%l')); + $i = strpos($fileLinkFormat, '#"', $i) ?: strlen($fileLinkFormat); + $fileLinkFormat = array(substr($fileLinkFormat, 0, $i), substr($fileLinkFormat, $i + 1)); + $fileLinkFormat[1] = @json_decode('{'.$fileLinkFormat[1].'}', true) ?: array(); + } + $this->stopwatch = $stopwatch; + $this->fileLinkFormat = $fileLinkFormat; + $this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'; + $this->requestStack = $requestStack; + $this->dumper = $dumper; + $this->dumperIsInjected = null !== $dumper; + + // All clones share these properties by reference: + $this->rootRefs = array( + &$this->data, + &$this->dataCount, + &$this->isCollected, + &$this->clonesCount, + ); + } + + public function __clone() + { + $this->clonesIndex = ++$this->clonesCount; + } + + public function dump(Data $data) + { + if ($this->stopwatch) { + $this->stopwatch->start('dump'); + } + if ($this->isCollected) { + $this->isCollected = false; + } + + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 7); + + $file = $trace[0]['file']; + $line = $trace[0]['line']; + $name = false; + $fileExcerpt = false; + + for ($i = 1; $i < 7; ++$i) { + if (isset($trace[$i]['class'], $trace[$i]['function']) + && 'dump' === $trace[$i]['function'] + && 'Symfony\Component\VarDumper\VarDumper' === $trace[$i]['class'] + ) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + while (++$i < 7) { + if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + break; + } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof \Twig_Template) { + $info = $trace[$i]['object']; + $name = $info->getTemplateName(); + $src = method_exists($info, 'getSource') ? $info->getSource() : $info->getEnvironment()->getLoader()->getSource($name); + $info = $info->getDebugInfo(); + if (null !== $src && isset($info[$trace[$i - 1]['line']])) { + $file = false; + $line = $info[$trace[$i - 1]['line']]; + $src = explode("\n", $src); + $fileExcerpt = array(); + + for ($i = max($line - 3, 1), $max = min($line + 3, count($src)); $i <= $max; ++$i) { + $fileExcerpt[] = ''.$this->htmlEncode($src[$i - 1]).''; + } + + $fileExcerpt = '
    '.implode("\n", $fileExcerpt).'
'; + } + break; + } + } + break; + } + } + + if (false === $name) { + $name = str_replace('\\', '/', $file); + $name = substr($name, strrpos($name, '/') + 1); + } + + if ($this->dumper) { + $this->doDump($data, $name, $file, $line); + } + + $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); + ++$this->dataCount; + + if ($this->stopwatch) { + $this->stopwatch->stop('dump'); + } + } + + public function collectData(DataInterface $data, Profile $profile) + { + // Sub-requests and programmatic calls stay in the collected profile. + if ($this->dumper) { + return true; + } + + if ($data instanceof RequestData) { + $request = $data->getRequest(); + + if (($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { + return true; + } + } + + // In all other conditions that remove the web debug toolbar, dumps are written on the output. + if (!$data instanceof RequestData + || !$this->requestStack + || !$data->getResponse()->headers->has('X-Debug-Token') + || $data->getResponse()->isRedirection() + || ($data->getResponse()->headers->has('Content-Type') && false === strpos($data->getResponse()->headers->get('Content-Type'), 'html')) + || 'html' !== $data->getRequest()->getRequestFormat() + || false === strripos($data->getResponse()->getContent(), '') + ) { + if ($data instanceof RequestData && $data->getResponse()->headers->has('Content-Type') && false !== strpos($data->getResponse()->headers->get('Content-Type'), 'html')) { + $this->dumper = new HtmlDumper('php://output', $this->charset); + $this->dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + } else { + $this->dumper = new CliDumper('php://output', $this->charset); + } + + foreach ($this->data as $dump) { + $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + } + } + + return true; + } + + public function serialize() + { + if ($this->clonesCount !== $this->clonesIndex) { + return 'a:0:{}'; + } + + $this->data[] = $this->fileLinkFormat; + $this->data[] = $this->charset; + $ser = serialize($this->data); + $this->data = array(); + $this->dataCount = 0; + $this->isCollected = true; + if (!$this->dumperIsInjected) { + $this->dumper = null; + } + + return $ser; + } + + public function unserialize($data) + { + parent::unserialize($data); + $charset = array_pop($this->data); + $fileLinkFormat = array_pop($this->data); + $this->dataCount = count($this->data); + self::__construct($this->stopwatch, $fileLinkFormat, $charset); + } + + public function getDumpsCount() + { + return $this->dataCount; + } + + public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1) + { + $data = fopen('php://memory', 'r+b'); + + if ('html' === $format) { + $dumper = new HtmlDumper($data, $this->charset); + $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + } else { + throw new \InvalidArgumentException(sprintf('Invalid dump format: %s', $format)); + } + $dumps = array(); + + foreach ($this->data as $dump) { + $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth)); + $dump['data'] = stream_get_contents($data, -1, 0); + ftruncate($data, 0); + rewind($data); + $dumps[] = $dump; + } + + return $dumps; + } + + public function getName() + { + return 'dump'; + } + + public function __destruct() + { + if (0 === $this->clonesCount-- && !$this->isCollected && $this->data) { + $this->clonesCount = 0; + $this->isCollected = true; + + $h = headers_list(); + $i = count($h); + array_unshift($h, 'Content-Type: '.ini_get('default_mimetype')); + while (0 !== stripos($h[$i], 'Content-Type:')) { + --$i; + } + + if ('cli' !== PHP_SAPI && stripos($h[$i], 'html')) { + $this->dumper = new HtmlDumper('php://output', $this->charset); + $this->dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + } else { + $this->dumper = new CliDumper('php://output', $this->charset); + } + + foreach ($this->data as $i => $dump) { + $this->data[$i] = null; + $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + } + + $this->data = array(); + $this->dataCount = 0; + } + } + + private function doDump($data, $name, $file, $line) + { + if ($this->dumper instanceof CliDumper) { + $contextDumper = function ($name, $file, $line, $fileLinkFormat) { + if ($this instanceof HtmlDumper) { + if ('' !== $file) { + $s = $this->style('meta', '%s'); + $name = strip_tags($this->style('', $name)); + $file = strip_tags($this->style('', $file)); + if ($fileLinkFormat) { + foreach ($fileLinkFormat[1] as $k => $v) { + if (0 === strpos($file, $k)) { + $file = substr_replace($file, $v, 0, strlen($k)); + break; + } + } + $link = strtr(strip_tags($this->style('', $fileLinkFormat[0])), array('%f' => $file, '%l' => (int) $line)); + $name = sprintf(''.$s.'', $link, $file, $name); + } else { + $name = sprintf(''.$s.'', $file, $name); + } + } else { + $name = $this->style('meta', $name); + } + $this->line = $name.' on line '.$this->style('meta', $line).':'; + } else { + $this->line = $this->style('meta', $name).' on line '.$this->style('meta', $line).':'; + } + $this->dumpLine(0); + }; + $contextDumper = $contextDumper->bindTo($this->dumper, $this->dumper); + $contextDumper($name, $file, $line, $this->fileLinkFormat); + } else { + $cloner = new VarCloner(); + $this->dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); + } + $this->dumper->dump($data); + } + + private function htmlEncode($s) + { + $html = ''; + + $dumper = new HtmlDumper(function ($line) use (&$html) {$html .= $line;}, $this->charset); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + + $cloner = new VarCloner(); + $dumper->dump($cloner->cloneVar($s)); + + return substr(strip_tags($html), 1, -1); + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php new file mode 100644 index 0000000000000..06b4f8997e3d9 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; + +/** + * EventDataCollector. + * + * @author Fabien Potencier + */ +class EventDataCollector extends DataCollector implements LateDataCollectorInterface +{ + protected $dispatcher; + + public function __construct(EventDispatcherInterface $dispatcher = null) + { + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + $this->data = array( + 'called_listeners' => array(), + 'not_called_listeners' => array(), + ); + return true; + } + + public function lateCollect() + { + if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { + $this->setCalledListeners($this->dispatcher->getCalledListeners()); + $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners()); + } + } + + /** + * Sets the called listeners. + * + * @param array $listeners An array of called listeners + * + * @see TraceableEventDispatcherInterface + */ + public function setCalledListeners(array $listeners) + { + $this->data['called_listeners'] = $listeners; + } + + /** + * Gets the called listeners. + * + * @return array An array of called listeners + * + * @see TraceableEventDispatcherInterface + */ + public function getCalledListeners() + { + return $this->data['called_listeners']; + } + + /** + * Sets the not called listeners. + * + * @param array $listeners An array of not called listeners + * + * @see TraceableEventDispatcherInterface + */ + public function setNotCalledListeners(array $listeners) + { + $this->data['not_called_listeners'] = $listeners; + } + + /** + * Gets the not called listeners. + * + * @return array An array of not called listeners + * + * @see TraceableEventDispatcherInterface + */ + public function getNotCalledListeners() + { + return $this->data['not_called_listeners']; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'events'; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php new file mode 100644 index 0000000000000..9d2ad7c1754ee --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; + +/** + * ExceptionDataCollector. + * + * @author Fabien Potencier + */ +class ExceptionDataCollector extends DataCollector +{ + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + if (null !== $data->getException()) { + $this->data = array( + 'exception' => FlattenException::create($data->getException()), + ); + } + + return true; + } + + /** + * Checks if the exception is not null. + * + * @return bool true if the exception is not null, false otherwise + */ + public function hasException() + { + return isset($this->data['exception']); + } + + /** + * Gets the exception. + * + * @return \Exception The exception + */ + public function getException() + { + return $this->data['exception']; + } + + /** + * Gets the exception message. + * + * @return string The exception message + */ + public function getMessage() + { + return $this->data['exception']->getMessage(); + } + + /** + * Gets the exception code. + * + * @return int The exception code + */ + public function getCode() + { + return $this->data['exception']->getCode(); + } + + /** + * Gets the status code. + * + * @return int The status code + */ + public function getStatusCode() + { + return $this->data['exception']->getStatusCode(); + } + + /** + * Gets the exception trace. + * + * @return array The exception trace + */ + public function getTrace() + { + return $this->data['exception']->getTrace(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'exception'; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php new file mode 100644 index 0000000000000..4c822ec520cfa --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +/** + * LateDataCollectorInterface. + * + * @author Fabien Potencier + */ +interface LateDataCollectorInterface +{ + /** + * Collects data as late as possible. + */ + public function lateCollect(); +} diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php new file mode 100644 index 0000000000000..7272f7a3869e4 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\Debug\Exception\SilencedErrorContext; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; + +/** + * LogDataCollector. + * + * @author Fabien Potencier + */ +class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface +{ + private $logger; + + public function __construct($logger = null) + { + if (null !== $logger && $logger instanceof DebugLoggerInterface) { + $this->logger = $logger; + } + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function lateCollect() + { + if (null !== $this->logger) { + $this->data = $this->computeErrorsCount(); + $this->data['logs'] = $this->sanitizeLogs($this->logger->getLogs()); + } + } + + /** + * Gets the logs. + * + * @return array An array of logs + */ + public function getLogs() + { + return isset($this->data['logs']) ? $this->data['logs'] : array(); + } + + public function getPriorities() + { + return isset($this->data['priorities']) ? $this->data['priorities'] : array(); + } + + public function countErrors() + { + return isset($this->data['error_count']) ? $this->data['error_count'] : 0; + } + + public function countDeprecations() + { + return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0; + } + + public function countWarnings() + { + return isset($this->data['warning_count']) ? $this->data['warning_count'] : 0; + } + + public function countScreams() + { + return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'logger'; + } + + private function sanitizeLogs($logs) + { + $sanitizedLogs = array(); + + foreach ($logs as $log) { + if (!$this->isSilencedOrDeprecationErrorLog($log)) { + $log['context'] = $log['context'] ? $this->cloneVar($log['context']) : $log['context']; + $sanitizedLogs[] = $log; + + continue; + } + + $exception = $log['context']['exception']; + $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}".($exception instanceof \Exception ? "\0".$exception->getMessage() : ''), true); + + if (isset($sanitizedLogs[$errorId])) { + ++$sanitizedLogs[$errorId]['errorCount']; + } else { + $log['context'] = $log['context'] ? $this->cloneVar($log['context']) : $log['context']; + + $log += array( + 'errorCount' => 1, + 'scream' => $exception instanceof SilencedErrorContext, + ); + + $sanitizedLogs[$errorId] = $log; + } + } + + return array_values($sanitizedLogs); + } + + private function isSilencedOrDeprecationErrorLog(array $log) + { + if (!isset($log['context']['exception'])) { + return false; + } + + $exception = $log['context']['exception']; + + if ($exception instanceof SilencedErrorContext) { + return true; + } + + if ($exception instanceof \ErrorException && in_array($exception->getSeverity(), array(E_DEPRECATED, E_USER_DEPRECATED), true)) { + return true; + } + + return false; + } + + private function computeErrorsCount() + { + $count = array( + 'error_count' => $this->logger->countErrors(), + 'deprecation_count' => 0, + 'warning_count' => 0, + 'scream_count' => 0, + 'priorities' => array(), + ); + + foreach ($this->logger->getLogs() as $log) { + if (isset($count['priorities'][$log['priority']])) { + ++$count['priorities'][$log['priority']]['count']; + } else { + $count['priorities'][$log['priority']] = array( + 'count' => 1, + 'name' => $log['priorityName'], + ); + } + if ('WARNING' === $log['priorityName']) { + ++$count['warning_count']; + } + + if ($this->isSilencedOrDeprecationErrorLog($log)) { + if ($log['context']['exception'] instanceof SilencedErrorContext) { + ++$count['scream_count']; + } else { + ++$count['deprecation_count']; + } + } + } + + ksort($count['priorities']); + + return $count; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php new file mode 100644 index 0000000000000..20def98bda476 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; + +/** + * MemoryDataCollector. + * + * @author Fabien Potencier + */ +class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface +{ + public function __construct() + { + $this->data = array( + 'memory' => 0, + 'memory_limit' => $this->convertToBytes(ini_get('memory_limit')), + ); + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + $this->updateMemoryUsage(); + return true; + } + + /** + * {@inheritdoc} + */ + public function lateCollect() + { + $this->updateMemoryUsage(); + } + + /** + * Gets the memory. + * + * @return int The memory + */ + public function getMemory() + { + return $this->data['memory']; + } + + /** + * Gets the PHP memory limit. + * + * @return int The memory limit + */ + public function getMemoryLimit() + { + return $this->data['memory_limit']; + } + + /** + * Updates the memory usage data. + */ + public function updateMemoryUsage() + { + $this->data['memory'] = memory_get_peak_usage(true); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'memory'; + } + + private function convertToBytes($memoryLimit) + { + if ('-1' === $memoryLimit) { + return -1; + } + + $memoryLimit = strtolower($memoryLimit); + $max = strtolower(ltrim($memoryLimit, '+')); + if (0 === strpos($max, '0x')) { + $max = intval($max, 16); + } elseif (0 === strpos($max, '0')) { + $max = intval($max, 8); + } else { + $max = (int) $max; + } + + switch (substr($memoryLimit, -1)) { + case 't': $max *= 1024; + case 'g': $max *= 1024; + case 'm': $max *= 1024; + case 'k': $max *= 1024; + } + + return $max; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php new file mode 100644 index 0000000000000..5f67d4c5a1b24 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php @@ -0,0 +1,441 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\ParameterBag; +use Symfony\Component\HttpFoundation\HeaderBag; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Event\FilterControllerEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Routing\Route; + +/** + * RequestDataCollector. + * + * @author Fabien Potencier + */ +class RequestDataCollector extends DataCollector implements EventSubscriberInterface +{ + /** @var \SplObjectStorage */ + protected $controllers; + + public function __construct() + { + $this->controllers = new \SplObjectStorage(); + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + if (!$data instanceof RequestData) { + return false; + } + + $response = $data->getResponse(); + $request = $data->getRequest(); + $responseHeaders = $response->headers->all(); + $cookies = array(); + foreach ($response->headers->getCookies() as $cookie) { + $cookies[] = $this->getCookieHeader( + $cookie->getName(), + $cookie->getValue(), + $cookie->getExpiresTime(), + $cookie->getPath(), + $cookie->getDomain(), + $cookie->isSecure(), + $cookie->isHttpOnly() + ); + } + if (count($cookies) > 0) { + $responseHeaders['Set-Cookie'] = $cookies; + } + + // attributes are serialized and as they can be anything, they need to be converted to strings. + $attributes = array(); + $route = ''; + foreach ($request->attributes->all() as $key => $value) { + if ('_route' === $key && $value instanceof Route) { + $attributes[$key] = $this->cloneVar($value->getPath()); + } else { + $attributes[$key] = $this->cloneVar($value); + } + + if ('_route' === $key) { + $route = $value instanceof Route ? $value->getPath() : $value; + } + } + + $content = null; + try { + $content = $request->getContent(); + } catch (\LogicException $e) { + // the user already got the request content as a resource + $content = false; + } + + $sessionMetadata = array(); + $sessionAttributes = array(); + $session = null; + $flashes = array(); + if ($request->hasSession()) { + $session = $request->getSession(); + if ($session->isStarted()) { + $sessionMetadata['Created'] = date(DATE_RFC822, $session->getMetadataBag()->getCreated()); + $sessionMetadata['Last used'] = date(DATE_RFC822, $session->getMetadataBag()->getLastUsed()); + $sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime(); + $sessionAttributes = $session->all(); + $flashes = $session->getFlashBag()->peekAll(); + } + } + + $statusCode = $response->getStatusCode(); + + $this->data = array( + 'method' => $request->getMethod(), + 'format' => $request->getRequestFormat(), + 'content' => $content, + 'content_type' => $response->headers->get('Content-Type', 'text/html'), + 'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '', + 'status_code' => $statusCode, + 'request_query' => array_map(array($this, 'cloneVar'), $request->query->all()), + 'request_request' => array_map(array($this, 'cloneVar'), $request->request->all()), + 'request_headers' => $request->headers->all(), + 'request_server' => $request->server->all(), + 'request_cookies' => $request->cookies->all(), + 'request_attributes' => $attributes, + 'route' => $route, + 'response_headers' => $responseHeaders, + 'session_metadata' => $sessionMetadata, + 'session_attributes' => $sessionAttributes, + 'flashes' => $flashes, + 'path_info' => $request->getPathInfo(), + 'controller' => 'n/a', + 'locale' => $request->getLocale(), + ); + + if (isset($this->data['request_headers']['php-auth-pw'])) { + $this->data['request_headers']['php-auth-pw'] = '******'; + } + + if (isset($this->data['request_server']['PHP_AUTH_PW'])) { + $this->data['request_server']['PHP_AUTH_PW'] = '******'; + } + + if (isset($this->data['request_request']['_password'])) { + $this->data['request_request']['_password'] = '******'; + } + + if (isset($this->controllers[$request])) { + $this->data['controller'] = $this->parseController($this->controllers[$request]); + unset($this->controllers[$request]); + } + + if (null !== $session && $session->isStarted()) { + if ($request->attributes->has('_redirected')) { + $this->data['redirect'] = $session->remove('sf_redirect'); + } + + if ($response->isRedirect()) { + $session->set('sf_redirect', array( + 'token' => $response->headers->get('x-debug-token'), + 'route' => $request->attributes->get('_route', 'n/a'), + 'method' => $request->getMethod(), + 'controller' => $this->parseController($request->attributes->get('_controller')), + 'status_code' => $statusCode, + 'status_text' => Response::$statusTexts[(int) $statusCode], + )); + } + } + + return true; + } + + public function getMethod() + { + return $this->data['method']; + } + + public function getPathInfo() + { + return $this->data['path_info']; + } + + public function getRequestRequest() + { + return new ParameterBag($this->data['request_request']); + } + + public function getRequestQuery() + { + return new ParameterBag($this->data['request_query']); + } + + public function getRequestHeaders() + { + return new HeaderBag($this->data['request_headers']); + } + + public function getRequestServer() + { + return new ParameterBag($this->data['request_server']); + } + + public function getRequestCookies() + { + return new ParameterBag($this->data['request_cookies']); + } + + public function getRequestAttributes() + { + return new ParameterBag($this->data['request_attributes']); + } + + public function getResponseHeaders() + { + return new ResponseHeaderBag($this->data['response_headers']); + } + + public function getSessionMetadata() + { + return $this->data['session_metadata']; + } + + public function getSessionAttributes() + { + return $this->data['session_attributes']; + } + + public function getFlashes() + { + return $this->data['flashes']; + } + + public function getContent() + { + return $this->data['content']; + } + + public function getContentType() + { + return $this->data['content_type']; + } + + public function getStatusText() + { + return $this->data['status_text']; + } + + public function getStatusCode() + { + return $this->data['status_code']; + } + + public function getFormat() + { + return $this->data['format']; + } + + public function getLocale() + { + return $this->data['locale']; + } + + /** + * Gets the route name. + * + * The _route request attributes is automatically set by the Router Matcher. + * + * @return string The route + */ + public function getRoute() + { + return $this->data['route']; + } + + public function getIdentifier() + { + return $this->data['route'] ?: (is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']); + } + + /** + * Gets the route parameters. + * + * The _route_params request attributes is automatically set by the RouterListener. + * + * @return array The parameters + */ + public function getRouteParams() + { + return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params'] : $this->cloneVar(array()); + } + + /** + * Gets the parsed controller. + * + * @return array|string The controller as a string or array of data + * with keys 'class', 'method', 'file' and 'line' + */ + public function getController() + { + return $this->data['controller']; + } + + /** + * Gets the previous request attributes. + * + * @return array|bool A legacy array of data from the previous redirection response + * or false otherwise + */ + public function getRedirect() + { + return isset($this->data['redirect']) ? $this->data['redirect'] : false; + } + + public function onKernelController(FilterControllerEvent $event) + { + $this->controllers[$event->getRequest()] = $event->getController(); + } + + public function onKernelResponse(FilterResponseEvent $event) + { + if (!$event->isMasterRequest() || !$event->getRequest()->hasSession() || !$event->getRequest()->getSession()->isStarted()) { + return; + } + + if ($event->getRequest()->getSession()->has('sf_redirect')) { + $event->getRequest()->attributes->set('_redirected', true); + } + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::CONTROLLER => 'onKernelController', + KernelEvents::RESPONSE => 'onKernelResponse', + ); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'request'; + } + + /** + * Parse a controller. + * + * @param mixed $controller The controller to parse + * + * @return array|string An array of controller data or a simple string + */ + protected function parseController($controller) + { + if (is_string($controller) && false !== strpos($controller, '::')) { + $controller = explode('::', $controller); + } + + if (is_array($controller)) { + try { + $r = new \ReflectionMethod($controller[0], $controller[1]); + + return array( + 'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0], + 'method' => $controller[1], + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ); + } catch (\ReflectionException $e) { + if (is_callable($controller)) { + // using __call or __callStatic + return array( + 'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0], + 'method' => $controller[1], + 'file' => 'n/a', + 'line' => 'n/a', + ); + } + } + } + + if ($controller instanceof \Closure) { + $r = new \ReflectionFunction($controller); + + return array( + 'class' => $r->getName(), + 'method' => null, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ); + } + + if (is_object($controller)) { + $r = new \ReflectionClass($controller); + + return array( + 'class' => $r->getName(), + 'method' => null, + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ); + } + + return (string) $controller ?: 'n/a'; + } + + private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly) + { + $cookie = sprintf('%s=%s', $name, urlencode($value)); + + if (0 !== $expires) { + if (is_numeric($expires)) { + $expires = (int) $expires; + } elseif ($expires instanceof \DateTime) { + $expires = $expires->getTimestamp(); + } else { + $tmp = strtotime($expires); + if (false === $tmp || -1 == $tmp) { + throw new \InvalidArgumentException(sprintf('The "expires" cookie parameter is not valid (%s).', $expires)); + } + $expires = $tmp; + } + + $cookie .= '; expires='.str_replace('+0000', '', \DateTime::createFromFormat('U', $expires, new \DateTimeZone('GMT'))->format('D, d-M-Y H:i:s T')); + } + + if ($domain) { + $cookie .= '; domain='.$domain; + } + + $cookie .= '; path='.$path; + + if ($secure) { + $cookie .= '; secure'; + } + + if ($httponly) { + $cookie .= '; httponly'; + } + + return $cookie; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php new file mode 100644 index 0000000000000..bcd6f6cad33d9 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpKernel\Event\FilterControllerEvent; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; + +/** + * RouterDataCollector. + * + * @author Fabien Potencier + */ +class RouterDataCollector extends DataCollector +{ + protected $controllers; + + public function __construct() + { + $this->controllers = new \SplObjectStorage(); + + $this->data = array( + 'redirect' => false, + 'url' => null, + 'route' => null, + ); + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + if (!$data instanceof RequestData) { + return false; + } + + $request = $data->getRequest(); + $response = $data->getResponse(); + + if ($response instanceof RedirectResponse) { + $this->data['redirect'] = true; + $this->data['url'] = $response->getTargetUrl(); + + if ($this->controllers->contains($request)) { + $this->data['route'] = $this->guessRoute($request, $this->controllers[$request]); + } + } + + unset($this->controllers[$request]); + } + + protected function guessRoute(Request $request, $controller) + { + return 'n/a'; + } + + /** + * Remembers the controller associated to each request. + * + * @param FilterControllerEvent $event The filter controller event + */ + public function onKernelController(FilterControllerEvent $event) + { + $this->controllers[$event->getRequest()] = $event->getController(); + } + + /** + * @return bool Whether this request will result in a redirect + */ + public function getRedirect() + { + return $this->data['redirect']; + } + + /** + * @return string|null The target URL + */ + public function getTargetUrl() + { + return $this->data['url']; + } + + /** + * @return string|null The target route + */ + public function getTargetRoute() + { + return $this->data['route']; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'router'; + } +} diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php new file mode 100644 index 0000000000000..c37c2523f35b2 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * TimeDataCollector. + * + * @author Fabien Potencier + */ +class TimeDataCollector extends DataCollector implements LateDataCollectorInterface +{ + protected $kernel; + protected $stopwatch; + + public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null) + { + $this->kernel = $kernel; + $this->stopwatch = $stopwatch; + } + + /** + * {@inheritdoc} + */ + public function collectData(DataInterface $data, Profile $profile) + { + if (null !== $this->kernel) { + $startTime = $this->kernel->getStartTime(); + } else { + if ($data instanceof RequestData) { + $request = $data->getRequest(); + } else { + $request = Request::createFromGlobals(); + } + + $startTime = $request->server->get('REQUEST_TIME_FLOAT', $request->server->get('REQUEST_TIME')); + } + + $this->data = array( + 'token' => $profile->getToken(), + 'start_time' => $startTime * 1000, + 'events' => array(), + ); + return true; + } + + /** + * {@inheritdoc} + */ + public function lateCollect() + { + if (null !== $this->stopwatch && isset($this->data['token'])) { + $this->setEvents($this->stopwatch->getSectionEvents($this->data['token'])); + } + unset($this->data['token']); + } + + /** + * Sets the request events. + * + * @param array $events The request events + */ + public function setEvents(array $events) + { + foreach ($events as $event) { + $event->ensureStopped(); + } + + $this->data['events'] = $events; + } + + /** + * Gets the request events. + * + * @return array The request events + */ + public function getEvents() + { + return $this->data['events']; + } + + /** + * Gets the request elapsed time. + * + * @return float The elapsed time + */ + public function getDuration() + { + if (!isset($this->data['events']['__section__'])) { + return 0; + } + + $lastEvent = $this->data['events']['__section__']; + + return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime(); + } + + /** + * Gets the initialization time. + * + * This is the time spent until the beginning of the request handling. + * + * @return float The elapsed time + */ + public function getInitTime() + { + if (!isset($this->data['events']['__section__'])) { + return 0; + } + + return $this->data['events']['__section__']->getOrigin() - $this->getStartTime(); + } + + /** + * Gets the request time. + * + * @return int The time + */ + public function getStartTime() + { + return $this->data['start_time']; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'time'; + } +} diff --git a/src/Symfony/Component/Profiler/DataInterface.php b/src/Symfony/Component/Profiler/DataInterface.php new file mode 100644 index 0000000000000..62b8bdc5bd625 --- /dev/null +++ b/src/Symfony/Component/Profiler/DataInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler; + +/** + * Storage for profiler using files. + * + * @author Alexandre Salomé + */ +class FileProfilerStorage implements ProfilerStorageInterface +{ + /** + * Folder where profiler data are stored. + * + * @var string + */ + private $folder; + + /** + * Constructs the file storage using a "dsn-like" path. + * + * Example : "file:/path/to/the/storage/folder" + * + * @param string $dsn The DSN + * + * @throws \RuntimeException + */ + public function __construct($dsn) + { + if (0 !== strpos($dsn, 'file:')) { + throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn)); + } + $this->folder = substr($dsn, 5); + + if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) { + throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder)); + } + } + + /** + * {@inheritdoc} + */ + public function find($ip, $url, $limit, $method, $statusCode, $start = null, $end = null) + { + $file = $this->getIndexFilename(); + + if (!file_exists($file)) { + return array(); + } + + $file = fopen($file, 'r'); + fseek($file, 0, SEEK_END); + + $result = array(); + while (count($result) < $limit && $line = $this->readLineFromFile($file)) { + $values = str_getcsv($line); + list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode) = $values; + $csvTime = (int) $csvTime; + + if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) { + continue; + } + + if (!empty($start) && $csvTime < $start) { + continue; + } + + if (!empty($end) && $csvTime > $end) { + continue; + } + + $result[$csvToken] = array( + 'token' => $csvToken, + 'ip' => $csvIp, + 'method' => $csvMethod, + 'url' => $csvUrl, + 'time' => $csvTime, + 'parent' => $csvParent, + 'status_code' => $csvStatusCode, + ); + } + + fclose($file); + + return array_values($result); + } + + /** + * {@inheritdoc} + */ + public function purge() + { + $flags = \FilesystemIterator::SKIP_DOTS; + $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); + $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); + + foreach ($iterator as $file) { + if (is_file($file)) { + unlink($file); + } else { + rmdir($file); + } + } + } + + /** + * {@inheritdoc} + */ + public function read($token) + { + if (!$token || !file_exists($file = $this->getFilename($token))) { + return; + } + + return $this->createProfileFromData($token, unserialize(file_get_contents($file))); + } + + /** + * {@inheritdoc} + * + * @throws \RuntimeException + */ + public function write(Profile $profile) + { + $file = $this->getFilename($profile->getToken()); + + $profileIndexed = is_file($file); + if (!$profileIndexed) { + // Create directory + $dir = dirname($file); + if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) { + throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir)); + } + } + + // Store profile + $data = array( + 'token' => $profile->getToken(), + 'parent' => $profile->getParentToken(), + 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), + 'data' => $profile->getCollectors(), + 'ip' => $profile->getIp(), + 'method' => $profile->getMethod(), + 'url' => $profile->getUrl(), + 'time' => $profile->getTime(), + 'status_code' => $profile->getStatusCode(), + ); + + if (false === file_put_contents($file, serialize($data))) { + return false; + } + + if (!$profileIndexed) { + // Add to index + if (false === $file = fopen($this->getIndexFilename(), 'a')) { + return false; + } + + fputcsv($file, array( + $profile->getToken(), + $profile->getIp(), + $profile->getMethod(), + $profile->getUrl(), + $profile->getTime(), + $profile->getParentToken(), + $profile->getStatusCode(), + )); + fclose($file); + } + + return true; + } + + /** + * Gets filename to store data, associated to the token. + * + * @param string $token + * + * @return string The profile filename + */ + protected function getFilename($token) + { + // Uses 4 last characters, because first are mostly the same. + $folderA = substr($token, -2, 2); + $folderB = substr($token, -4, 2); + + return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; + } + + /** + * Gets the index filename. + * + * @return string The index filename + */ + protected function getIndexFilename() + { + return $this->folder.'/index.csv'; + } + + /** + * Reads a line in the file, backward. + * + * This function automatically skips the empty lines and do not include the line return in result value. + * + * @param resource $file The file resource, with the pointer placed at the end of the line to read + * + * @return mixed A string representing the line or null if beginning of file is reached + */ + protected function readLineFromFile($file) + { + $line = ''; + $position = ftell($file); + + if (0 === $position) { + return; + } + + while (true) { + $chunkSize = min($position, 1024); + $position -= $chunkSize; + fseek($file, $position); + + if (0 === $chunkSize) { + // bof reached + break; + } + + $buffer = fread($file, $chunkSize); + + if (false === ($upTo = strrpos($buffer, "\n"))) { + $line = $buffer.$line; + continue; + } + + $position += $upTo; + $line = substr($buffer, $upTo + 1).$line; + fseek($file, max(0, $position), SEEK_SET); + + if ('' !== $line) { + break; + } + } + + return '' === $line ? null : $line; + } + + protected function createProfileFromData($token, $data, $parent = null) + { + $profile = new Profile($token); + $profile->setIp($data['ip']); + $profile->setMethod($data['method']); + $profile->setUrl($data['url']); + $profile->setTime($data['time']); + $profile->setStatusCode($data['status_code']); + $profile->setCollectors($data['data']); + + if (!$parent && $data['parent']) { + $parent = $this->read($data['parent']); + } + + if ($parent) { + $profile->setParent($parent); + } + + foreach ($data['children'] as $token) { + if (!$token || !file_exists($file = $this->getFilename($token))) { + continue; + } + + $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile)); + } + + return $profile; + } +} diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php new file mode 100644 index 0000000000000..72ec030dcd94c --- /dev/null +++ b/src/Symfony/Component/Profiler/Profile.php @@ -0,0 +1,292 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler; + +use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; + +/** + * Profile. + * + * @author Fabien Potencier + */ +class Profile +{ + private $token; + + /** + * @var DataCollectorInterface[] + */ + private $collectors = array(); + + private $ip; + private $method; + private $url; + private $time; + private $statusCode; + + /** + * @var Profile + */ + private $parent; + + /** + * @var Profile[] + */ + private $children = array(); + + /** + * Constructor. + * + * @param string $token The token + */ + public function __construct($token) + { + $this->token = $token; + } + + /** + * Sets the token. + * + * @param string $token The token + */ + public function setToken($token) + { + $this->token = $token; + } + + /** + * Gets the token. + * + * @return string The token + */ + public function getToken() + { + return $this->token; + } + + /** + * Sets the parent token. + * + * @param Profile $parent The parent Profile + */ + public function setParent(Profile $parent) + { + $this->parent = $parent; + } + + /** + * Returns the parent profile. + * + * @return Profile The parent profile + */ + public function getParent() + { + return $this->parent; + } + + /** + * Returns the parent token. + * + * @return null|string The parent token + */ + public function getParentToken() + { + return $this->parent ? $this->parent->getToken() : null; + } + + /** + * Returns the IP. + * + * @return string The IP + */ + public function getIp() + { + return $this->ip; + } + + /** + * Sets the IP. + * + * @param string $ip + */ + public function setIp($ip) + { + $this->ip = $ip; + } + + /** + * Returns the request method. + * + * @return string The request method + */ + public function getMethod() + { + return $this->method; + } + + public function setMethod($method) + { + $this->method = $method; + } + + /** + * Returns the URL. + * + * @return string The URL + */ + public function getUrl() + { + return $this->url; + } + + public function setUrl($url) + { + $this->url = $url; + } + + /** + * Returns the time. + * + * @return string The time + */ + public function getTime() + { + if (null === $this->time) { + return 0; + } + + return $this->time; + } + + public function setTime($time) + { + $this->time = $time; + } + + /** + * @param int $statusCode + */ + public function setStatusCode($statusCode) + { + $this->statusCode = $statusCode; + } + + /** + * @return int + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * Finds children profilers. + * + * @return Profile[] An array of Profile + */ + public function getChildren() + { + return $this->children; + } + + /** + * Sets children profiler. + * + * @param Profile[] $children An array of Profile + */ + public function setChildren(array $children) + { + $this->children = array(); + foreach ($children as $child) { + $this->addChild($child); + } + } + + /** + * Adds the child token. + * + * @param Profile $child The child Profile + */ + public function addChild(Profile $child) + { + $this->children[] = $child; + $child->setParent($this); + } + + /** + * Gets a Collector by name. + * + * @param string $name A collector name + * + * @return DataCollectorInterface A DataCollectorInterface instance + * + * @throws \InvalidArgumentException if the collector does not exist + */ + public function getCollector($name) + { + if (!isset($this->collectors[$name])) { + throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); + } + + return $this->collectors[$name]; + } + + /** + * Gets the Collectors associated with this profile. + * + * @return DataCollectorInterface[] + */ + public function getCollectors() + { + return $this->collectors; + } + + /** + * Sets the Collectors associated with this profile. + * + * @param DataCollectorInterface[] $collectors + */ + public function setCollectors(array $collectors) + { + $this->collectors = array(); + foreach ($collectors as $collector) { + $this->addCollector($collector); + } + } + + /** + * Adds a Collector. + * + * @param DataCollectorInterface $collector A DataCollectorInterface instance + */ + public function addCollector(DataCollectorInterface $collector) + { + $this->collectors[$collector->getName()] = $collector; + } + + /** + * Returns true if a Collector for the given name exists. + * + * @param string $name A collector name + * + * @return bool + */ + public function hasCollector($name) + { + return isset($this->collectors[$name]); + } + + public function __sleep() + { + return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode'); + } +} diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php new file mode 100644 index 0000000000000..513635af1a68d --- /dev/null +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -0,0 +1,252 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler; + +use Symfony\Component\HttpFoundation\Response; +use Psr\Log\LoggerInterface; +use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; +use Symfony\Component\Profiler\DataCollector\LateDataCollectorInterface; + +/** + * Profiler. + * + * @author Fabien Potencier + */ +class Profiler +{ + /** + * @var ProfilerStorageInterface + */ + private $storage; + + /** + * @var DataCollectorInterface[] + */ + private $collectors = array(); + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var bool + */ + private $enabled = true; + + /** + * Constructor. + * + * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null) + { + $this->storage = $storage; + $this->logger = $logger; + } + + /** + * Disables the profiler. + */ + public function disable() + { + $this->enabled = false; + } + + /** + * Enables the profiler. + */ + public function enable() + { + $this->enabled = true; + } + + /** + * Loads the Profile for the given token. + * + * @param string $token A token + * + * @return Profile A Profile instance + */ + public function loadProfile($token) + { + return $this->storage->read($token); + } + + /** + * Saves a Profile. + * + * @param Profile $profile A Profile instance + * + * @return bool + */ + public function saveProfile(Profile $profile) + { + // late collect + foreach ($profile->getCollectors() as $collector) { + if ($collector instanceof LateDataCollectorInterface) { + $collector->lateCollect(); + } + } + + if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { + $this->logger->warning('Unable to store the profiler information.', array('configured_storage' => get_class($this->storage))); + } + + return $ret; + } + + /** + * Purges all data from the storage. + */ + public function purge() + { + $this->storage->purge(); + } + + /** + * Finds profiler tokens for the given criteria. + * + * @param string $ip The IP + * @param string $url The URL + * @param string $limit The maximum number of tokens to return + * @param string $method The request method + * @param string $start The start date to search from + * @param string $end The end date to search to + * @param string $statusCode The request status code + * + * @return array An array of tokens + * + * @see http://php.net/manual/en/datetime.formats.php for the supported date/time formats + */ + public function find($ip, $url, $limit, $method, $statusCode, $start, $end) + { + return $this->storage->find( + $ip, + $url, + $limit, + $method, + $statusCode, + $this->getTimestamp($start), + $this->getTimestamp($end) + ); + } + + /** + * Collects data for the given response. + * + * @param DataInterface $data + * @return null|Profile A Profile instance or null if the profiler is disabled + */ + public function collectData(DataInterface $data) + { + if (false === $this->enabled) { + return null; + } + + $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); + $profile->setTime(time()); + $profile->setUrl($data->getUri()); + $profile->setMethod($data->getMethod()); + $profile->setStatusCode($data->getStatusCode()); + $profile->setIp($data->getClientIp()); + + foreach ($this->collectors as $collector) { + if ($collector->collectData($data,)) { + // we need to clone for sub-requests + $profile->addCollector(clone $collector); + } + + } + + return $profile; + } + + /** + * Gets the Collectors associated with this profiler. + * + * @return array An array of collectors + */ + public function all() + { + return $this->collectors; + } + + /** + * Sets the Collectors associated with this profiler. + * + * @param DataCollectorInterface[] $collectors An array of collectors + */ + public function set(array $collectors = array()) + { + $this->collectors = array(); + foreach ($collectors as $collector) { + $this->add($collector); + } + } + + /** + * Adds a Collector. + * + * @param DataCollectorInterface $collector A DataCollectorInterface instance + */ + public function add(DataCollectorInterface $collector) + { + $this->collectors[$collector->getName()] = $collector; + } + + /** + * Returns true if a Collector for the given name exists. + * + * @param string $name A collector name + * + * @return bool + */ + public function has($name) + { + return isset($this->collectors[$name]); + } + + /** + * Gets a Collector by name. + * + * @param string $name A collector name + * + * @return DataCollectorInterface A DataCollectorInterface instance + * + * @throws \InvalidArgumentException if the collector does not exist + */ + public function get($name) + { + if (!isset($this->collectors[$name])) { + throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); + } + + return $this->collectors[$name]; + } + + private function getTimestamp($value) + { + if (null === $value || '' == $value) { + return null; + } + + try { + $value = new \DateTime(is_numeric($value) ? '@'.$value : $value); + } catch (\Exception $e) { + return null; + } + + return $value->getTimestamp(); + } +} diff --git a/src/Symfony/Component/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/Profiler/ProfilerStorageInterface.php new file mode 100644 index 0000000000000..c73c86d656912 --- /dev/null +++ b/src/Symfony/Component/Profiler/ProfilerStorageInterface.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Profiler; + +/** + * ProfilerStorageInterface. + * + * @author Fabien Potencier + */ +interface ProfilerStorageInterface +{ + /** + * Finds profiler tokens for the given criteria. + * + * @param string $ip The IP + * @param string $url The URL + * @param string $limit The maximum number of tokens to return + * @param string $method The request method + * @param null $statusCode + * @param int|null $start The start date to search from + * @param int|null $end The end date to search to + * @return array An array of tokens + */ + public function find($ip, $url, $limit, $method, $statusCode, $start = null, $end = null); + + /** + * Reads data associated with the given token. + * + * The method returns false if the token does not exist in the storage. + * + * @param string $token A token + * + * @return Profile The profile associated with token + */ + public function read($token); + + /** + * Saves a Profile. + * + * @param Profile $profile A Profile instance + * + * @return bool Write operation successful + */ + public function write(Profile $profile); + + /** + * Purges all data from the database. + */ + public function purge(); +} diff --git a/src/Symfony/Component/Profiler/RequestData.php b/src/Symfony/Component/Profiler/RequestData.php new file mode 100644 index 0000000000000..3210527f1f359 --- /dev/null +++ b/src/Symfony/Component/Profiler/RequestData.php @@ -0,0 +1,76 @@ +exception = $exception; + $this->request = $request; + $this->response = $response; + } + + public function getException() + { + return $this->exception; + } + + public function getUri() + { + return $this->request->getUri(); + } + + public function getStatusCode() + { + return $this->response->getStatusCode(); + } + + public function getMethod() + { + return $this->request->getMethod(); + } + + public function getClientIp() + { + try { + return $this->request->getClientIp(); + } catch (ConflictingHeadersException $e) { + return 'Unknown'; + } + } + + /** + * @return Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * @return Response + */ + public function getResponse() + { + return $this->response; + } +} \ No newline at end of file From 537b550bd3a2bc72350de655292013ca67439410 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 5 Nov 2016 21:06:31 -0400 Subject: [PATCH 2/9] cleanup --- .../{ => Data}/ConsoleCommandData.php | 18 +----------------- .../Profiler/{ => Data}/DataInterface.php | 12 +----------- .../Profiler/{ => Data}/RequestData.php | 19 ++----------------- .../DataCollector/AjaxDataCollector.php | 5 ++--- .../DataCollector/ConfigDataCollector.php | 5 +---- .../DataCollector/DataCollectorInterface.php | 4 +--- .../DataCollector/DumpDataCollector.php | 7 ++----- .../DataCollector/EventDataCollector.php | 4 +--- .../DataCollector/ExceptionDataCollector.php | 4 +--- .../DataCollector/LoggerDataCollector.php | 4 +--- .../DataCollector/MemoryDataCollector.php | 3 +-- .../DataCollector/RequestDataCollector.php | 12 +++++++++--- .../DataCollector/RouterDataCollector.php | 5 ++--- .../DataCollector/TimeDataCollector.php | 5 ++--- src/Symfony/Component/Profiler/Profiler.php | 5 ++--- 15 files changed, 29 insertions(+), 83 deletions(-) rename src/Symfony/Component/Profiler/{ => Data}/ConsoleCommandData.php (82%) rename src/Symfony/Component/Profiler/{ => Data}/DataInterface.php (65%) rename src/Symfony/Component/Profiler/{ => Data}/RequestData.php (73%) diff --git a/src/Symfony/Component/Profiler/ConsoleCommandData.php b/src/Symfony/Component/Profiler/Data/ConsoleCommandData.php similarity index 82% rename from src/Symfony/Component/Profiler/ConsoleCommandData.php rename to src/Symfony/Component/Profiler/Data/ConsoleCommandData.php index e2cf5c418412b..4d5d4770f5455 100644 --- a/src/Symfony/Component/Profiler/ConsoleCommandData.php +++ b/src/Symfony/Component/Profiler/Data/ConsoleCommandData.php @@ -6,7 +6,7 @@ * Time: 10:27 PM */ -namespace Symfony\Component\Profiler; +namespace Symfony\Component\Profiler\Data; use Symfony\Component\Console\Command\Command; @@ -56,20 +56,4 @@ public function getStatusCode() { return $this->exitCode; } - - /** - * @return null|string - */ - public function getMethod() - { - return null; - } - - /** - * @return null|string - */ - public function getClientIp() - { - return null; - } } \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/DataInterface.php b/src/Symfony/Component/Profiler/Data/DataInterface.php similarity index 65% rename from src/Symfony/Component/Profiler/DataInterface.php rename to src/Symfony/Component/Profiler/Data/DataInterface.php index 62b8bdc5bd625..310b113ae5b82 100644 --- a/src/Symfony/Component/Profiler/DataInterface.php +++ b/src/Symfony/Component/Profiler/Data/DataInterface.php @@ -6,7 +6,7 @@ * Time: 5:06 PM */ -namespace Symfony\Component\Profiler; +namespace Symfony\Component\Profiler\Data; interface DataInterface { @@ -24,14 +24,4 @@ public function getUri(); * @return null|string */ public function getStatusCode(); - - /** - * @return null|string - */ - public function getMethod(); - - /** - * @return null|string - */ - public function getClientIp(); } diff --git a/src/Symfony/Component/Profiler/RequestData.php b/src/Symfony/Component/Profiler/Data/RequestData.php similarity index 73% rename from src/Symfony/Component/Profiler/RequestData.php rename to src/Symfony/Component/Profiler/Data/RequestData.php index 3210527f1f359..5654a09809098 100644 --- a/src/Symfony/Component/Profiler/RequestData.php +++ b/src/Symfony/Component/Profiler/Data/RequestData.php @@ -6,9 +6,8 @@ * Time: 10:18 PM */ -namespace Symfony\Component\Profiler; +namespace Symfony\Component\Profiler\Data; -use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -21,7 +20,7 @@ class RequestData implements DataInterface public function __construct(Request $request, Response $response, $exception = null) { if (!is_null($exception) && !$exception instanceof \Exception && !$exception instanceof \Throwable) { - throw new \InvalidArgumentException('$exception must be either null or an exception'); + throw new \InvalidArgumentException('$exception must be either null or an instance of \Exception or \Throwable'); } $this->exception = $exception; @@ -44,20 +43,6 @@ public function getStatusCode() return $this->response->getStatusCode(); } - public function getMethod() - { - return $this->request->getMethod(); - } - - public function getClientIp() - { - try { - return $this->request->getClientIp(); - } catch (ConflictingHeadersException $e) { - return 'Unknown'; - } - } - /** * @return Request */ diff --git a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php index b0460b1f100fd..c504a486cbf2b 100644 --- a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php @@ -11,10 +11,9 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Profiler\Data\RequestData; /** * AjaxDataCollector. diff --git a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php index c9c16c720e7e8..4d7843144d236 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php @@ -13,11 +13,8 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; /** * ConfigDataCollector. diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php index a349ae52f0b5a..7e8cb12b0f96b 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php @@ -11,9 +11,7 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; /** diff --git a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php index f917166f61938..3f94eaf52f19c 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php @@ -11,13 +11,10 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\ConsoleCommandData; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Profiler\Data\RequestData; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php index 06b4f8997e3d9..90280e7fdffcd 100644 --- a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -11,11 +11,9 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; /** diff --git a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php index 9d2ad7c1754ee..ded0372c3ef04 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php @@ -12,9 +12,7 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\Debug\Exception\FlattenException; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; /** diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php index 7272f7a3869e4..a6828a4aada41 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -12,10 +12,8 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\Debug\Exception\SilencedErrorContext; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; /** diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php index 20def98bda476..6b343498a6cb2 100644 --- a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -11,8 +11,7 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; /** diff --git a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php index 5f67d4c5a1b24..e889e2f756bb3 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php @@ -11,18 +11,18 @@ namespace Symfony\Component\Profiler\DataCollector; +use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\HeaderBag; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Profiler\Data\RequestData; use Symfony\Component\Routing\Route; /** @@ -51,6 +51,12 @@ public function collectData(DataInterface $data, Profile $profile) $response = $data->getResponse(); $request = $data->getRequest(); + $profile->setMethod($request->getMethod()); + try { + $profile->setIp($request->getClientIp()); + } catch (ConflictingHeadersException $e) { + $profile->setIp('Unknown'); + } $responseHeaders = $response->headers->all(); $cookies = array(); foreach ($response->headers->getCookies() as $cookie) { diff --git a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php index bcd6f6cad33d9..59b73726e2bac 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php @@ -12,12 +12,11 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Profiler\Data\RequestData; /** * RouterDataCollector. diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php index c37c2523f35b2..7bfd43e63c74d 100644 --- a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -12,11 +12,10 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\Profiler\DataInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\RequestData; +use Symfony\Component\Profiler\Data\RequestData; use Symfony\Component\Stopwatch\Stopwatch; /** diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index 513635af1a68d..4cfdf5ef3c6c1 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpFoundation\Response; use Psr\Log\LoggerInterface; +use Symfony\Component\Profiler\Data\DataInterface; use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; use Symfony\Component\Profiler\DataCollector\LateDataCollectorInterface; @@ -157,12 +158,10 @@ public function collectData(DataInterface $data) $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $profile->setTime(time()); $profile->setUrl($data->getUri()); - $profile->setMethod($data->getMethod()); $profile->setStatusCode($data->getStatusCode()); - $profile->setIp($data->getClientIp()); foreach ($this->collectors as $collector) { - if ($collector->collectData($data,)) { + if ($collector->collectData($data, $profile)) { // we need to clone for sub-requests $profile->addCollector(clone $collector); } From 52e2eecd4d53307444d22ae9307b40b290b64c13 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 5 Nov 2016 21:17:54 -0400 Subject: [PATCH 3/9] movedthins artound renamed things --- .../ConsoleCommandContext.php} | 6 ++--- .../ContextInterface.php} | 6 ++--- .../RequestContext.php} | 6 ++--- .../DataCollector/AjaxDataCollector.php | 8 +++---- .../DataCollector/ConfigDataCollector.php | 4 ++-- .../DataCollector/DataCollectorInterface.php | 6 ++--- .../DataCollector/DumpDataCollector.php | 24 +++++++++---------- .../DataCollector/EventDataCollector.php | 4 ++-- .../DataCollector/ExceptionDataCollector.php | 8 +++---- .../DataCollector/LoggerDataCollector.php | 4 ++-- .../DataCollector/MemoryDataCollector.php | 4 ++-- .../DataCollector/RequestDataCollector.php | 12 +++++----- .../DataCollector/RouterDataCollector.php | 12 +++++----- .../DataCollector/TimeDataCollector.php | 10 ++++---- .../Profiler/FileProfilerStorage.php | 6 ++--- src/Symfony/Component/Profiler/Profile.php | 10 ++++---- src/Symfony/Component/Profiler/Profiler.php | 10 ++++---- 17 files changed, 70 insertions(+), 70 deletions(-) rename src/Symfony/Component/Profiler/{Data/ConsoleCommandData.php => Context/ConsoleCommandContext.php} (89%) rename src/Symfony/Component/Profiler/{Data/DataInterface.php => Context/ContextInterface.php} (75%) rename src/Symfony/Component/Profiler/{Data/RequestData.php => Context/RequestContext.php} (90%) diff --git a/src/Symfony/Component/Profiler/Data/ConsoleCommandData.php b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php similarity index 89% rename from src/Symfony/Component/Profiler/Data/ConsoleCommandData.php rename to src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php index 4d5d4770f5455..a10c619bedb31 100644 --- a/src/Symfony/Component/Profiler/Data/ConsoleCommandData.php +++ b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php @@ -6,11 +6,11 @@ * Time: 10:27 PM */ -namespace Symfony\Component\Profiler\Data; +namespace Symfony\Component\Profiler\Context; use Symfony\Component\Console\Command\Command; -class ConsoleCommandData implements DataInterface +class ConsoleCommandContext implements ContextInterface { protected $exception; protected $exitCode; @@ -44,7 +44,7 @@ public function getException() /** * @return null|string */ - public function getUri() + public function getName() { return sprintf('command=>%s', $this->command->getName()); } diff --git a/src/Symfony/Component/Profiler/Data/DataInterface.php b/src/Symfony/Component/Profiler/Context/ContextInterface.php similarity index 75% rename from src/Symfony/Component/Profiler/Data/DataInterface.php rename to src/Symfony/Component/Profiler/Context/ContextInterface.php index 310b113ae5b82..ba6bf0c40adbe 100644 --- a/src/Symfony/Component/Profiler/Data/DataInterface.php +++ b/src/Symfony/Component/Profiler/Context/ContextInterface.php @@ -6,9 +6,9 @@ * Time: 5:06 PM */ -namespace Symfony\Component\Profiler\Data; +namespace Symfony\Component\Profiler\Context; -interface DataInterface +interface ContextInterface { /** * @return \Exception|\Throwable|null @@ -18,7 +18,7 @@ public function getException(); /** * @return null|string */ - public function getUri(); + public function getName(); /** * @return null|string diff --git a/src/Symfony/Component/Profiler/Data/RequestData.php b/src/Symfony/Component/Profiler/Context/RequestContext.php similarity index 90% rename from src/Symfony/Component/Profiler/Data/RequestData.php rename to src/Symfony/Component/Profiler/Context/RequestContext.php index 5654a09809098..14d03f6691ad6 100644 --- a/src/Symfony/Component/Profiler/Data/RequestData.php +++ b/src/Symfony/Component/Profiler/Context/RequestContext.php @@ -6,12 +6,12 @@ * Time: 10:18 PM */ -namespace Symfony\Component\Profiler\Data; +namespace Symfony\Component\Profiler\Context; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -class RequestData implements DataInterface +class RequestContext implements ContextInterface { protected $exception; protected $request; @@ -33,7 +33,7 @@ public function getException() return $this->exception; } - public function getUri() + public function getName() { return $this->request->getUri(); } diff --git a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php index c504a486cbf2b..33355f2b27af1 100644 --- a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\Data\RequestData; +use Symfony\Component\Profiler\Context\RequestContext; /** * AjaxDataCollector. @@ -22,9 +22,9 @@ */ class AjaxDataCollector extends DataCollector { - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { - return $data instanceof RequestData; + return $context instanceof RequestContext; } public function getName() diff --git a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php index 4d7843144d236..077ae2d8d607e 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -56,7 +56,7 @@ public function setKernel(KernelInterface $kernel = null) /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->data = array( 'app_name' => $this->name, diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php index 7e8cb12b0f96b..00f2c5d7d0e01 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -24,11 +24,11 @@ interface DataCollectorInterface /** * Collects data for the given Request and Response. * - * @param DataInterface $data + * @param ContextInterface $context * @param Profile $profile * @return */ - public function collectData(DataInterface $data, Profile $profile); + public function collectData(ContextInterface $context, Profile $profile); /** * Returns the name of the collector. diff --git a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php index 3f94eaf52f19c..ed4ca0a726e28 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php @@ -12,9 +12,9 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\Data\RequestData; +use Symfony\Component\Profiler\Context\RequestContext; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; @@ -140,15 +140,15 @@ public function dump(Data $data) } } - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper) { return true; } - if ($data instanceof RequestData) { - $request = $data->getRequest(); + if ($context instanceof RequestContext) { + $request = $context->getRequest(); if (($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { return true; @@ -156,15 +156,15 @@ public function collectData(DataInterface $data, Profile $profile) } // In all other conditions that remove the web debug toolbar, dumps are written on the output. - if (!$data instanceof RequestData + if (!$context instanceof RequestContext || !$this->requestStack - || !$data->getResponse()->headers->has('X-Debug-Token') - || $data->getResponse()->isRedirection() - || ($data->getResponse()->headers->has('Content-Type') && false === strpos($data->getResponse()->headers->get('Content-Type'), 'html')) - || 'html' !== $data->getRequest()->getRequestFormat() - || false === strripos($data->getResponse()->getContent(), '') + || !$context->getResponse()->headers->has('X-Debug-Token') + || $context->getResponse()->isRedirection() + || ($context->getResponse()->headers->has('Content-Type') && false === strpos($context->getResponse()->headers->get('Content-Type'), 'html')) + || 'html' !== $context->getRequest()->getRequestFormat() + || false === strripos($context->getResponse()->getContent(), '') ) { - if ($data instanceof RequestData && $data->getResponse()->headers->has('Content-Type') && false !== strpos($data->getResponse()->headers->get('Content-Type'), 'html')) { + if ($context instanceof RequestContext && $context->getResponse()->headers->has('Content-Type') && false !== strpos($context->getResponse()->headers->get('Content-Type'), 'html')) { $this->dumper = new HtmlDumper('php://output', $this->charset); $this->dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); } else { diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php index 90280e7fdffcd..efd7234108ca1 100644 --- a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -33,7 +33,7 @@ public function __construct(EventDispatcherInterface $dispatcher = null) /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->data = array( 'called_listeners' => array(), diff --git a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php index ded0372c3ef04..921513a13b134 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\Debug\Exception\FlattenException; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -25,11 +25,11 @@ class ExceptionDataCollector extends DataCollector /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { - if (null !== $data->getException()) { + if (null !== $context->getException()) { $this->data = array( - 'exception' => FlattenException::create($data->getException()), + 'exception' => FlattenException::create($context->getException()), ); } diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php index a6828a4aada41..71c7a8185b2dd 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\Debug\Exception\SilencedErrorContext; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -35,7 +35,7 @@ public function __construct($logger = null) /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { return true; } diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php index 6b343498a6cb2..8e2b86bef3360 100644 --- a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; /** @@ -32,7 +32,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->updateMemoryUsage(); return true; diff --git a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php index e889e2f756bb3..bd197afcce2a8 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php @@ -20,9 +20,9 @@ use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\Data\RequestData; +use Symfony\Component\Profiler\Context\RequestContext; use Symfony\Component\Routing\Route; /** @@ -43,14 +43,14 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { - if (!$data instanceof RequestData) { + if (!$context instanceof RequestContext) { return false; } - $response = $data->getResponse(); - $request = $data->getRequest(); + $response = $context->getResponse(); + $request = $context->getRequest(); $profile->setMethod($request->getMethod()); try { $profile->setIp($request->getClientIp()); diff --git a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php index 59b73726e2bac..e4b6606711e60 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php @@ -14,9 +14,9 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\Data\RequestData; +use Symfony\Component\Profiler\Context\RequestContext; /** * RouterDataCollector. @@ -41,14 +41,14 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { - if (!$data instanceof RequestData) { + if (!$context instanceof RequestContext) { return false; } - $request = $data->getRequest(); - $response = $data->getResponse(); + $request = $context->getRequest(); + $response = $context->getResponse(); if ($response instanceof RedirectResponse) { $this->data['redirect'] = true; diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php index 7bfd43e63c74d..552e5fb87901e 100644 --- a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -13,9 +13,9 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\Data\RequestData; +use Symfony\Component\Profiler\Context\RequestContext; use Symfony\Component\Stopwatch\Stopwatch; /** @@ -37,13 +37,13 @@ public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch /** * {@inheritdoc} */ - public function collectData(DataInterface $data, Profile $profile) + public function collectData(ContextInterface $context, Profile $profile) { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); } else { - if ($data instanceof RequestData) { - $request = $data->getRequest(); + if ($context instanceof RequestContext) { + $request = $context->getRequest(); } else { $request = Request::createFromGlobals(); } diff --git a/src/Symfony/Component/Profiler/FileProfilerStorage.php b/src/Symfony/Component/Profiler/FileProfilerStorage.php index 627ffb3b5f227..0d005fc180339 100644 --- a/src/Symfony/Component/Profiler/FileProfilerStorage.php +++ b/src/Symfony/Component/Profiler/FileProfilerStorage.php @@ -150,7 +150,7 @@ public function write(Profile $profile) 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), - 'url' => $profile->getUrl(), + 'url' => $profile->getName(), 'time' => $profile->getTime(), 'status_code' => $profile->getStatusCode(), ); @@ -169,7 +169,7 @@ public function write(Profile $profile) $profile->getToken(), $profile->getIp(), $profile->getMethod(), - $profile->getUrl(), + $profile->getName(), $profile->getTime(), $profile->getParentToken(), $profile->getStatusCode(), @@ -258,7 +258,7 @@ protected function createProfileFromData($token, $data, $parent = null) $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); - $profile->setUrl($data['url']); + $profile->setName($data['url']); $profile->setTime($data['time']); $profile->setStatusCode($data['status_code']); $profile->setCollectors($data['data']); diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php index 72ec030dcd94c..7bc53eaab8f43 100644 --- a/src/Symfony/Component/Profiler/Profile.php +++ b/src/Symfony/Component/Profiler/Profile.php @@ -29,7 +29,7 @@ class Profile private $ip; private $method; - private $url; + private $name; private $time; private $statusCode; @@ -143,14 +143,14 @@ public function setMethod($method) * * @return string The URL */ - public function getUrl() + public function getName() { - return $this->url; + return $this->name; } - public function setUrl($url) + public function setName($name) { - $this->url = $url; + $this->name = $name; } /** diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index 4cfdf5ef3c6c1..b985647d8f79d 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpFoundation\Response; use Psr\Log\LoggerInterface; -use Symfony\Component\Profiler\Data\DataInterface; +use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; use Symfony\Component\Profiler\DataCollector\LateDataCollectorInterface; @@ -146,10 +146,10 @@ public function find($ip, $url, $limit, $method, $statusCode, $start, $end) /** * Collects data for the given response. * - * @param DataInterface $data + * @param ContextInterface $data * @return null|Profile A Profile instance or null if the profiler is disabled */ - public function collectData(DataInterface $data) + public function collectData(ContextInterface $data) { if (false === $this->enabled) { return null; @@ -157,7 +157,7 @@ public function collectData(DataInterface $data) $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $profile->setTime(time()); - $profile->setUrl($data->getUri()); + $profile->setName($data->getName()); $profile->setStatusCode($data->getStatusCode()); foreach ($this->collectors as $collector) { @@ -227,7 +227,7 @@ public function has($name) */ public function get($name) { - if (!isset($this->collectors[$name])) { + if (!$this->has($name)) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } From b616f96c7e551128fb2ce109dacbeca1d81fde0d Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 5 Nov 2016 21:22:45 -0400 Subject: [PATCH 4/9] added type info to profiles --- .../Context/ConsoleCommandContext.php | 19 +++++++++---------- .../Profiler/Context/ContextInterface.php | 9 +++++++-- .../Profiler/Context/RequestContext.php | 8 ++++++++ .../Component/Profiler/Context/Types.php | 16 ++++++++++++++++ src/Symfony/Component/Profiler/Profile.php | 17 +++++++++++++++++ src/Symfony/Component/Profiler/Profiler.php | 11 ++++++----- 6 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 src/Symfony/Component/Profiler/Context/Types.php diff --git a/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php index a10c619bedb31..0605f3c803794 100644 --- a/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php +++ b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php @@ -33,27 +33,26 @@ public function __construct(Command $command, $exitCode, $exception = null) $this->command = $command; } - /** - * @return \Exception|\Throwable|null - */ public function getException() { return $this->exception; } - /** - * @return null|string - */ public function getName() { - return sprintf('command=>%s', $this->command->getName()); + return sprintf('command => %s', $this->command->getName()); } - /** - * @return null|string - */ public function getStatusCode() { return $this->exitCode; } + + /** + * @return string + */ + public function getType() + { + return Types::COMMAND; + } } \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/Context/ContextInterface.php b/src/Symfony/Component/Profiler/Context/ContextInterface.php index ba6bf0c40adbe..4517c993cf11b 100644 --- a/src/Symfony/Component/Profiler/Context/ContextInterface.php +++ b/src/Symfony/Component/Profiler/Context/ContextInterface.php @@ -16,12 +16,17 @@ interface ContextInterface public function getException(); /** - * @return null|string + * @return string */ public function getName(); /** - * @return null|string + * @return string + */ + public function getType(); + + /** + * @return null|int */ public function getStatusCode(); } diff --git a/src/Symfony/Component/Profiler/Context/RequestContext.php b/src/Symfony/Component/Profiler/Context/RequestContext.php index 14d03f6691ad6..524034cf19586 100644 --- a/src/Symfony/Component/Profiler/Context/RequestContext.php +++ b/src/Symfony/Component/Profiler/Context/RequestContext.php @@ -58,4 +58,12 @@ public function getResponse() { return $this->response; } + + /** + * @return string + */ + public function getType() + { + return Types::REQUEST; + } } \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/Context/Types.php b/src/Symfony/Component/Profiler/Context/Types.php new file mode 100644 index 0000000000000..540097c66553f --- /dev/null +++ b/src/Symfony/Component/Profiler/Context/Types.php @@ -0,0 +1,16 @@ +children; } + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @param mixed $type + */ + public function setType($type) + { + $this->type = $type; + } + /** * Sets children profiler. * diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index b985647d8f79d..8c73e4a4f8b5b 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -146,10 +146,10 @@ public function find($ip, $url, $limit, $method, $statusCode, $start, $end) /** * Collects data for the given response. * - * @param ContextInterface $data + * @param ContextInterface $context * @return null|Profile A Profile instance or null if the profiler is disabled */ - public function collectData(ContextInterface $data) + public function collectData(ContextInterface $context) { if (false === $this->enabled) { return null; @@ -157,11 +157,12 @@ public function collectData(ContextInterface $data) $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $profile->setTime(time()); - $profile->setName($data->getName()); - $profile->setStatusCode($data->getStatusCode()); + $profile->setName($context->getName()); + $profile->setStatusCode($context->getStatusCode()); + $profile->setType($context->getType()); foreach ($this->collectors as $collector) { - if ($collector->collectData($data, $profile)) { + if ($collector->collectData($context, $profile)) { // we need to clone for sub-requests $profile->addCollector(clone $collector); } From a45087aed995c72c7feb99afe8ffd31af24395d7 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 5 Nov 2016 21:23:09 -0400 Subject: [PATCH 5/9] removed string concat from console command getName --- .../Component/Profiler/Context/ConsoleCommandContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php index 0605f3c803794..b76863170183d 100644 --- a/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php +++ b/src/Symfony/Component/Profiler/Context/ConsoleCommandContext.php @@ -40,7 +40,7 @@ public function getException() public function getName() { - return sprintf('command => %s', $this->command->getName()); + return $this->command->getName(); } public function getStatusCode() From 21ea1f8948bb989d339ba2d24b82d60cd3d70263 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 5 Nov 2016 21:44:01 -0400 Subject: [PATCH 6/9] refactored storage finding --- .../Profiler/FileProfilerStorage.php | 34 +++++++++++++++---- src/Symfony/Component/Profiler/Profile.php | 6 ++-- src/Symfony/Component/Profiler/Profiler.php | 24 ++++++------- .../Profiler/ProfilerStorageInterface.php | 12 ++++--- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Component/Profiler/FileProfilerStorage.php b/src/Symfony/Component/Profiler/FileProfilerStorage.php index 0d005fc180339..1f828a6daa052 100644 --- a/src/Symfony/Component/Profiler/FileProfilerStorage.php +++ b/src/Symfony/Component/Profiler/FileProfilerStorage.php @@ -49,8 +49,9 @@ public function __construct($dsn) /** * {@inheritdoc} */ - public function find($ip, $url, $limit, $method, $statusCode, $start = null, $end = null) + public function find(array $criteria, $limit, $start = null, $end = null) { + $criteria = $this->normalizeCriteria($criteria); $file = $this->getIndexFilename(); if (!file_exists($file)) { @@ -63,10 +64,10 @@ public function find($ip, $url, $limit, $method, $statusCode, $start = null, $en $result = array(); while (count($result) < $limit && $line = $this->readLineFromFile($file)) { $values = str_getcsv($line); - list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode) = $values; + list($csvToken, $csvIp, $csvMethod, $csvName, $csvTime, $csvParent, $csvStatusCode) = $values; $csvTime = (int) $csvTime; - if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) { + if ($criteria['ip'] && false === strpos($csvIp, $criteria['ip']) || $criteria['name'] && false === strpos($csvName, $criteria['name']) || $criteria['method'] && false === strpos($csvMethod, $criteria['method']) || $criteria['status_code'] && false === strpos($csvStatusCode, $criteria['status_code'])) { continue; } @@ -82,7 +83,7 @@ public function find($ip, $url, $limit, $method, $statusCode, $start = null, $en 'token' => $csvToken, 'ip' => $csvIp, 'method' => $csvMethod, - 'url' => $csvUrl, + 'name' => $csvName, 'time' => $csvTime, 'parent' => $csvParent, 'status_code' => $csvStatusCode, @@ -150,7 +151,7 @@ public function write(Profile $profile) 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), - 'url' => $profile->getName(), + 'name' => $profile->getName(), 'time' => $profile->getTime(), 'status_code' => $profile->getStatusCode(), ); @@ -258,7 +259,7 @@ protected function createProfileFromData($token, $data, $parent = null) $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); - $profile->setName($data['url']); + $profile->setName($data['name']); $profile->setTime($data['time']); $profile->setStatusCode($data['status_code']); $profile->setCollectors($data['data']); @@ -281,4 +282,25 @@ protected function createProfileFromData($token, $data, $parent = null) return $profile; } + + public function getSearchableKeys() + { + return array( + 'ip', + 'name', + 'method', + 'status_code', + ); + } + + private function normalizeCriteria(array $criteria) + { + return array_merge( + array_combine( + $this->getSearchableKeys(), + array_fill(0, count($this->getSearchableKeys()), null) + ), + $criteria + ); + } } diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php index 095b72997446a..1ccbb8623ce7e 100644 --- a/src/Symfony/Component/Profiler/Profile.php +++ b/src/Symfony/Component/Profiler/Profile.php @@ -140,9 +140,9 @@ public function setMethod($method) } /** - * Returns the URL. + * Returns the name. * - * @return string The URL + * @return string The name */ public function getName() { @@ -304,6 +304,6 @@ public function hasCollector($name) public function __sleep() { - return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode'); + return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'time', 'statusCode', 'name'); } } diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index 8c73e4a4f8b5b..ef55cb6393f3b 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -118,31 +118,29 @@ public function purge() /** * Finds profiler tokens for the given criteria. * - * @param string $ip The IP - * @param string $url The URL - * @param string $limit The maximum number of tokens to return - * @param string $method The request method - * @param string $start The start date to search from - * @param string $end The end date to search to - * @param string $statusCode The request status code - * + * @param array $criteria + * @param string $limit The maximum number of tokens to return + * @param string $start The start date to search from + * @param string $end The end date to search to * @return array An array of tokens * * @see http://php.net/manual/en/datetime.formats.php for the supported date/time formats */ - public function find($ip, $url, $limit, $method, $statusCode, $start, $end) + public function find(array $criteria, $limit, $start, $end) { return $this->storage->find( - $ip, - $url, + $criteria, $limit, - $method, - $statusCode, $this->getTimestamp($start), $this->getTimestamp($end) ); } + public function getSearchableKeys() + { + return $this->storage->getSearchableKeys(); + } + /** * Collects data for the given response. * diff --git a/src/Symfony/Component/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/Profiler/ProfilerStorageInterface.php index c73c86d656912..e4acb406f539f 100644 --- a/src/Symfony/Component/Profiler/ProfilerStorageInterface.php +++ b/src/Symfony/Component/Profiler/ProfilerStorageInterface.php @@ -21,16 +21,13 @@ interface ProfilerStorageInterface /** * Finds profiler tokens for the given criteria. * - * @param string $ip The IP - * @param string $url The URL + * @param array $criteria * @param string $limit The maximum number of tokens to return - * @param string $method The request method - * @param null $statusCode * @param int|null $start The start date to search from * @param int|null $end The end date to search to * @return array An array of tokens */ - public function find($ip, $url, $limit, $method, $statusCode, $start = null, $end = null); + public function find(array $criteria, $limit, $start = null, $end = null); /** * Reads data associated with the given token. @@ -56,4 +53,9 @@ public function write(Profile $profile); * Purges all data from the database. */ public function purge(); + + /** + * @return array list of keys you can search by in the find method + */ + public function getSearchableKeys(); } From bdcc7a7776fc7690e1f0509cdbf43520010a6c27 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 12 Nov 2016 21:05:00 -0500 Subject: [PATCH 7/9] added the profile interface. moved the storages to their own dir in preparation for adding more flexibility to it. --- .../DataCollector/EventDataCollector.php | 3 +- .../LateDataCollectorInterface.php | 6 +- .../DataCollector/LoggerDataCollector.php | 3 +- .../DataCollector/MemoryDataCollector.php | 3 +- .../DataCollector/TimeDataCollector.php | 3 +- src/Symfony/Component/Profiler/Profile.php | 2 +- .../Component/Profiler/ProfileInterface.php | 133 ++++++++++++++++++ src/Symfony/Component/Profiler/Profiler.php | 1 + .../{ => Storage}/FileProfilerStorage.php | 5 +- .../ProfilerStorageInterface.php | 4 +- 10 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Component/Profiler/ProfileInterface.php rename src/Symfony/Component/Profiler/{ => Storage}/FileProfilerStorage.php (98%) rename src/Symfony/Component/Profiler/{ => Storage}/ProfilerStorageInterface.php (94%) diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php index efd7234108ca1..1795aadb2e7a8 100644 --- a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -15,6 +15,7 @@ use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * EventDataCollector. @@ -42,7 +43,7 @@ public function collectData(ContextInterface $context, Profile $profile) return true; } - public function lateCollect() + public function lateCollect(ProfileInterface $profile) { if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { $this->setCalledListeners($this->dispatcher->getCalledListeners()); diff --git a/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php index 4c822ec520cfa..5f1dbee6fbf73 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Profiler\DataCollector; +use Symfony\Component\Profiler\ProfileInterface; + /** * LateDataCollectorInterface. * @@ -20,6 +22,8 @@ interface LateDataCollectorInterface { /** * Collects data as late as possible. + * @param ProfileInterface $profile + * @return */ - public function lateCollect(); + public function lateCollect(ProfileInterface $profile); } diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php index 71c7a8185b2dd..532be08da2a21 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * LogDataCollector. @@ -43,7 +44,7 @@ public function collectData(ContextInterface $context, Profile $profile) /** * {@inheritdoc} */ - public function lateCollect() + public function lateCollect(ProfileInterface $profile) { if (null !== $this->logger) { $this->data = $this->computeErrorsCount(); diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php index 8e2b86bef3360..8f3a65eec647b 100644 --- a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -13,6 +13,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * MemoryDataCollector. @@ -41,7 +42,7 @@ public function collectData(ContextInterface $context, Profile $profile) /** * {@inheritdoc} */ - public function lateCollect() + public function lateCollect(ProfileInterface $profile) { $this->updateMemoryUsage(); } diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php index 552e5fb87901e..0b5f629695f51 100644 --- a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -16,6 +16,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; +use Symfony\Component\Profiler\ProfileInterface; use Symfony\Component\Stopwatch\Stopwatch; /** @@ -62,7 +63,7 @@ public function collectData(ContextInterface $context, Profile $profile) /** * {@inheritdoc} */ - public function lateCollect() + public function lateCollect(ProfileInterface $profile) { if (null !== $this->stopwatch && isset($this->data['token'])) { $this->setEvents($this->stopwatch->getSectionEvents($this->data['token'])); diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php index 1ccbb8623ce7e..97d86589d4c68 100644 --- a/src/Symfony/Component/Profiler/Profile.php +++ b/src/Symfony/Component/Profiler/Profile.php @@ -18,7 +18,7 @@ * * @author Fabien Potencier */ -class Profile +class Profile implements ProfileInterface { private $token; diff --git a/src/Symfony/Component/Profiler/ProfileInterface.php b/src/Symfony/Component/Profiler/ProfileInterface.php new file mode 100644 index 0000000000000..0213f93d1fac1 --- /dev/null +++ b/src/Symfony/Component/Profiler/ProfileInterface.php @@ -0,0 +1,133 @@ + + */ +interface ProfileInterface +{ + /** + * Gets the token. + * + * @return string The token + */ + public function getToken(); + + /** + * Sets the parent token. + * + * @param Profile $parent The parent Profile + */ + public function setParent(Profile $parent); + + /** + * Returns the parent profile. + * + * @return Profile The parent profile + */ + public function getParent(); + + /** + * Returns the parent token. + * + * @return null|string The parent token + */ + public function getParentToken(); + + /** + * Returns the name. + * + * @return string The name + */ + public function getName(); + + /** + * Returns the time. + * + * @return string The time + */ + public function getTime(); + + /** + * @return int + */ + public function getStatusCode(); + + /** + * Finds children profilers. + * + * @return Profile[] An array of Profile + */ + public function getChildren(); + + /** + * @return mixed + */ + public function getType(); + + /** + * Sets children profiler. + * + * @param Profile[] $children An array of Profile + */ + public function setChildren(array $children); + + /** + * Adds the child token. + * + * @param Profile $child The child Profile + */ + public function addChild(Profile $child); + + /** + * Gets a Collector by name. + * + * @param string $name A collector name + * + * @return DataCollectorInterface A DataCollectorInterface instance + * + * @throws \InvalidArgumentException if the collector does not exist + */ + public function getCollector($name); + + /** + * Gets the Collectors associated with this profile. + * + * @return DataCollectorInterface[] + */ + public function getCollectors(); + + /** + * Sets the Collectors associated with this profile. + * + * @param DataCollectorInterface[] $collectors + */ + public function setCollectors(array $collectors); + + /** + * Adds a Collector. + * + * @param DataCollectorInterface $collector A DataCollectorInterface instance + */ + public function addCollector(DataCollectorInterface $collector); + + /** + * Returns true if a Collector for the given name exists. + * + * @param string $name A collector name + * + * @return bool + */ + public function hasCollector($name); +} \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index ef55cb6393f3b..3ab00afffadcc 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -16,6 +16,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; use Symfony\Component\Profiler\DataCollector\LateDataCollectorInterface; +use Symfony\Component\Profiler\Storage\ProfilerStorageInterface; /** * Profiler. diff --git a/src/Symfony/Component/Profiler/FileProfilerStorage.php b/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php similarity index 98% rename from src/Symfony/Component/Profiler/FileProfilerStorage.php rename to src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php index 1f828a6daa052..f6b24a45a3ddd 100644 --- a/src/Symfony/Component/Profiler/FileProfilerStorage.php +++ b/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php @@ -9,7 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Profiler; +namespace Symfony\Component\Profiler\Storage; + +use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\Storage\ProfilerStorageInterface; /** * Storage for profiler using files. diff --git a/src/Symfony/Component/Profiler/ProfilerStorageInterface.php b/src/Symfony/Component/Profiler/Storage/ProfilerStorageInterface.php similarity index 94% rename from src/Symfony/Component/Profiler/ProfilerStorageInterface.php rename to src/Symfony/Component/Profiler/Storage/ProfilerStorageInterface.php index e4acb406f539f..8387b36fd9c93 100644 --- a/src/Symfony/Component/Profiler/ProfilerStorageInterface.php +++ b/src/Symfony/Component/Profiler/Storage/ProfilerStorageInterface.php @@ -9,7 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Profiler; +namespace Symfony\Component\Profiler\Storage; + +use Symfony\Component\Profiler\Profile; /** * ProfilerStorageInterface. From f42468d50dcebc68393fe0de126f798e27e950d0 Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 12 Nov 2016 21:11:24 -0500 Subject: [PATCH 8/9] added licence file to the new interface. changed collector collectData signature to take an instance of profile interface --- .../DataCollector/AjaxDataCollector.php | 4 +-- .../DataCollector/ConfigDataCollector.php | 4 +-- .../Profiler/DataCollector/DataCollector.php | 1 - .../DataCollector/DataCollectorInterface.php | 5 ++-- .../DataCollector/DumpDataCollector.php | 4 +-- .../DataCollector/EventDataCollector.php | 3 +- .../DataCollector/ExceptionDataCollector.php | 4 +-- .../DataCollector/LoggerDataCollector.php | 2 +- .../DataCollector/MemoryDataCollector.php | 2 +- .../DataCollector/RequestDataCollector.php | 3 +- .../DataCollector/RouterDataCollector.php | 4 +-- .../DataCollector/TimeDataCollector.php | 3 +- src/Symfony/Component/Profiler/Profile.php | 8 ++--- .../Component/Profiler/ProfileInterface.php | 29 ++++++------------- 14 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php index 33355f2b27af1..1e734d53f8685 100644 --- a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Profiler\DataCollector; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; +use Symfony\Component\Profiler\ProfileInterface; /** * AjaxDataCollector. @@ -22,7 +22,7 @@ */ class AjaxDataCollector extends DataCollector { - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { return $context instanceof RequestContext; } diff --git a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php index 077ae2d8d607e..9f16937a6fde0 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php @@ -14,7 +14,7 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * ConfigDataCollector. @@ -56,7 +56,7 @@ public function setKernel(KernelInterface $kernel = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { $this->data = array( 'app_name' => $this->name, diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DataCollector.php index 1899bb298e0ef..47c8c6e8342b9 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollector.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Component\VarDumper\Caster\LinkStub; use Symfony\Component\VarDumper\Caster\StubCaster; diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php index 00f2c5d7d0e01..5aea7166b35a2 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php @@ -13,6 +13,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * DataCollectorInterface. @@ -25,10 +26,10 @@ interface DataCollectorInterface * Collects data for the given Request and Response. * * @param ContextInterface $context - * @param Profile $profile + * @param ProfileInterface|Profile $profile * @return */ - public function collectData(ContextInterface $context, Profile $profile); + public function collectData(ContextInterface $context, ProfileInterface $profile); /** * Returns the name of the collector. diff --git a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php index ed4ca0a726e28..7f728d2e561d9 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php @@ -13,8 +13,8 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; +use Symfony\Component\Profiler\ProfileInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; @@ -140,7 +140,7 @@ public function dump(Data $data) } } - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper) { diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php index 1795aadb2e7a8..ae7e7d4a0f911 100644 --- a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -14,7 +14,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\ProfileInterface; /** @@ -34,7 +33,7 @@ public function __construct(EventDispatcherInterface $dispatcher = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { $this->data = array( 'called_listeners' => array(), diff --git a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php index 921513a13b134..55dc6eeb9284b 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; +use Symfony\Component\Profiler\ProfileInterface; /** * ExceptionDataCollector. @@ -25,7 +25,7 @@ class ExceptionDataCollector extends DataCollector /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { if (null !== $context->getException()) { $this->data = array( diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php index 532be08da2a21..1384c4dfbef9d 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -36,7 +36,7 @@ public function __construct($logger = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { return true; } diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php index 8f3a65eec647b..a9e0c7a92ef85 100644 --- a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -33,7 +33,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { $this->updateMemoryUsage(); return true; diff --git a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php index bd197afcce2a8..6fdf3e70d8b5d 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php @@ -23,6 +23,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; +use Symfony\Component\Profiler\ProfileInterface; use Symfony\Component\Routing\Route; /** @@ -43,7 +44,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { if (!$context instanceof RequestContext) { return false; diff --git a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php index e4b6606711e60..493671e89dcf6 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php @@ -15,8 +15,8 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; +use Symfony\Component\Profiler\ProfileInterface; /** * RouterDataCollector. @@ -41,7 +41,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { if (!$context instanceof RequestContext) { return false; diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php index 0b5f629695f51..129f55d33a495 100644 --- a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -14,7 +14,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; use Symfony\Component\Profiler\ProfileInterface; use Symfony\Component\Stopwatch\Stopwatch; @@ -38,7 +37,7 @@ public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, Profile $profile) + public function collectData(ContextInterface $context, ProfileInterface $profile) { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php index 97d86589d4c68..8fad5f6b8332d 100644 --- a/src/Symfony/Component/Profiler/Profile.php +++ b/src/Symfony/Component/Profiler/Profile.php @@ -35,12 +35,12 @@ class Profile implements ProfileInterface private $type; /** - * @var Profile + * @var ProfileInterface */ private $parent; /** - * @var Profile[] + * @var ProfileInterface[] */ private $children = array(); @@ -77,9 +77,9 @@ public function getToken() /** * Sets the parent token. * - * @param Profile $parent The parent Profile + * @param ProfileInterface $parent The parent Profile */ - public function setParent(Profile $parent) + public function setParent(ProfileInterface $parent) { $this->parent = $parent; } diff --git a/src/Symfony/Component/Profiler/ProfileInterface.php b/src/Symfony/Component/Profiler/ProfileInterface.php index 0213f93d1fac1..e8f723a8705f2 100644 --- a/src/Symfony/Component/Profiler/ProfileInterface.php +++ b/src/Symfony/Component/Profiler/ProfileInterface.php @@ -1,10 +1,13 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ + namespace Symfony\Component\Profiler; use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; @@ -13,7 +16,7 @@ /** * Profile. * - * @author Fabien Potencier + * @author Yosef Deray */ interface ProfileInterface { @@ -24,13 +27,6 @@ interface ProfileInterface */ public function getToken(); - /** - * Sets the parent token. - * - * @param Profile $parent The parent Profile - */ - public function setParent(Profile $parent); - /** * Returns the parent profile. * @@ -38,13 +34,6 @@ public function setParent(Profile $parent); */ public function getParent(); - /** - * Returns the parent token. - * - * @return null|string The parent token - */ - public function getParentToken(); - /** * Returns the name. * From 8d70d79d133d0076916036b54888fab387bcbf4b Mon Sep 17 00:00:00 2001 From: Yosef Deray Date: Sat, 12 Nov 2016 22:01:15 -0500 Subject: [PATCH 9/9] removed the profiler intrerface. started summarizing system --- .../DataCollector/AjaxDataCollector.php | 4 +- .../DataCollector/ConfigDataCollector.php | 4 +- .../DataCollector/DataCollectorInterface.php | 5 +- .../DataCollector/DumpDataCollector.php | 4 +- .../DataCollector/EventDataCollector.php | 6 +- .../DataCollector/ExceptionDataCollector.php | 4 +- .../LateDataCollectorInterface.php | 6 +- .../DataCollector/LoggerDataCollector.php | 5 +- .../DataCollector/MemoryDataCollector.php | 5 +- .../DataCollector/RequestDataCollector.php | 24 ++-- .../DataCollector/RouterDataCollector.php | 4 +- .../DataCollector/TimeDataCollector.php | 6 +- src/Symfony/Component/Profiler/Profile.php | 10 +- .../Component/Profiler/ProfileInterface.php | 122 ------------------ src/Symfony/Component/Profiler/Profiler.php | 3 +- .../Profiler/Storage/FileProfilerStorage.php | 2 - .../Summary/SummaryCollectorInterface.php | 17 +++ .../Profiler/Summary/SummaryGenerator.php | 37 ++++++ 18 files changed, 101 insertions(+), 167 deletions(-) delete mode 100644 src/Symfony/Component/Profiler/ProfileInterface.php create mode 100644 src/Symfony/Component/Profiler/Summary/SummaryCollectorInterface.php create mode 100644 src/Symfony/Component/Profiler/Summary/SummaryGenerator.php diff --git a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php index 1e734d53f8685..472956a0db326 100644 --- a/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/AjaxDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Context\RequestContext; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * AjaxDataCollector. @@ -22,7 +22,7 @@ */ class AjaxDataCollector extends DataCollector { - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { return $context instanceof RequestContext; } diff --git a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php index 9f16937a6fde0..077ae2d8d607e 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ConfigDataCollector.php @@ -14,7 +14,7 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * ConfigDataCollector. @@ -56,7 +56,7 @@ public function setKernel(KernelInterface $kernel = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->data = array( 'app_name' => $this->name, diff --git a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php index 5aea7166b35a2..e317edd7ae90a 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/DataCollectorInterface.php @@ -13,7 +13,6 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\ProfileInterface; /** * DataCollectorInterface. @@ -26,10 +25,10 @@ interface DataCollectorInterface * Collects data for the given Request and Response. * * @param ContextInterface $context - * @param ProfileInterface|Profile $profile + * @param Profile|Profile $profile * @return */ - public function collectData(ContextInterface $context, ProfileInterface $profile); + public function collectData(ContextInterface $context, Profile $profile); /** * Returns the name of the collector. diff --git a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php index 7f728d2e561d9..b9d6b553780bf 100644 --- a/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/DumpDataCollector.php @@ -14,7 +14,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Context\RequestContext; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; @@ -140,7 +140,7 @@ public function dump(Data $data) } } - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper) { diff --git a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php index ae7e7d4a0f911..49a71aea5023b 100644 --- a/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/EventDataCollector.php @@ -14,7 +14,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * EventDataCollector. @@ -33,7 +33,7 @@ public function __construct(EventDispatcherInterface $dispatcher = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->data = array( 'called_listeners' => array(), @@ -42,7 +42,7 @@ public function collectData(ContextInterface $context, ProfileInterface $profile return true; } - public function lateCollect(ProfileInterface $profile) + public function lateCollect(Profile $profile) { if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { $this->setCalledListeners($this->dispatcher->getCalledListeners()); diff --git a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php index 55dc6eeb9284b..921513a13b134 100644 --- a/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/ExceptionDataCollector.php @@ -13,7 +13,7 @@ use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Profiler\Context\ContextInterface; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * ExceptionDataCollector. @@ -25,7 +25,7 @@ class ExceptionDataCollector extends DataCollector /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { if (null !== $context->getException()) { $this->data = array( diff --git a/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php index 5f1dbee6fbf73..3ce443e613c3a 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php +++ b/src/Symfony/Component/Profiler/DataCollector/LateDataCollectorInterface.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Profiler\DataCollector; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * LateDataCollectorInterface. @@ -22,8 +22,8 @@ interface LateDataCollectorInterface { /** * Collects data as late as possible. - * @param ProfileInterface $profile + * @param Profile $profile * @return */ - public function lateCollect(ProfileInterface $profile); + public function lateCollect(Profile $profile); } diff --git a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php index 1384c4dfbef9d..62ad66c7ece59 100644 --- a/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/LoggerDataCollector.php @@ -15,7 +15,6 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\ProfileInterface; /** * LogDataCollector. @@ -36,7 +35,7 @@ public function __construct($logger = null) /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { return true; } @@ -44,7 +43,7 @@ public function collectData(ContextInterface $context, ProfileInterface $profile /** * {@inheritdoc} */ - public function lateCollect(ProfileInterface $profile) + public function lateCollect(Profile $profile) { if (null !== $this->logger) { $this->data = $this->computeErrorsCount(); diff --git a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php index a9e0c7a92ef85..1fefbaf27f62a 100644 --- a/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/MemoryDataCollector.php @@ -13,7 +13,6 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; -use Symfony\Component\Profiler\ProfileInterface; /** * MemoryDataCollector. @@ -33,7 +32,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { $this->updateMemoryUsage(); return true; @@ -42,7 +41,7 @@ public function collectData(ContextInterface $context, ProfileInterface $profile /** * {@inheritdoc} */ - public function lateCollect(ProfileInterface $profile) + public function lateCollect(Profile $profile) { $this->updateMemoryUsage(); } diff --git a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php index 6fdf3e70d8b5d..6d5f7f43eae42 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RequestDataCollector.php @@ -23,7 +23,6 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Context\RequestContext; -use Symfony\Component\Profiler\ProfileInterface; use Symfony\Component\Routing\Route; /** @@ -31,7 +30,7 @@ * * @author Fabien Potencier */ -class RequestDataCollector extends DataCollector implements EventSubscriberInterface +class RequestDataCollector extends DataCollector implements SummaryCollectorInterface, EventSubscriberInterface { /** @var \SplObjectStorage */ protected $controllers; @@ -44,7 +43,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { if (!$context instanceof RequestContext) { return false; @@ -52,12 +51,6 @@ public function collectData(ContextInterface $context, ProfileInterface $profile $response = $context->getResponse(); $request = $context->getRequest(); - $profile->setMethod($request->getMethod()); - try { - $profile->setIp($request->getClientIp()); - } catch (ConflictingHeadersException $e) { - $profile->setIp('Unknown'); - } $responseHeaders = $response->headers->all(); $cookies = array(); foreach ($response->headers->getCookies() as $cookie) { @@ -138,6 +131,11 @@ public function collectData(ContextInterface $context, ProfileInterface $profile 'locale' => $request->getLocale(), ); + try { + $this->data['id'] = $request->getClientIp(); + } catch (ConflictingHeadersException $e) { + $this->data['id'] = 'Unknown'; + } if (isset($this->data['request_headers']['php-auth-pw'])) { $this->data['request_headers']['php-auth-pw'] = '******'; } @@ -445,4 +443,12 @@ private function getCookieHeader($name, $value, $expires, $path, $domain, $secur return $cookie; } + + public function getSummary(Profile $profile) + { + return array( + 'ip' => $this->data['ip'], + 'method' => $this->data['method'] + ); + } } diff --git a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php index 493671e89dcf6..0260bed1fb9b2 100644 --- a/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/RouterDataCollector.php @@ -16,7 +16,7 @@ use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Context\RequestContext; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; /** * RouterDataCollector. @@ -41,7 +41,7 @@ public function __construct() /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { if (!$context instanceof RequestContext) { return false; diff --git a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php index 129f55d33a495..ed802c45b02ab 100644 --- a/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php +++ b/src/Symfony/Component/Profiler/DataCollector/TimeDataCollector.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\Context\RequestContext; -use Symfony\Component\Profiler\ProfileInterface; +use Symfony\Component\Profiler\Profile; use Symfony\Component\Stopwatch\Stopwatch; /** @@ -37,7 +37,7 @@ public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch /** * {@inheritdoc} */ - public function collectData(ContextInterface $context, ProfileInterface $profile) + public function collectData(ContextInterface $context, Profile $profile) { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); @@ -62,7 +62,7 @@ public function collectData(ContextInterface $context, ProfileInterface $profile /** * {@inheritdoc} */ - public function lateCollect(ProfileInterface $profile) + public function lateCollect(Profile $profile) { if (null !== $this->stopwatch && isset($this->data['token'])) { $this->setEvents($this->stopwatch->getSectionEvents($this->data['token'])); diff --git a/src/Symfony/Component/Profiler/Profile.php b/src/Symfony/Component/Profiler/Profile.php index 8fad5f6b8332d..1ccbb8623ce7e 100644 --- a/src/Symfony/Component/Profiler/Profile.php +++ b/src/Symfony/Component/Profiler/Profile.php @@ -18,7 +18,7 @@ * * @author Fabien Potencier */ -class Profile implements ProfileInterface +class Profile { private $token; @@ -35,12 +35,12 @@ class Profile implements ProfileInterface private $type; /** - * @var ProfileInterface + * @var Profile */ private $parent; /** - * @var ProfileInterface[] + * @var Profile[] */ private $children = array(); @@ -77,9 +77,9 @@ public function getToken() /** * Sets the parent token. * - * @param ProfileInterface $parent The parent Profile + * @param Profile $parent The parent Profile */ - public function setParent(ProfileInterface $parent) + public function setParent(Profile $parent) { $this->parent = $parent; } diff --git a/src/Symfony/Component/Profiler/ProfileInterface.php b/src/Symfony/Component/Profiler/ProfileInterface.php deleted file mode 100644 index e8f723a8705f2..0000000000000 --- a/src/Symfony/Component/Profiler/ProfileInterface.php +++ /dev/null @@ -1,122 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Profiler; - -use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; - - -/** - * Profile. - * - * @author Yosef Deray - */ -interface ProfileInterface -{ - /** - * Gets the token. - * - * @return string The token - */ - public function getToken(); - - /** - * Returns the parent profile. - * - * @return Profile The parent profile - */ - public function getParent(); - - /** - * Returns the name. - * - * @return string The name - */ - public function getName(); - - /** - * Returns the time. - * - * @return string The time - */ - public function getTime(); - - /** - * @return int - */ - public function getStatusCode(); - - /** - * Finds children profilers. - * - * @return Profile[] An array of Profile - */ - public function getChildren(); - - /** - * @return mixed - */ - public function getType(); - - /** - * Sets children profiler. - * - * @param Profile[] $children An array of Profile - */ - public function setChildren(array $children); - - /** - * Adds the child token. - * - * @param Profile $child The child Profile - */ - public function addChild(Profile $child); - - /** - * Gets a Collector by name. - * - * @param string $name A collector name - * - * @return DataCollectorInterface A DataCollectorInterface instance - * - * @throws \InvalidArgumentException if the collector does not exist - */ - public function getCollector($name); - - /** - * Gets the Collectors associated with this profile. - * - * @return DataCollectorInterface[] - */ - public function getCollectors(); - - /** - * Sets the Collectors associated with this profile. - * - * @param DataCollectorInterface[] $collectors - */ - public function setCollectors(array $collectors); - - /** - * Adds a Collector. - * - * @param DataCollectorInterface $collector A DataCollectorInterface instance - */ - public function addCollector(DataCollectorInterface $collector); - - /** - * Returns true if a Collector for the given name exists. - * - * @param string $name A collector name - * - * @return bool - */ - public function hasCollector($name); -} \ No newline at end of file diff --git a/src/Symfony/Component/Profiler/Profiler.php b/src/Symfony/Component/Profiler/Profiler.php index 3ab00afffadcc..f7aec754ed12e 100644 --- a/src/Symfony/Component/Profiler/Profiler.php +++ b/src/Symfony/Component/Profiler/Profiler.php @@ -16,6 +16,7 @@ use Symfony\Component\Profiler\Context\ContextInterface; use Symfony\Component\Profiler\DataCollector\DataCollectorInterface; use Symfony\Component\Profiler\DataCollector\LateDataCollectorInterface; +use Symfony\Component\Profiler\Profile; use Symfony\Component\Profiler\Storage\ProfilerStorageInterface; /** @@ -97,7 +98,7 @@ public function saveProfile(Profile $profile) // late collect foreach ($profile->getCollectors() as $collector) { if ($collector instanceof LateDataCollectorInterface) { - $collector->lateCollect(); + $collector->lateCollect($profile); } } diff --git a/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php b/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php index f6b24a45a3ddd..cac877aab64a8 100644 --- a/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php +++ b/src/Symfony/Component/Profiler/Storage/FileProfilerStorage.php @@ -260,8 +260,6 @@ protected function readLineFromFile($file) protected function createProfileFromData($token, $data, $parent = null) { $profile = new Profile($token); - $profile->setIp($data['ip']); - $profile->setMethod($data['method']); $profile->setName($data['name']); $profile->setTime($data['time']); $profile->setStatusCode($data['status_code']); diff --git a/src/Symfony/Component/Profiler/Summary/SummaryCollectorInterface.php b/src/Symfony/Component/Profiler/Summary/SummaryCollectorInterface.php new file mode 100644 index 0000000000000..3c5a5fb4d8d14 --- /dev/null +++ b/src/Symfony/Component/Profiler/Summary/SummaryCollectorInterface.php @@ -0,0 +1,17 @@ +collectors as $collector) { + $summary = array_merge($summary, $collector->getSummary($profile)); + } + + return $summary; + } + + public function addCollector(SummaryCollectorInterface $collector) + { + $this->collectors[] = $collector; + return $this; + } +} \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy