235 lines
6.5 KiB
PHP
235 lines
6.5 KiB
PHP
|
<?php
|
||
|
|
||
|
/*
|
||
|
* This file is part of the Symfony package.
|
||
|
*
|
||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||
|
*
|
||
|
* For the full copyright and license information, please view the LICENSE
|
||
|
* file that was distributed with this source code.
|
||
|
*/
|
||
|
|
||
|
namespace Symfony\Component\Console\DataCollector;
|
||
|
|
||
|
use Symfony\Component\Console\Command\Command;
|
||
|
use Symfony\Component\Console\Debug\CliRequest;
|
||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||
|
use Symfony\Component\Console\SignalRegistry\SignalMap;
|
||
|
use Symfony\Component\HttpFoundation\Request;
|
||
|
use Symfony\Component\HttpFoundation\Response;
|
||
|
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||
|
use Symfony\Component\VarDumper\Cloner\Data;
|
||
|
|
||
|
/**
|
||
|
* @internal
|
||
|
*
|
||
|
* @author Jules Pietri <jules@heahprod.com>
|
||
|
*/
|
||
|
final class CommandDataCollector extends DataCollector
|
||
|
{
|
||
|
public function collect(Request $request, Response $response, \Throwable $exception = null): void
|
||
|
{
|
||
|
if (!$request instanceof CliRequest) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$command = $request->command;
|
||
|
$application = $command->getApplication();
|
||
|
|
||
|
$this->data = [
|
||
|
'command' => $this->cloneVar($command->command),
|
||
|
'exit_code' => $command->exitCode,
|
||
|
'interrupted_by_signal' => $command->interruptedBySignal,
|
||
|
'duration' => $command->duration,
|
||
|
'max_memory_usage' => $command->maxMemoryUsage,
|
||
|
'verbosity_level' => match ($command->output->getVerbosity()) {
|
||
|
OutputInterface::VERBOSITY_QUIET => 'quiet',
|
||
|
OutputInterface::VERBOSITY_NORMAL => 'normal',
|
||
|
OutputInterface::VERBOSITY_VERBOSE => 'verbose',
|
||
|
OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose',
|
||
|
OutputInterface::VERBOSITY_DEBUG => 'debug',
|
||
|
},
|
||
|
'interactive' => $command->isInteractive,
|
||
|
'validate_input' => !$command->ignoreValidation,
|
||
|
'enabled' => $command->isEnabled(),
|
||
|
'visible' => !$command->isHidden(),
|
||
|
'input' => $this->cloneVar($command->input),
|
||
|
'output' => $this->cloneVar($command->output),
|
||
|
'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs),
|
||
|
'signalable' => $command->getSubscribedSignals(),
|
||
|
'handled_signals' => $command->handledSignals,
|
||
|
'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())),
|
||
|
];
|
||
|
|
||
|
$baseDefinition = $application->getDefinition();
|
||
|
|
||
|
foreach ($command->arguments as $argName => $argValue) {
|
||
|
if ($baseDefinition->hasArgument($argName)) {
|
||
|
$this->data['application_inputs'][$argName] = $this->cloneVar($argValue);
|
||
|
} else {
|
||
|
$this->data['arguments'][$argName] = $this->cloneVar($argValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach ($command->options as $optName => $optValue) {
|
||
|
if ($baseDefinition->hasOption($optName)) {
|
||
|
$this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue);
|
||
|
} else {
|
||
|
$this->data['options'][$optName] = $this->cloneVar($optValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function getName(): string
|
||
|
{
|
||
|
return 'command';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array{
|
||
|
* class?: class-string,
|
||
|
* executor?: string,
|
||
|
* file: string,
|
||
|
* line: int,
|
||
|
* }
|
||
|
*/
|
||
|
public function getCommand(): array
|
||
|
{
|
||
|
$class = $this->data['command']->getType();
|
||
|
$r = new \ReflectionMethod($class, 'execute');
|
||
|
|
||
|
if (Command::class !== $r->getDeclaringClass()) {
|
||
|
return [
|
||
|
'executor' => $class.'::'.$r->name,
|
||
|
'file' => $r->getFileName(),
|
||
|
'line' => $r->getStartLine(),
|
||
|
];
|
||
|
}
|
||
|
|
||
|
$r = new \ReflectionClass($class);
|
||
|
|
||
|
return [
|
||
|
'class' => $class,
|
||
|
'file' => $r->getFileName(),
|
||
|
'line' => $r->getStartLine(),
|
||
|
];
|
||
|
}
|
||
|
|
||
|
public function getInterruptedBySignal(): ?string
|
||
|
{
|
||
|
if (isset($this->data['interrupted_by_signal'])) {
|
||
|
return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']);
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public function getDuration(): string
|
||
|
{
|
||
|
return $this->data['duration'];
|
||
|
}
|
||
|
|
||
|
public function getMaxMemoryUsage(): string
|
||
|
{
|
||
|
return $this->data['max_memory_usage'];
|
||
|
}
|
||
|
|
||
|
public function getVerbosityLevel(): string
|
||
|
{
|
||
|
return $this->data['verbosity_level'];
|
||
|
}
|
||
|
|
||
|
public function getInteractive(): bool
|
||
|
{
|
||
|
return $this->data['interactive'];
|
||
|
}
|
||
|
|
||
|
public function getValidateInput(): bool
|
||
|
{
|
||
|
return $this->data['validate_input'];
|
||
|
}
|
||
|
|
||
|
public function getEnabled(): bool
|
||
|
{
|
||
|
return $this->data['enabled'];
|
||
|
}
|
||
|
|
||
|
public function getVisible(): bool
|
||
|
{
|
||
|
return $this->data['visible'];
|
||
|
}
|
||
|
|
||
|
public function getInput(): Data
|
||
|
{
|
||
|
return $this->data['input'];
|
||
|
}
|
||
|
|
||
|
public function getOutput(): Data
|
||
|
{
|
||
|
return $this->data['output'];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Data[]
|
||
|
*/
|
||
|
public function getArguments(): array
|
||
|
{
|
||
|
return $this->data['arguments'] ?? [];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Data[]
|
||
|
*/
|
||
|
public function getOptions(): array
|
||
|
{
|
||
|
return $this->data['options'] ?? [];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Data[]
|
||
|
*/
|
||
|
public function getApplicationInputs(): array
|
||
|
{
|
||
|
return $this->data['application_inputs'] ?? [];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Data[]
|
||
|
*/
|
||
|
public function getInteractiveInputs(): array
|
||
|
{
|
||
|
return $this->data['interactive_inputs'] ?? [];
|
||
|
}
|
||
|
|
||
|
public function getSignalable(): array
|
||
|
{
|
||
|
return array_map(
|
||
|
static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
|
||
|
$this->data['signalable']
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function getHandledSignals(): array
|
||
|
{
|
||
|
$keys = array_map(
|
||
|
static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
|
||
|
array_keys($this->data['handled_signals'])
|
||
|
);
|
||
|
|
||
|
return array_combine($keys, array_values($this->data['handled_signals']));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Data[]
|
||
|
*/
|
||
|
public function getHelperSet(): array
|
||
|
{
|
||
|
return $this->data['helper_set'] ?? [];
|
||
|
}
|
||
|
|
||
|
public function reset(): void
|
||
|
{
|
||
|
$this->data = [];
|
||
|
}
|
||
|
}
|