Вход Регистрация
Файл: vendor/symfony/console/Command/TraceableCommand.php
Строк: 553
<?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 SymfonyComponentConsoleCommand;

use 
SymfonyComponentConsoleApplication;
use 
SymfonyComponentConsoleCompletionCompletionInput;
use 
SymfonyComponentConsoleCompletionCompletionSuggestions;
use 
SymfonyComponentConsoleHelperHelperInterface;
use 
SymfonyComponentConsoleHelperHelperSet;
use 
SymfonyComponentConsoleInputInputDefinition;
use 
SymfonyComponentConsoleInputInputInterface;
use 
SymfonyComponentConsoleOutputConsoleOutputInterface;
use 
SymfonyComponentConsoleOutputOutputInterface;
use 
SymfonyComponentStopwatchStopwatch;

/**
 * @internal
 *
 * @author Jules Pietri <jules@heahprod.com>
 */
final class TraceableCommand extends Command implements SignalableCommandInterface
{
    public 
readonly Command $command;
    public 
int $exitCode;
    public ?
int $interruptedBySignal = null;
    public 
bool $ignoreValidation;
    public 
bool $isInteractive = false;
    public 
string $duration = 'n/a';
    public 
string $maxMemoryUsage = 'n/a';
    public 
InputInterface $input;
    public 
OutputInterface $output;
    
/** @var array<string, mixed> */
    
public array $arguments;
    
/** @var array<string, mixed> */
    
public array $options;
    
/** @var array<string, mixed> */
    
public array $interactiveInputs = [];
    public array 
$handledSignals = [];

    public function 
__construct(
        
Command $command,
        private 
readonly Stopwatch $stopwatch,
    ) {
        if (
$command instanceof LazyCommand) {
            
$command = $command->getCommand();
        }

        
$this->command = $command;

        
// prevent call to self::getDefaultDescription()
        
$this->setDescription($command->getDescription());

        
parent::__construct($command->getName());

        
// init below enables calling {@see parent::run()}
        
[$code, $processTitle, $ignoreValidationErrors] = Closure::bind(function () {
            return [
$this->code, $this->processTitle, $this->ignoreValidationErrors];
        }, 
$command, Command::class)();

        if (
is_callable($code)) {
            
$this->setCode($code);
        }

        if (
$processTitle) {
            
parent::setProcessTitle($processTitle);
        }

        if (
$ignoreValidationErrors) {
            
parent::ignoreValidationErrors();
        }

        
$this->ignoreValidation = $ignoreValidationErrors;
    }

    public function 
__call(string $name, array $arguments): mixed
    
{
        return 
$this->command->{$name}(...$arguments);
    }

    public function 
getSubscribedSignals(): array
    {
        return 
$this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : [];
    }

    public function 
handleSignal(int $signal, int|false $previousExitCode = 0): int|false
    
{
        if (!
$this->command instanceof SignalableCommandInterface) {
            return 
false;
        }

        
$event = $this->stopwatch->start($this->getName().'.handle_signal');

        
$exit = $this->command->handleSignal($signal, $previousExitCode);

        
$event->stop();

        if (!isset(
$this->handledSignals[$signal])) {
            
$this->handledSignals[$signal] = [
                
'handled' => 0,
                
'duration' => 0,
                
'memory' => 0,
            ];
        }

        ++
$this->handledSignals[$signal]['handled'];
        
$this->handledSignals[$signal]['duration'] += $event->getDuration();
        
$this->handledSignals[$signal]['memory'] = max(
            
$this->handledSignals[$signal]['memory'],
            
$event->getMemory() >> 20
        
);

        return 
$exit;
    }

    
/**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    
public function ignoreValidationErrors(): void
    
{
        
$this->ignoreValidation = true;
        
$this->command->ignoreValidationErrors();

        
parent::ignoreValidationErrors();
    }

    public function 
setApplication(?Application $application = null): void
    
{
        
$this->command->setApplication($application);
    }

    public function 
getApplication(): ?Application
    
{
        return 
$this->command->getApplication();
    }

    public function 
setHelperSet(HelperSet $helperSet): void
    
{
        
$this->command->setHelperSet($helperSet);
    }

    public function 
getHelperSet(): ?HelperSet
    
{
        return 
$this->command->getHelperSet();
    }

    public function 
isEnabled(): bool
    
{
        return 
$this->command->isEnabled();
    }

    public function 
complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    
{
        
$this->command->complete($input, $suggestions);
    }

    
/**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    
public function setCode(callable $code): static
    {
        
$this->command->setCode($code);

        return 
parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int {
            
$event = $this->stopwatch->start($this->getName().'.code');

            
$this->exitCode = $code($input, $output);

            
$event->stop();

            return 
$this->exitCode;
        });
    }

    
/**
     * @internal
     */
    
public function mergeApplicationDefinition(bool $mergeArgs = true): void
    
{
        
$this->command->mergeApplicationDefinition($mergeArgs);
    }

