Come posso eseguire il comando di esecuzione di symfony 2 dal controller

Mi chiedo come posso eseguire il comando Symfony 2 dalla query del browser o dal controller.

È perché non ho alcuna possibilità di hosting per eseguirlo e ogni lavoro cron è impostato da admin.

Non ho nemmeno abilitato la funzione exec() , quindi quando voglio testarlo, devo copiare tutto il contenuto dal comando a qualche controller di test e questa non è la soluzione migliore.

Vedi la documentazione ufficiale su questo problema per le versioni più recenti di Symfony


Non sono necessari servizi per l’esecuzione del comando dal controller e, penso, è meglio chiamare il comando tramite il metodo run e non tramite l’input della stringa della console, tuttavia i documenti ufficiali suggeriscono di chiamare il comando tramite il suo alias. Inoltre, vedere questa risposta . Testato su Symfony 2.1-2.6.

La class del comando deve estendere 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); } } 

Nella maggior parte dei casi non è necessario BufferedOutput (dalla risposta di Jbm ) ed è sufficiente controllare che $resultCode is 0 , altrimenti si è verificato un errore.

Registra il tuo comando come un servizio e non dimenticare di chiamare setContainer

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

Nel tuo controller, devi solo ottenere questo servizio e chiamare il metodo execute con gli argomenti dei diritti

Imposta l’input con il metodo setArgument :

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

Chiama il metodo di run del comando:

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

Nel mio ambiente (Symony 2.1) ho dovuto apportare alcune modifiche alla soluzione di @Reuven per farlo funzionare. Eccoli:

Definizione del servizio – nessuna modifica.

Nel controller:

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

Ecco un’alternativa che ti permette di eseguire comandi come stringhe nello stesso modo in cui faresti sulla console (non c’è bisogno di definire i servizi con questa console).

Puoi controllare il controller di questo bundle per vedere come è fatto con tutti i dettagli. Qui ho intenzione di riassumere l’omissione di alcuni dettagli (come la gestione dell’ambiente, quindi qui tutti i comandi verranno eseguiti nello stesso ambiente in cui sono richiamati).

Se vuoi solo eseguire comandi dal browser, puoi usare quel bundle così com’è, ma se vuoi eseguire comandi da un controller arbitrario ecco come farlo:

Nel tuo controller definisci una funzione come questa:

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

Quindi puoi invocarlo da un’azione come questa:

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

Inoltre, è necessario definire una class che funga da buffer di output, poiché non esiste nessuno fornito dal framework:

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

come @malloc ma

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

Puoi semplicemente creare un’istanza del tuo comando ed eseguirla:

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

Se devi passare argomenti (e / o opzioni), quindi in v2.0.12 (e potrebbe essere vero per le versioni successive), devi prima specificare InputDefinition prima di istanziare un object di input.

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

Come nota a margine, se stai usando se usi getContainer () nel tuo comando, allora la seguente funzione potrebbe essere utile per il tuo 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(); } 

È ansible utilizzare questo pacchetto per eseguire i comandi Symfony2 dal controller (richiesta http) e passare opzioni / parametri nell’URL.

https://github.com/mrafalko/CommandRunnerBundle

Se si esegue un comando che richiede l’opzione env come assetic:dump

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

Devi creare un’applicazione Symfony\Component\Console\Application e impostare la definizione in questo modo:

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

Non è ansible impostare l’opzione env sul comando perché non è nella sua definizione.