Update dependencies

This commit is contained in:
Chris Hunt
2024-02-16 21:36:54 +00:00
parent 22d7a59e59
commit d52ae0d3c3
9569 changed files with 460443 additions and 282416 deletions

View File

@@ -21,12 +21,12 @@ use Symfony\Component\HttpFoundation\Response;
*/
class AjaxDataCollector extends DataCollector
{
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
// all collecting is done client side
}
public function reset()
public function reset(): void
{
// all collecting is done client side
}

View File

@@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @author Fabien Potencier <fabien@symfony.com>
@@ -24,26 +25,24 @@ use Symfony\Component\VarDumper\Caster\ClassStub;
*/
class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
{
/**
* @var KernelInterface
*/
private $kernel;
private KernelInterface $kernel;
/**
* Sets the Kernel associated with this Request.
*/
public function setKernel(KernelInterface $kernel = null)
public function setKernel(?KernelInterface $kernel = null): void
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/http-kernel', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
$this->kernel = $kernel;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data = [
'token' => $response->headers->get('X-Debug-Token'),
@@ -60,15 +59,15 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
'php_timezone' => date_default_timezone_get(),
'xdebug_enabled' => \extension_loaded('xdebug'),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL),
'bundles' => [],
'sapi_name' => \PHP_SAPI,
];
if (isset($this->kernel)) {
foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
$this->data['bundles'][$name] = new ClassStub($bundle::class);
}
}
@@ -78,15 +77,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [];
}
public function lateCollect()
public function lateCollect(): void
{
$this->data = $this->cloneVar($this->data);
}
@@ -108,9 +99,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
}
/**
* Returns the state of the current Symfony release.
*
* @return string One of: unknown, dev, stable, eom, eol
* Returns the state of the current Symfony release
* as one of: unknown, dev, stable, eom, eol.
*/
public function getSymfonyState(): string
{
@@ -126,9 +116,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['symfony_minor_version'];
}
/**
* Returns if the current Symfony version is a Long-Term Support one.
*/
public function isSymfonyLts(): bool
{
return $this->data['symfony_lts'];
@@ -168,9 +155,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['php_version_extra'] ?? null;
}
/**
* @return int The PHP architecture as number of bits (e.g. 32 or 64)
*/
public function getPhpArchitecture(): int
{
return $this->data['php_architecture'];
@@ -199,19 +183,27 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*
* @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set
*/
public function isDebug()
public function isDebug(): bool|string
{
return $this->data['debug'];
}
/**
* Returns true if the XDebug is enabled.
* Returns true if the Xdebug is enabled.
*/
public function hasXDebug(): bool
public function hasXdebug(): bool
{
return $this->data['xdebug_enabled'];
}
/**
* Returns true if the function xdebug_info is available.
*/
public function hasXdebugInfo(): bool
{
return \function_exists('xdebug_info');
}
/**
* Returns true if APCu is enabled.
*/
@@ -228,7 +220,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['zend_opcache_enabled'];
}
public function getBundles()
public function getBundles(): array|Data
{
return $this->data['bundles'];
}
@@ -241,24 +233,16 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['sapi_name'];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'config';
}
/**
* Tries to retrieve information about the current Symfony version.
*
* @return string One of: dev, stable, eom, eol
*/
private function determineSymfonyState(): string
{
$now = new \DateTime();
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
$now = new \DateTimeImmutable();
$eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
$eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
if ($now > $eol) {
$versionState = 'eol';

View File

@@ -33,27 +33,20 @@ abstract class DataCollector implements DataCollectorInterface
*/
protected $data = [];
/**
* @var ClonerInterface
*/
private $cloner;
private ClonerInterface $cloner;
/**
* 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)
protected function cloneVar(mixed $var): Data
{
if ($var instanceof Data) {
return $var;
}
if (null === $this->cloner) {
if (!isset($this->cloner)) {
$this->cloner = new VarCloner();
$this->cloner->setMaxItems(-1);
$this->cloner->addCasters($this->getCasters());
@@ -84,14 +77,14 @@ abstract class DataCollector implements DataCollectorInterface
return $casters;
}
/**
* @return array
*/
public function __sleep()
public function __sleep(): array
{
return ['data'];
}
/**
* @return void
*/
public function __wakeup()
{
}
@@ -99,14 +92,22 @@ abstract class DataCollector implements DataCollectorInterface
/**
* @internal to prevent implementing \Serializable
*/
final protected function serialize()
final protected function serialize(): void
{
}
/**
* @internal to prevent implementing \Serializable
*/
final protected function unserialize($data)
final protected function unserialize(string $data): void
{
}
/**
* @return void
*/
public function reset()
{
$this->data = [];
}
}

View File

@@ -24,8 +24,10 @@ interface DataCollectorInterface extends ResetInterface
{
/**
* Collects data for the given Request and Response.
*
* @return void
*/
public function collect(Request $request, Response $response, \Throwable $exception = null);
public function collect(Request $request, Response $response, ?\Throwable $exception = null);
/**
* Returns the name of the collector.

View File

@@ -11,10 +11,10 @@
namespace Symfony\Component\HttpKernel\DataCollector;
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
@@ -31,23 +31,20 @@ use Symfony\Component\VarDumper\Server\Connection;
*/
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 $sourceContextProvider;
private ?Stopwatch $stopwatch = null;
private string|FileLinkFormatter|false $fileLinkFormat;
private int $dataCount = 0;
private bool $isCollected = true;
private int $clonesCount = 0;
private int $clonesIndex = 0;
private array $rootRefs;
private string $charset;
private ?RequestStack $requestStack;
private DataDumperInterface|Connection|null $dumper;
private mixed $sourceContextProvider;
private bool $webMode;
/**
* @param string|FileLinkFormatter|null $fileLinkFormat
* @param DataDumperInterface|Connection|null $dumper
*/
public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null)
public function __construct(?Stopwatch $stopwatch = null, string|FileLinkFormatter|null $fileLinkFormat = null, ?string $charset = null, ?RequestStack $requestStack = null, DataDumperInterface|Connection|null $dumper = null, ?bool $webMode = null)
{
$fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->stopwatch = $stopwatch;
@@ -55,6 +52,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8';
$this->requestStack = $requestStack;
$this->dumper = $dumper;
$this->webMode = $webMode ?? !\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);
// All clones share these properties by reference:
$this->rootRefs = [
@@ -72,36 +70,37 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
$this->clonesIndex = ++$this->clonesCount;
}
public function dump(Data $data)
public function dump(Data $data): ?string
{
if ($this->stopwatch) {
$this->stopwatch->start('dump');
}
$this->stopwatch?->start('dump');
['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext();
if ($this->dumper instanceof Connection) {
if (!$this->dumper->write($data)) {
$this->isCollected = false;
}
} elseif ($this->dumper) {
$this->doDump($this->dumper, $data, $name, $file, $line);
} else {
if (!$this->dumper || $this->dumper instanceof Connection && !$this->dumper->write($data)) {
$this->isCollected = false;
}
$context = $data->getContext();
$label = $context['label'] ?? '';
unset($context['label']);
$data = $data->withContext($context);
if ($this->dumper && !$this->dumper instanceof Connection) {
$this->doDump($this->dumper, $data, $name, $file, $line, $label);
}
if (!$this->dataCount) {
$this->data = [];
}
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt', 'label');
++$this->dataCount;
if ($this->stopwatch) {
$this->stopwatch->stop('dump');
}
$this->stopwatch?->stop('dump');
return null;
}
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (!$this->dataCount) {
$this->data = [];
@@ -116,32 +115,28 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
if (!$this->requestStack
|| !$response->headers->has('X-Debug-Token')
|| $response->isRedirection()
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html'))
|| ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html'))
|| 'html' !== $request->getRequestFormat()
|| false === strripos($response->getContent(), '</body>')
) {
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) {
if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type') ?? '', 'html')) {
$dumper = new HtmlDumper('php://output', $this->charset);
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
} else {
$dumper = new CliDumper('php://output', $this->charset);
if (method_exists($dumper, 'setDisplayOptions')) {
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
foreach ($this->data as $dump) {
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']);
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');
}
}
}
public function reset()
public function reset(): void
{
if ($this->stopwatch) {
$this->stopwatch->reset();
}
$this->data = [];
$this->stopwatch?->reset();
parent::reset();
$this->dataCount = 0;
$this->isCollected = true;
$this->clonesCount = 0;
@@ -172,7 +167,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
/**
* @internal
*/
public function __wakeup()
public function __wakeup(): void
{
parent::__wakeup();
@@ -238,19 +233,17 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
--$i;
}
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && stripos($h[$i], 'html')) {
if ($this->webMode) {
$dumper = new HtmlDumper('php://output', $this->charset);
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
} else {
$dumper = new CliDumper('php://output', $this->charset);
if (method_exists($dumper, 'setDisplayOptions')) {
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
$dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]);
}
foreach ($this->data as $i => $dump) {
$this->data[$i] = null;
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']);
$this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? '');
}
$this->data = [];
@@ -258,10 +251,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
}
}
private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line)
private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line, string $label): void
{
if ($dumper instanceof CliDumper) {
$contextDumper = function ($name, $file, $line, $fmt) {
$contextDumper = function ($name, $file, $line, $fmt, $label) {
$this->line = '' !== $label ? $this->style('meta', $label).' in ' : '';
if ($this instanceof HtmlDumper) {
if ($file) {
$s = $this->style('meta', '%s');
@@ -275,17 +270,17 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
} else {
$name = $this->style('meta', $name);
}
$this->line = $name.' on line '.$this->style('meta', $line).':';
$this->line .= $name.' on line '.$this->style('meta', $line).':';
} else {
$this->line = $this->style('meta', $name).' on line '.$this->style('meta', $line).':';
$this->line .= $this->style('meta', $name).' on line '.$this->style('meta', $line).':';
}
$this->dumpLine(0);
};
$contextDumper = $contextDumper->bindTo($dumper, $dumper);
$contextDumper($name, $file, $line, $this->fileLinkFormat);
$contextDumper($name, $file, $line, $this->fileLinkFormat, $label);
} else {
$cloner = new VarCloner();
$dumper->dump($cloner->cloneVar($name.' on line '.$line.':'));
$dumper->dump($cloner->cloneVar(('' !== $label ? $label.' in ' : '').$name.' on line '.$line.':'));
}
$dumper->dump($data);
}

View File

@@ -22,89 +22,97 @@ use Symfony\Contracts\Service\ResetInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
*
* @see TraceableEventDispatcher
*
* @final
*/
class EventDataCollector extends DataCollector implements LateDataCollectorInterface
{
protected $dispatcher;
private $requestStack;
private $currentRequest;
public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null)
{
$this->dispatcher = $dispatcher;
$this->requestStack = $requestStack;
}
/** @var iterable<EventDispatcherInterface> */
private iterable $dispatchers;
private ?Request $currentRequest = null;
/**
* {@inheritdoc}
* @param iterable<EventDispatcherInterface>|EventDispatcherInterface|null $dispatchers
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
$this->data = [
'called_listeners' => [],
'not_called_listeners' => [],
'orphaned_events' => [],
];
public function __construct(
iterable|EventDispatcherInterface|null $dispatchers = null,
private ?RequestStack $requestStack = null,
private string $defaultDispatcher = 'event_dispatcher',
) {
if ($dispatchers instanceof EventDispatcherInterface) {
$dispatchers = [$this->defaultDispatcher => $dispatchers];
}
$this->dispatchers = $dispatchers ?? [];
}
public function reset()
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
$this->data = [];
}
if ($this->dispatcher instanceof ResetInterface) {
$this->dispatcher->reset();
public function reset(): void
{
parent::reset();
foreach ($this->dispatchers as $dispatcher) {
if ($dispatcher instanceof ResetInterface) {
$dispatcher->reset();
}
}
}
public function lateCollect()
public function lateCollect(): void
{
if ($this->dispatcher instanceof TraceableEventDispatcher) {
$this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest));
$this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest));
$this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest));
foreach ($this->dispatchers as $name => $dispatcher) {
if (!$dispatcher instanceof TraceableEventDispatcher) {
continue;
}
$this->setCalledListeners($dispatcher->getCalledListeners($this->currentRequest), $name);
$this->setNotCalledListeners($dispatcher->getNotCalledListeners($this->currentRequest), $name);
$this->setOrphanedEvents($dispatcher->getOrphanedEvents($this->currentRequest), $name);
}
$this->data = $this->cloneVar($this->data);
}
/**
* @param array $listeners An array of called listeners
*
* @see TraceableEventDispatcher
*/
public function setCalledListeners(array $listeners)
public function getData(): array|Data
{
$this->data['called_listeners'] = $listeners;
}
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getCalledListeners()
{
return $this->data['called_listeners'];
return $this->data;
}
/**
* @see TraceableEventDispatcher
*/
public function setNotCalledListeners(array $listeners)
public function setCalledListeners(array $listeners, ?string $dispatcher = null): void
{
$this->data['not_called_listeners'] = $listeners;
$this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] = $listeners;
}
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getNotCalledListeners()
public function getCalledListeners(?string $dispatcher = null): array|Data
{
return $this->data['not_called_listeners'];
return $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] ?? [];
}
/**
* @see TraceableEventDispatcher
*/
public function setNotCalledListeners(array $listeners, ?string $dispatcher = null): void
{
$this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] = $listeners;
}
/**
* @see TraceableEventDispatcher
*/
public function getNotCalledListeners(?string $dispatcher = null): array|Data
{
return $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] ?? [];
}
/**
@@ -112,24 +120,19 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter
*
* @see TraceableEventDispatcher
*/
public function setOrphanedEvents(array $events)
public function setOrphanedEvents(array $events, ?string $dispatcher = null): void
{
$this->data['orphaned_events'] = $events;
$this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] = $events;
}
/**
* @see TraceableEventDispatcher
*
* @return array|Data
*/
public function getOrphanedEvents()
public function getOrphanedEvents(?string $dispatcher = null): array|Data
{
return $this->data['orphaned_events'];
return $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] ?? [];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'events';

