我怎样才能从控制器运行symfony 2运行命令
我想知道如何从浏览器查询或从控制器运行Symfony 2命令。
因为我没有任何可能托pipe运行它,每个cron作业都由pipe理员设置。
我甚至没有启用exec()
函数,所以当我想testing它时,我必须将所有内容从命令复制到某个testing控制器,这不是最好的解决scheme。
你不需要从控制器执行命令的服务,我认为,最好是通过run
方法调用命令,而不是通过控制台stringinput,但官方文档build议你通过它的别名调用命令。 另外,看到这个答案 。 在Symfony 2.1-2.6上testing。
您的命令类必须扩展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
就足够了,否则会出错。
注册您的命令作为服务,不要忘记调用setContainer
MyCommandService: class: MyBundle\Command\MyCommand calls: - [setContainer, ["@service_container"] ]
在你的控制器中,你只需要得到这个服务,然后用权限参数调用execute方法
使用setArgument
方法设置input:
$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, $ouput);
在我的环境中(Symony 2.1),我必须对@Reuven解决scheme进行一些修改才能使其工作。 他们来了:
服务定义 – 不变。
在控制器中:
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); }
这里有一个替代scheme,可以让你像控制台一样以string的forms执行命令(不需要用这个命令定义服务)。
你可以检查这个包的控制器 ,看看它是如何完成所有的细节。 在这里我将总结一些细节(比如处理环境,所以这里所有的命令都会在它们被调用的同一个环境中运行)。
如果你只是想从浏览器运行命令,你可以直接使用这个bundle,但是如果你想从一个任意的控制器运行命令,可以这样做:
在你的控制器中定义一个这样的函数:
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; } }
与@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); }
你可以简单地创build一个你的命令的实例并运行它:
/** * @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(); }
如果必须传递参数(和/或选项),那么在v2.0.12中(对于更高版本可能是true),则需要在实例化input对象之前指定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(); }
你可以使用这个包来从控制器(http请求)运行Symfony2命令,并传递URL中的选项/参数。
如果你运行一个需要env
选项的命令,像assetic:dump
$stdout->writeln(sprintf('Dumping all <comment>%s</comment> assets.', $input->getOption('env')));
您必须创build一个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
设置为该命令,因为它不在其定义中。