web-dev-qa-db-fra.com

Comment lancer la commande symfony 2 run depuis le contrôleur

Je me demande comment puis-je exécuter Symfony 2 command à partir d'une requête du navigateur ou d'un contrôleur.

C'est parce que je n'ai aucune possibilité sur l'hébergement de l'exécuter et que toutes les tâches cron sont configurées par l'administrateur.

Je n'ai même pas activé la fonction exec(). Par conséquent, lorsque je souhaite la tester, je dois copier tout le contenu de la commande sur un contrôleur de test, ce qui n'est pas la meilleure solution. 

41
PayteR

Voir documentation officielle sur ce numéro pour les versions les plus récentes de Symfony 


Vous n'avez pas besoin de services d'exécution de commande à partir du contrôleur et, je pense, il est préférable d'appeler commande via la méthode run et non via la chaîne d'entrée de la console, cependant documentation officielle vous suggère d'appeler la commande via son alias. Voir aussi cette réponse . Testé sur Symfony 2.1-2.6.

Votre classe de commande doit être étendue 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);
    }
}

Dans la plupart des cas, vous n'avez pas besoin de BufferedOutput (de la réponse de Jbm) et il suffit de vérifier que $resultCode is 0, sinon une erreur s'est produite.

63
Dmitriy

Enregistrez votre commande en tant que service et n'oubliez pas d'appeler setContainer

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

Dans votre contrôleur, vous devrez simplement obtenir ce service et appeler la méthode execute avec les arguments de droits.

Définissez l'entrée avec la méthode setArgument:

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

Appelez la méthode run de la commande:

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

Dans mon environnement (Symony 2.1), je devais apporter quelques modifications à la solution @Reuven pour que cela fonctionne. Les voici:

Définition du service - pas de changement.

Dans le contrôleur:

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

Vous pouvez simplement créer une instance de votre commande et l'exécuter:

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

Voici une alternative qui vous permet d’exécuter des commandes sous forme de chaînes de la même façon que sur la console (il n’est pas nécessaire de définir des services avec celle-ci).

Vous pouvez vérifier le contrôleur de cet ensemble pour voir comment cela fonctionne avec tous les détails. Je vais résumer ici certains détails (comme la gestion de l'environnement, de sorte que toutes les commandes s'exécutent dans le même environnement où elles sont appelées).

Si vous voulez seulement exécuter des commandes à partir du navigateur, vous pouvez utiliser cet ensemble tel quel, mais si vous voulez exécuter des commandes à partir d'un contrôleur arbitraire, voici comment procéder:

Dans votre contrôleur, définissez une fonction comme celle-ci:

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

Ensuite, vous pouvez l'invoquer à partir d'une action comme celle-ci:

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

    return new Response($output);
}

En outre, vous devez définir une classe agissant en tant que tampon de sortie, car aucune structure n'est fournie par la structure:

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

identique à @malloc mais

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

Si vous devez passer des arguments (et/ou des options), vous devez d'abord spécifier InputDefinition avant d'instancier un objet d'entrée.

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



En guise de remarque, si vous utilisez si vous utilisez getContainer () dans votre commande, la fonction suivante peut être pratique pour votre commande.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();
}
1
aTTozk

Vous pouvez utiliser cet ensemble pour exécuter des commandes Symfony2 à partir du contrôleur (requête http) et transmettre des options/paramètres dans une URL.

https://github.com/mrafalko/CommandRunnerBundle

0
borN_free

Si vous exécutez une commande nécessitant l'option env telle que assetic:dump

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

Vous devez créer un Symfony\Component\Console\Application et définir la définition comme suit:

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

Vous ne pouvez pas définir l'option env à la commande car elle ne figure pas dans sa définition.

0
Kevin Robatel