    public function 
setDefinition(array|InputDefinition $definition): static
    {
        
$this->command->setDefinition($definition);

        return 
$this;
    }

    public function 
getDefinition(): InputDefinition
    
{
        return 
$this->command->getDefinition();
    }

    public function 
getNativeDefinition(): InputDefinition
    
{
        return 
$this->command->getNativeDefinition();
    }

    public function 
addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|Closure $suggestedValues = []): static
    {
        
$this->command->addArgument($name, $mode, $description, $default, $suggestedValues);

        return 
$this;
    }

    public function 
addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|Closure $suggestedValues = []): static
    {
        
$this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     *
     * Calling parent method is required to be used in {@see parent::run()}.
     */
    
public function setProcessTitle(string $title): static
    {
        
$this->command->setProcessTitle($title);

        return 
parent::setProcessTitle($title);
    }

    public function 
setHelp(string $help): static
    {
        
$this->command->setHelp($help);

        return 
$this;
    }

    public function 
getHelp(): string
    
{
        return 
$this->command->getHelp();
    }

    public function 
getProcessedHelp(): string
    
{
        return 
$this->command->getProcessedHelp();
    }

    public function 
getSynopsis(bool $short = false): string
    
{
        return 
$this->command->getSynopsis($short);
    }

    public function 
addUsage(string $usage): static
    {
        
$this->command->addUsage($usage);

        return 
$this;
    }

    public function 
getUsages(): array
    {
        return 
$this->command->getUsages();
    }

    public function 
getHelper(string $name): HelperInterface
    
{
        return 
$this->command->getHelper($name);
    }

    public function 
run(InputInterface $input, OutputInterface $output): int
    
{
        
$this->input = $input;
        
$this->output = $output;
        
$this->arguments = $input->getArguments();
        
$this->options = $input->getOptions();
        
$event = $this->stopwatch->start($this->getName(), 'command');

        try {
            
$this->exitCode = parent::run($input, $output);
        } finally {
            
$event->stop();

            if (
$output instanceof ConsoleOutputInterface && $output->isDebug()) {
                
$output->getErrorOutput()->writeln((string) $event);
            }

            
$this->duration = $event->getDuration().' ms';
            
$this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB';

            if (
$this->isInteractive) {
                
$this->extractInteractiveInputs($input->getArguments(), $input->getOptions());
            }
        }

        return 
$this->exitCode;
    }

    protected function 
initialize(InputInterface $input, OutputInterface $output): void
    
{
        
$event = $this->stopwatch->start($this->getName().'.init', 'command');

        
$this->command->initialize($input, $output);

        
$event->stop();
    }

    protected function 
interact(InputInterface $input, OutputInterface $output): void
    
{
        if (!
$this->isInteractive = Command::class !== (new ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) {
            return;
        }

        
$event = $this->stopwatch->start($this->getName().'.interact', 'command');

        
$this->command->interact($input, $output);

        
$event->stop();
    }

    protected function 
execute(InputInterface $input, OutputInterface $output): int
    
{
        
$event = $this->stopwatch->start($this->getName().'.execute', 'command');

        
$exitCode = $this->command->execute($input, $output);

        
$event->stop();

        return 
$exitCode;
    }

    private function 
extractInteractiveInputs(array $arguments, array $options): void
    
{
        foreach (
$arguments as $argName => $argValue) {
            if (
array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) {
                continue;
            }

            
$this->interactiveInputs[$argName] = $argValue;
        }

        foreach (
$options as $optName => $optValue) {
            if (
array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) {
                continue;
            }

            
$this->interactiveInputs['--'.$optName] = $optValue;
        }
    }
}
Онлайн: 3
Реклама