¿Cómo puedo ejecutar el comando de ejecución Symfony 2 desde el controlador

Me pregunto cómo puedo ejecutar el comando Symfony 2 desde la consulta del navegador o desde el controlador.

Es porque no tengo ninguna posibilidad de alojamiento para ejecutarlo y cada tarea cron es configurada por el administrador.

Ni siquiera tengo habilitada la función exec() así que cuando quiero probarla, debo copiar todo el contenido del comando a algún controlador de prueba y esta no es la mejor solución.

Consulte la documentación oficial sobre este tema para las versiones más recientes de Symfony


No necesita servicios para la ejecución de comandos desde el controlador y, creo, es mejor llamar al comando a través del método de run y no a través de la entrada de cadena de la consola, sin embargo, los documentos oficiales sugieren que llame al comando a través de su alias. Además, mira esta respuesta . Probado en Symfony 2.1-2.6.

Su clase de comando debe extender 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); } } 

En la mayoría de los casos, no necesita BufferedOutput (de la respuesta de Jbm ) y es suficiente para verificar que $resultCode is 0 ; de lo contrario, habría un error.

Registre su comando como un servicio y no olvide llamar a setContainer

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

En su controlador, solo tendrá que obtener este servicio y llamar al método de ejecución con los argumentos de derechos

Establezca la entrada con el método setArgument :

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

Llame al método de run del comando:

 $command = $this->get('MyCommandService'); $command->run($input, $ouput); 

En mi entorno (Symony 2.1) tuve que hacer algunas modificaciones a la solución @Reuven para que funcione. Aquí están:

Definición del servicio: sin cambios.

En el controlador:

 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); } 

Aquí hay una alternativa que le permite ejecutar comandos como cadenas de la misma manera que lo haría en la consola (no hay necesidad de definir servicios con este).

Puede consultar el controlador de este paquete para ver cómo se hace con todos los detalles. Aquí voy a resumir que omite ciertos detalles (como el manejo del entorno, por lo que aquí todos los comandos se ejecutarán en el mismo entorno en que se invocan).

Si solo desea ejecutar comandos desde el navegador, puede usar ese paquete tal como está, pero si desea ejecutar comandos desde un controlador arbitrario, aquí está cómo hacerlo:

En su controlador defina una función como esta:

 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; } 

Entonces puedes invocarlo desde una acción como esta:

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

Además, debe definir una clase para que actúe como búfer de salida, ya que no existe ninguno proporcionado por el marco:

 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; } } 

lo mismo que @malloc pero

 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); } 

Simplemente puede crear una instancia de su comando y ejecutarlo:

 /** * @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(); } 

Si tiene que pasar argumentos (y / u opciones), entonces en v2.0.12 (y puede ser cierto para versiones posteriores), necesita especificar InputDefinition primero antes de instanciar un objeto de entrada.

 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(); 

Como nota al margen, si está utilizando si está usando getContainer () en su comando, entonces la siguiente función puede ser útil para su comando.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(); } 

Puede usar este paquete para ejecutar comandos Symfony2 desde el controlador (solicitud HTTP) y pasar opciones / parámetros en la URL.

https://github.com/mrafalko/CommandRunnerBundle

Si ejecuta un comando que necesita la opción env como assetic:dump

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

Tienes que crear una Symfony\Component\Console\Application y establecer la definición de esa manera:

 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); 

No puede establecer la opción env en el comando porque no está en su definición.