View File

@@ -22,35 +22,21 @@ use Symfony\Component\HttpFoundation\Response;
*/
class ExceptionDataCollector extends DataCollector
{
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (null !== $exception) {
$this->data = [
'exception' => FlattenException::createFromThrowable($exception),
'exception' => FlattenException::createWithDataRepresentation($exception),
];
}
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->data = [];
}
public function hasException(): bool
{
return isset($this->data['exception']);
}
/**
* @return \Exception|FlattenException
*/
public function getException()
public function getException(): \Exception|FlattenException
{
return $this->data['exception'];
}
@@ -75,9 +61,6 @@ class ExceptionDataCollector extends DataCollector
return $this->data['exception']->getTrace();
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'exception';

View File

@@ -20,6 +20,8 @@ interface LateDataCollectorInterface
{
/**
* Collects data as late as possible.
*
* @return void
*/
public function lateCollect();
}

View File

@@ -15,7 +15,9 @@ use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @author Fabien Potencier <fabien@symfony.com>
@@ -24,47 +26,27 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
*/
class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface
{
private $logger;
private $containerPathPrefix;
private $currentRequest;
private $requestStack;
private $processedLogs;
private ?DebugLoggerInterface $logger;
private ?string $containerPathPrefix;
private ?Request $currentRequest = null;
private ?RequestStack $requestStack;
private ?array $processedLogs = null;
public function __construct(object $logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null)
public function __construct(?object $logger = null, ?string $containerPathPrefix = null, ?RequestStack $requestStack = null)
{
if (null !== $logger && $logger instanceof DebugLoggerInterface) {
$this->logger = $logger;
}
$this->logger = DebugLoggerConfigurator::getDebugLogger($logger);
$this->containerPathPrefix = $containerPathPrefix;
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null;
}
/**
* {@inheritdoc}
*/
public function reset()
public function lateCollect(): void
{
if ($this->logger instanceof DebugLoggerInterface) {
$this->logger->clear();
}
$this->data = [];
}
/**
* {@inheritdoc}
*/
public function lateCollect()
{
if (null !== $this->logger) {
if ($this->logger) {
$containerDeprecationLogs = $this->getContainerDeprecationLogs();
$this->data = $this->computeErrorsCount($containerDeprecationLogs);
// get compiler logs later (only when they are needed) to improve performance
@@ -76,12 +58,12 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
$this->currentRequest = null;
}
public function getLogs()
public function getLogs(): Data|array
{
return $this->data['logs'] ?? [];
}
public function getProcessedLogs()
public function getProcessedLogs(): array
{
if (null !== $this->processedLogs) {
return $this->processedLogs;
@@ -119,14 +101,12 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
}
// sort logs from oldest to newest
usort($logs, static function ($logA, $logB) {
return $logA['timestamp'] <=> $logB['timestamp'];
});
usort($logs, static fn ($logA, $logB) => $logA['timestamp'] <=> $logB['timestamp']);
return $this->processedLogs = $logs;
}
public function getFilters()
public function getFilters(): array
{
$filters = [
'channel' => [],
@@ -157,39 +137,36 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $filters;
}
public function getPriorities()
public function getPriorities(): Data|array
{
return $this->data['priorities'] ?? [];
}
public function countErrors()
public function countErrors(): int
{
return $this->data['error_count'] ?? 0;
}
public function countDeprecations()
public function countDeprecations(): int
{
return $this->data['deprecation_count'] ?? 0;
}
public function countWarnings()
public function countWarnings(): int
{
return $this->data['warning_count'] ?? 0;
}
public function countScreams()
public function countScreams(): int
{
return $this->data['scream_count'] ?? 0;
}
public function getCompilerLogs()
public function getCompilerLogs(): Data
{
return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null));
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'logger';
@@ -222,9 +199,9 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $logs;
}
private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array
private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array
{
if (!is_file($compilerLogsFilepath)) {
if (!$compilerLogsFilepath || !is_file($compilerLogsFilepath)) {
return [];
}
@@ -241,7 +218,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return $logs;
}
private function sanitizeLogs(array $logs)
private function sanitizeLogs(array $logs): array
{
$sanitizedLogs = [];
$silencedLogs = [];
@@ -273,7 +250,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
continue;
}
$errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true);
$errorId = hash('xxh128', "{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true);
if (isset($sanitizedLogs[$errorId])) {
++$sanitizedLogs[$errorId]['errorCount'];

View File

@@ -26,18 +26,12 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
$this->reset();
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->updateMemoryUsage();
}
/**
* {@inheritdoc}
*/
public function reset()
public function reset(): void
{
$this->data = [
'memory' => 0,
@@ -45,10 +39,7 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
];
}
/**
* {@inheritdoc}
*/
public function lateCollect()
public function lateCollect(): void
{
$this->updateMemoryUsage();
}
@@ -58,31 +49,22 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
return $this->data['memory'];
}
/**
* @return int|float
*/
public function getMemoryLimit()
public function getMemoryLimit(): int|float
{
return $this->data['memory_limit'];
}
public function updateMemoryUsage()
public function updateMemoryUsage(): void
{
$this->data['memory'] = memory_get_peak_usage(true);
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'memory';
}
/**
* @return int|float
*/
private function convertToBytes(string $memoryLimit)
private function convertToBytes(string $memoryLimit): int|float
{
if ('-1' === $memoryLimit) {
return -1;
@@ -100,11 +82,11 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
switch (substr($memoryLimit, -1)) {
case 't': $max *= 1024;
// no break
// no break
case 'g': $max *= 1024;
// no break
// no break
case 'm': $max *= 1024;
// no break
// no break
case 'k': $max *= 1024;
}

View File

@@ -34,20 +34,17 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
/**
* @var \SplObjectStorage<Request, callable>
*/
private $controllers;
private $sessionUsages = [];
private $requestStack;
private \SplObjectStorage $controllers;
private array $sessionUsages = [];
private ?RequestStack $requestStack;
public function __construct(RequestStack $requestStack = null)
public function __construct(?RequestStack $requestStack = null)
{
$this->controllers = new \SplObjectStorage();
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
// attributes are serialized and as they can be anything, they need to be converted to strings.
$attributes = [];
@@ -110,7 +107,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'session_metadata' => $sessionMetadata,
'session_attributes' => $sessionAttributes,
'session_usages' => array_values($this->sessionUsages),
'stateless_check' => $this->requestStack && ($mainRequest = $this->requestStack->getMainRequest()) && $mainRequest->attributes->get('_stateless', false),
'stateless_check' => $this->requestStack?->getMainRequest()?->attributes->get('_stateless') ?? false,
'flashes' => $flashes,
'path_info' => $request->getPathInfo(),
'controller' => 'n/a',
@@ -139,7 +136,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
continue;
}
if ('request_headers' === $key || 'response_headers' === $key) {
$this->data[$key] = array_map(function ($v) { return isset($v[0]) && !isset($v[1]) ? $v[0] : $v; }, $value);
$this->data[$key] = array_map(fn ($v) => isset($v[0]) && !isset($v[1]) ? $v[0] : $v, $value);
}
}
@@ -176,108 +173,144 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
}
public function lateCollect()
public function lateCollect(): void
{
$this->data = $this->cloneVar($this->data);
}
public function reset()
public function reset(): void
{
$this->data = [];
parent::reset();
$this->controllers = new \SplObjectStorage();
$this->sessionUsages = [];
}
public function getMethod()
public function getMethod(): string
{
return $this->data['method'];
}
public function getPathInfo()
public function getPathInfo(): string
{
return $this->data['path_info'];
}
/**
* @return ParameterBag
*/
public function getRequestRequest()
{
return new ParameterBag($this->data['request_request']->getValue());
}
/**
* @return ParameterBag
*/
public function getRequestQuery()
{
return new ParameterBag($this->data['request_query']->getValue());
}
/**
* @return ParameterBag
*/
public function getRequestFiles()
{
return new ParameterBag($this->data['request_files']->getValue());
}
/**
* @return ParameterBag
*/
public function getRequestHeaders()
{
return new ParameterBag($this->data['request_headers']->getValue());
}
/**
* @return ParameterBag
*/
public function getRequestServer(bool $raw = false)
{
return new ParameterBag($this->data['request_server']->getValue($raw));
}
/**
* @return ParameterBag
*/
public function getRequestCookies(bool $raw = false)
{
return new ParameterBag($this->data['request_cookies']->getValue($raw));
}
/**
* @return ParameterBag
*/
public function getRequestAttributes()
{
return new ParameterBag($this->data['request_attributes']->getValue());
}
/**
* @return ParameterBag
*/
public function getResponseHeaders()
{
return new ParameterBag($this->data['response_headers']->getValue());
}
/**
* @return ParameterBag
*/
public function getResponseCookies()
{
return new ParameterBag($this->data['response_cookies']->getValue());
}
public function getSessionMetadata()
public function getSessionMetadata(): array
{
return $this->data['session_metadata']->getValue();
}
public function getSessionAttributes()
public function getSessionAttributes(): array
{
return $this->data['session_attributes']->getValue();
}
public function getStatelessCheck()
public function getStatelessCheck(): bool
{
return $this->data['stateless_check'];
}
public function getSessionUsages()
public function getSessionUsages(): Data|array
{
return $this->data['session_usages'];
}
public function getFlashes()
public function getFlashes(): array
{
return $this->data['flashes']->getValue();
}
/**
* @return string|resource
*/
public function getContent()
{
return $this->data['content'];
}
/**
* @return bool
*/
public function isJsonRequest()
{
return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']);
}
/**
* @return string|null
*/
public function getPrettyJson()
{
$decoded = json_decode($this->getContent());
@@ -285,31 +318,34 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null;
}
public function getContentType()
public function getContentType(): string
{
return $this->data['content_type'];
}
public function getStatusText()
public function getStatusText(): string
{
return $this->data['status_text'];
}
public function getStatusCode()
public function getStatusCode(): int
{
return $this->data['status_code'];
}
public function getFormat()
public function getFormat(): string
{
return $this->data['format'];
}
public function getLocale()
public function getLocale(): string
{
return $this->data['locale'];
}
/**
* @return ParameterBag
*/
public function getDotenvVars()
{
return new ParameterBag($this->data['dotenv_vars']->getValue());
@@ -325,7 +361,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return $this->data['route'];
}
public function getIdentifier()
public function getIdentifier(): string
{
return $this->data['identifier'];
}
@@ -346,7 +382,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* @return array|string|Data The controller as a string or array of data
* with keys 'class', 'method', 'file' and 'line'
*/
public function getController()
public function getController(): array|string|Data
{
return $this->data['controller'];
}
@@ -357,22 +393,22 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
* @return array|Data|false A legacy array of data from the previous redirection response
* or false otherwise
*/
public function getRedirect()
public function getRedirect(): array|Data|false
{
return $this->data['redirect'] ?? false;
}
public function getForwardToken()
public function getForwardToken(): ?string
{
return $this->data['forward_token'] ?? null;
}
public function onKernelController(ControllerEvent $event)
public function onKernelController(ControllerEvent $event): void
{
$this->controllers[$event->getRequest()] = $event->getController();
}
public function onKernelResponse(ResponseEvent $event)
public function onKernelResponse(ResponseEvent $event): void
{
if (!$event->isMainRequest()) {
return;
@@ -391,9 +427,6 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'request';
@@ -431,11 +464,9 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
/**
* @param string|object|array|null $controller The controller to parse
*
* @return array|string An array of controller data or a simple string
*/
private function parseController($controller)
private function parseController(array|object|string|null $controller): array|string
{
if (\is_string($controller) && str_contains($controller, '::')) {
$controller = explode('::', $controller);
@@ -451,7 +482,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
];
} catch (\ReflectionException $e) {
} catch (\ReflectionException) {
if (\is_callable($controller)) {
// using __call or __callStatic
return [
@@ -479,7 +510,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
}
$controller['method'] = $r->name;
if ($class = $r->getClosureScopeClass()) {
if ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
$controller['class'] = $class->name;
} else {
return $r->name;

View File

@@ -32,11 +32,9 @@ class RouterDataCollector extends DataCollector
}
/**
* {@inheritdoc}
*
* @final
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if ($response instanceof RedirectResponse) {
$this->data['redirect'] = true;
@@ -50,6 +48,9 @@ class RouterDataCollector extends DataCollector
unset($this->controllers[$request]);
}
/**
* @return void
*/
public function reset()
{
$this->controllers = new \SplObjectStorage();
@@ -61,13 +62,18 @@ class RouterDataCollector extends DataCollector
];
}
protected function guessRoute(Request $request, $controller)
/**
* @return string
*/
protected function guessRoute(Request $request, string|object|array $controller)
{
return 'n/a';
}
/**
* Remembers the controller associated to each request.
*
* @return void
*/
public function onKernelController(ControllerEvent $event)
{
@@ -77,31 +83,22 @@ class RouterDataCollector extends DataCollector
/**
* @return bool Whether this request will result in a redirect
*/
public function getRedirect()
public function getRedirect(): bool
{
return $this->data['redirect'];
}
/**
* @return string|null
*/
public function getTargetUrl()
public function getTargetUrl(): ?string
{
return $this->data['url'];
}
/**
* @return string|null
*/
public function getTargetRoute()
public function getTargetRoute(): ?string
{
return $this->data['route'];
}
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'router';
}

View File

@@ -24,19 +24,17 @@ use Symfony\Component\Stopwatch\StopwatchEvent;
*/
class TimeDataCollector extends DataCollector implements LateDataCollectorInterface
{
private $kernel;
private $stopwatch;
private ?KernelInterface $kernel;
private ?Stopwatch $stopwatch;
public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null)
public function __construct(?KernelInterface $kernel = null, ?Stopwatch $stopwatch = null)
{
$this->kernel = $kernel;
$this->stopwatch = $stopwatch;
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (null !== $this->kernel) {
$startTime = $this->kernel->getStartTime();
@@ -52,22 +50,14 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
];
}
/**
* {@inheritdoc}
*/
public function reset()
public function reset(): void
{
$this->data = [];
$this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0];
if (null !== $this->stopwatch) {
$this->stopwatch->reset();
}
$this->stopwatch?->reset();
}
/**
* {@inheritdoc}
*/
public function lateCollect()
public function lateCollect(): void
{
if (null !== $this->stopwatch && isset($this->data['token'])) {
$this->setEvents($this->stopwatch->getSectionEvents($this->data['token']));
@@ -78,7 +68,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
/**
* @param StopwatchEvent[] $events The request events
*/
public function setEvents(array $events)
public function setEvents(array $events): void
{
foreach ($events as $event) {
$event->ensureStopped();
@@ -133,9 +123,6 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
return $this->data['stopwatch_installed'];
}
/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'time';