我想知道我怎么可以从浏览器查询或控制器运行的Symfony 2命令。
它的,因为我没有上托管运行它和每一个cron作业是由管理员设置好的任何可能性。
我甚至不启用exec()
函数,所以当我想测试它,我必须从命令的所有内容复制到一些测试控制器,这是不是最好的解决办法。
我想知道我怎么可以从浏览器查询或控制器运行的Symfony 2命令。
它的,因为我没有上托管运行它和每一个cron作业是由管理员设置好的任何可能性。
我甚至不启用exec()
函数,所以当我想测试它,我必须从命令的所有内容复制到一些测试控制器,这是不是最好的解决办法。
请参见官方文件对这一问题进行的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
,否则出现了错误。
注册您的命令,作为一个服务,不要忘了打电话给setContainer
MyCommandService:
class: MyBundle\Command\MyCommand
calls:
- [setContainer, ["@service_container"] ]
在你的控制器,你只需要得到这个服务,并调用与权利参数的execute方法
设置与输入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);
在我的环境(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);
}
下面是一个可以让你执行命令为字符串你会在控制台上以同样的方式替代(也没有必要为这一个定义服务)。
您可以检查这个包的控制器 ,看看它是如何的所有细节进行。 在这里,我要总结一下ommiting某些细节(如处理环境,所以这里所有的命令将在它们被调用同一个环境中运行)。
如果你只想从浏览器中运行的命令,你可以使用捆绑,因为它是,但如果你想从任意控制器运行命令这里是如何做到这一点:
在您的控制器这样定义一个函数:
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;
}
}
你可以只是简单的创建命令的实例,并运行它:
/**
* @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();
}
同@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);
}
如果你有来传递参数(和/或选项),然后在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();
}
可以使用此束运行从控制器(http请求)Symfony2的命令,并通过在URL选项/参数。
https://github.com/mrafalko/CommandRunnerBundle
如果您运行所需要的命令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
,因为它不是在其定义的命令。