使用Controller

时间:2016-10-06 09:31:53

标签: symfony console sudo

我正在使用symfony实现一个Web界面,它允许一些系统限制命令。

为了更好地分离我的代码逻辑,我创建了一些控制台命令,如:

app/console system:do-restricted --option

然后我从控制器中调用这样的命令:

$status = $console->run(new ArrayInput([
    'command' => 'system:do-restricted',
    '--option' => true
]), $output = new BufferedOutput());

有没有办法允许sudo控制台命令?

我认为唯一的方法是将上述命令重新转换为shell表单并使用Process,在这种情况下,有一种简单的方法可以将InputArray转换为命令,将stdout转换为OutputBaffer(+ ansi colors)?

1 个答案:

答案 0 :(得分:0)

最后,我已经实现了这个类来代替symfony的Console\Application

<?php

namespace Acme\Model;

use Symfony\Component\Process\Process;
use Symfony\Component\Console\Input\ArrayInput;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Output\OutputInterface;

final class Console implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    private $consoleCommand;

    public function __construct($consoleCommand = 'sudo app/console')
    {
        $this->consoleCommand = $consoleCommand;
    }

    /**
    * Create a process for console command.
    *
    * @param string  $command
    * @param array[] $argv    Same syntax as symfony ArrayInput
    *
    * @see Symfony\Component\Console\Input\ArrayInput
    */
    public function process($command, array $argv = [])
    {
        $console = escapeshellcmd($this->consoleCommand);

        $command = escapeshellarg($command);

        $options = [];

        $arguments = [];

        foreach ($argv as $name => $value) {
            if ('--' === substr($name, 0, 2)) {
                if (false === $value) {
                    continue;
                }
                $option = $name;
                if (is_string($value)) {
                    $option .= '='.$value;
                }
                $options[] = escapeshellarg($option);
            } else {
                $arguments[] = escapeshellarg($value);
            }
        }

        $process = new Process(
            $console.' '
            .$command.' '
            .implode(' ', $options).' '
            .implode(' ', $arguments)
        );

        if ($this->logger) {
            $this->logger->info(sprintf('Created process for command: %s', $process->getCommandLine()));
        }

        return $process;
    }

    /**
    * Run a console command.
    *
    * @param string               $command One of the 'app/console' commands
    * @param array[]              $argv    Assoc array '--opt' => true/false, '--opt' => 'value' or 'arg_name' => 'arg_value'
    * @param OutputInterface|null $output  Output object
    *
    * @see Symfony\Component\Console\Input\ArrayInput
    */
    public function run($command, array $argv = [], OutputInterface $output = null)
    {
        if ($output->isDecorated()) {
            $argv['--ansi'] = true;
        }
        $process = $this->process($command, $argv);

        $callable = null;
        if (null !== $output) {
            $callable = function ($type, $line) use ($output) {
                $output->writeln($line);
            };
        }

        $exitCode = $process->run($callable);

        if ($this->logger) {
            $this->logger->info(sprintf('Command returned: %d', $exitCode), ['output' => $output]);
        }

        return $exitCode;
    }
}

然后我称之为:

$status = $this->console->run(
    'balancer:cluster:copy-config',
    ['--option' => true, '--opt-val' => 'value', 'arg1' => 'value1'],
    $output = new BufferedOutput()
);