我在想如何從瀏覽器查詢或從控制器運行Symfony 2命令。如何從控制器運行symfony 2運行命令
因爲我沒有任何可能託管運行它,並且每個cron作業都由admin設置。
我甚至沒有啓用exec()
函數,所以當我想測試它時,我必須將所有內容從命令複製到某個測試控制器,這不是最好的解決方案。
我在想如何從瀏覽器查詢或從控制器運行Symfony 2命令。如何從控制器運行symfony 2運行命令
因爲我沒有任何可能託管運行它,並且每個cron作業都由admin設置。
我甚至沒有啓用exec()
函數,所以當我想測試它時,我必須將所有內容從命令複製到某個測試控制器,這不是最好的解決方案。
見official documentation在這個問題上進行的Symfony的新版本
你不需要從控制器命令執行服務,我想,這最好是通過run
方法調用命令,而不是通過控制檯字符串輸入,但是official docs建議您通過別名調用命令。另請參閱this answer。在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, $ouput);
在我的環境(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);
}
這裏有一個替代方案,可以讓你執行命令爲字符串你會在控制檯上以同樣的方式(也沒有必要爲這一個定義服務)。
你可以檢查this bundle's controller看看它是如何完成所有的細節。在這裏,我將總結它省略某些細節(例如處理環境,所以這裏所有命令都會在它們被調用的相同環境中運行)。
如果你只想從瀏覽器中運行的命令,你可以使用捆綁,因爲它是,但如果你想從任意控制器運行命令在這裏是如何做到這一點:
在你的控制器定義這樣的功能:
public function dumpassetsAction()
{
$output = $this->execute('assetic:dump');
return new Response($output);
}
此外,您還需要定義一個類來作爲輸出緩衝器,b:
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;
}
然後你可以從這樣一個動作調用它ecause有沒有框架提供:
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;
}
}
在LiipFunctionalTestBundle中還有一個相當不錯的實現,它使用php:// temp stream和內置的StreamOutput類來捕獲輸出,所以你不需要自己創建第二個輸出緩衝類。 https://github.com/liip/LiipFunctionalTestBundle/blob/master/Test/WebTestCase.php#L102 – Cvuorinen
請注意,自從Symfony 2.4發佈以來,現在已經可以使用BufferedOutput了。 – noisebleed
如果您必須傳遞參數(和/或選項),那麼在v2.0.12中(對於更高版本可能爲true),您需要在實例化輸入對象之前指定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();
}
一樣@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);
}
你可以只是簡單的創建一個instanc你的命令的e和運行它:
/**
* @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();
}
您可以使用此包從運行控制器(http請求)Symfony2的命令,並通過在URL選項/參數。
如果運行所需要的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
設置爲該命令,因爲它不在其定義中。
Silex Application擴展了Pimple Container並實現了HttpKernelInterface,TerminableInterface,並且沒有'setDefinition'方法。 – Trix
+1爲'--some-option'示例 – gondo
我沒有在2.4中使用'setContainer'方法 – RedactedProfile
@DJDarkViper查看更新後的答案。 – Dmitriy