45

我想知道如何从浏览器查询或控制器运行Symfony 2命令。

这是因为我没有任何可能在托管上运行它,并且每个 cron 作业都是由管理员设置的。

我什至没有启用exec()功能,所以当我想测试它时,我必须将所有内容从命令复制到某个测试控制器,这不是最好的解决方案。

4

9 回答 9

66

有关较新版本的 Symfony,请参阅有关此问题的官方文档


您不需要从控制器执行命令的服务,我认为最好通过run方法而不是通过控制台字符串输入调用命令,但是官方文档建议您通过它的别名调用命令。另外,请参阅此答案。在 Symfony 2.1-2.6 上测试。

您的命令类必须扩展ContainerAwareCommand

// Your command

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

class MyCommand extends ContainerAwareCommand {
    // …
}


// Your controller

use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;

class SomeController extends Controller {

    // …

    public function myAction()
    {
        $command = new MyCommand();
        $command->setContainer($this->container);
        $input = new ArrayInput(array('some-param' => 10, '--some-option' => true));
        $output = new NullOutput();
        $resultCode = $command->run($input, $output);
    }
}

在大多数情况下,您不需要BufferedOutput(来自Jbm 的回答)并且检查一下就足够了$resultCode is 0,否则会出现错误。

于 2013-08-07T11:29:43.653 回答
57

将您的命令注册为服务,不要忘记调用setContainer

MyCommandService:
    class: MyBundle\Command\MyCommand
    calls:
        - [setContainer, ["@service_container"] ]

在您的控制器中,您只需要获取此服务,并使用权限参数调用执行方法

使用方法设置输入setArgument

$input = new Symfony\Component\Console\Input\ArgvInput([]);
$input->setArgument('arg1', 'value');
$output = new Symfony\Component\Console\Output\ConsoleOutput();

调用run命令的方法:

$command = $this->get('MyCommandService');
$command->run($input, $output);
于 2012-05-08T12:58:19.010 回答
10

在我的环境( Symony 2.1 )中,我必须对@Reuven 解决方案进行一些修改才能使其正常工作。他们来了:

服务定义 - 没有变化。

在控制器中:

use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;

...

public function myAction() {
    $command = $this->get('MyCommandService');

    $input = new ArgvInput(array('arg1'=> 'value'));
    $output = new ConsoleOutput();

    $command->run($input, $output);
}
于 2012-12-13T09:38:54.407 回答
4

您可以简单地创建一个命令实例并运行它:

/**
 * @Route("/run-command")
 */
public function someAction()
{
    // Running the command
    $command = new YourCommand();
    $command->setContainer($this->container);

    $input = new ArrayInput(['--your_argument' => true]);
    $output = new ConsoleOutput();

    $command->run($input, $output);

    return new Response();
}
于 2013-12-20T14:04:59.757 回答
3

这是一种替代方法,可让您以与在控制台上相同的方式将命令作为字符串执行(无需使用此定义服务)。

您可以检查此捆绑包的控制器以了解它是如何处理所有详细信息的。在这里,我将对其进行总结,省略某些细节(例如处理环境,因此这里所有命令都将在它们被调用的同一环境中运行)。

如果您只想从浏览器运行命令,则可以按原样使用该捆绑包,但如果您想从任意控制器运行命令,请执行以下操作:

在你的控制器中定义一个这样的函数:

use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\StringInput;

private function execute($command)
{
    $app = new Application($this->get('kernel'));
    $app->setAutoExit(false);

    $input = new StringInput($command);
    $output = new BufferedOutput();

    $error = $app->run($input, $output);

    if($error != 0)
        $msg = "Error: $error";
    else
        $msg = $output->getBuffer();
    return $msg;
}

然后你可以从这样的动作中调用它:

public function dumpassetsAction()
{
    $output = $this->execute('assetic:dump');

    return new Response($output);
}

此外,您需要定义一个类作为输出缓冲区,因为框架没有提供:

use Symfony\Component\Console\Output\Output;

class BufferedOutput extends Output
{
    public function doWrite($message, $newline)
    {
        $this->buffer .= $message. ($newline? PHP_EOL: '');
    }

    public function getBuffer()
    {
        return $this->buffer;
    }
}
于 2013-03-29T21:45:10.920 回答
2

与@malloc 相同,但

use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;

...

public function myAction() {
  $command = $this->get('MyCommandService');

  // $input[0] : command name
  // $input[1] : argument1
  $input = new ArgvInput(array('my:command', 'arg1'));
  $output = new ConsoleOutput();

  $command->run($input, $output);
}
于 2013-12-18T23:23:48.447 回答
1

如果您必须传递参数(和/或选项),那么在 v2.0.12 中(可能适用于更高版本),您需要在实例化输入对象之前先指定 InputDefinition。

use // you will need the following
    Symfony\Component\Console\Input\InputOption,
    Symfony\Component\Console\Input\InputArgument,
    Symfony\Component\Console\Input\InputDefinition,
    Symfony\Component\Console\Input\ArgvInput,
    Symfony\Component\Console\Output\NullOutput;


// tell symfony what to expect in the input
$inputDefinition = new InputDefinition(array(
    new InputArgument('myArg1', InputArgument::REQUIRED),
    new InputArgument('myArg2', InputArgument::REQUIRED),
    new InputOption('debug', '0', InputOption::VALUE_OPTIONAL),
));


// then pass the values for arguments to constructor, however make sure 
// first param is dummy value (there is an array_shift() in ArgvInput's constructor)
$input = new ArgvInput(
                        array(
                                'dummySoInputValidates' => 'dummy', 
                                'myArg2' => 'myValue1', 
                                'myArg2' => 'myValue2'), 
                        $inputDefinition);
$output = new NullOutput();



附带说明一下,如果您在命令中使用 getContainer(),则以下函数可能对您的 command.php 很方便:

/**
 * Inject a dependency injection container, this is used when using the 
 * command as a service
 * 
 */
function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null)
{
    $this->container = $container;
}

/**
 * Since we are using command as a service, getContainer() is not available
 * hence we need to pass the container (via services.yml) and use this function to switch
 * between conatiners..
 *
 */
public function getcontainer()
{
    if (is_object($this->container))
        return $this->container;

    return parent::getcontainer();
}
于 2013-11-06T21:09:48.627 回答
0

您可以使用此捆绑包从控制器(http 请求)运行 Symfony2 命令并在 URL 中传递选项/参数。

https://github.com/mrafalko/CommandRunnerBundle

于 2014-04-30T20:11:41.443 回答
0

如果您运行需要env类似选项的命令assetic:dump

$stdout->writeln(sprintf('Dumping all <comment>%s</comment> assets.', $input->getOption('env')));

您必须像这样创建Symfony\Component\Console\Application并设置定义:

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\NullOuput;

// Create and run the command of assetic
$app = new Application();
$app->setDefinition(new InputDefinition([
    new InputOption('env', '', InputOption::VALUE_OPTIONAL, '', 'prod')
]));
$app->add(new DumpCommand());

/** @var DumpCommand $command */
$command = $app->find('assetic:dump');
$command->setContainer($this->container);
$input = new ArgvInput([
    'command' => 'assetic:dump',
    'write_to' => $this->assetsDir
]);
$output = new NullOutput();
$command->run($input, $output);

您无法将选项设置env为命令,因为它不在其定义中。

于 2015-04-16T15:15:03.093 回答