it-swarm.com.de

Wie kann ich den Symfony 2-Run-Befehl vom Controller aus ausführen

Ich frage mich, wie ich den Befehl Symfony 2 von einer Browserabfrage oder vom Controller aus ausführen kann.

Ich habe keine Möglichkeit, das Hosting durchzuführen, und alle Cron-Jobs werden vom Administrator erledigt.

Ich habe noch nicht einmal die Funktion exec() aktiviert. Wenn ich sie testen möchte, muss ich den gesamten Inhalt vom Befehl auf einen Testcontroller kopieren. Dies ist keine optimale Lösung. 

41
PayteR

offizielle Dokumentation zu diesem Problem für neuere Versionen von Symfony 


Sie benötigen keine Dienste für die Befehlsausführung vom Controller, und ich denke, es ist besser, den Befehl über die run-Methode und nicht über die Konsolenstring-Eingabe aufzurufen. offizielle Dokumente schlagen jedoch vor, den Befehl über den Aliasnamen aufzurufen. Siehe auch diese Antwort . Getestet auf Symfony 2.1-2.6.

Ihre Befehlsklasse muss ContainerAwareCommand erweitern.

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

In den meisten Fällen benötigen Sie keine BufferedOutput (aus der Antwort von Jbm), und es reicht aus, den $resultCode is 0 zu überprüfen, andernfalls ist ein Fehler aufgetreten.

63
Dmitriy

Registrieren Sie Ihren Befehl als Dienst und vergessen Sie nicht, setContainer aufzurufen.

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

In Ihrem Controller müssen Sie nur diesen Dienst anfordern und die Ausführungsmethode mit den Berechtigungsargumenten aufrufen

Setzen Sie die Eingabe mit der setArgument-Methode:

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

Rufen Sie die run-Methode des Befehls auf:

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

In meiner Umgebung (Symony 2.1) musste ich einige Änderungen an der @Reuven-Lösung vornehmen, damit sie funktioniert. Hier sind sie:

Servicedefinition - keine Änderungen.

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

Sie können einfach eine Instanz Ihres Befehls erstellen und ausführen:

/**
 * @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

Hier ist eine Alternative, mit der Sie Befehle als Zeichenfolgen wie auf der Konsole ausführen können (es ist nicht erforderlich, Dienste mit dieser zu definieren).

Sie können den Controller dieses Bundles überprüfen, um zu sehen, wie es mit allen Details gemacht wird. Ich werde es hier zusammenfassen, indem ich bestimmte Details auslasse (z. B. den Umgang mit der Umgebung, daher werden alle Befehle in derselben Umgebung ausgeführt, in der sie aufgerufen werden).

Wenn Sie nur Befehle vom Browser aus ausführen möchten, können Sie dieses Bundle so verwenden, wie es ist. Wenn Sie jedoch Befehle von einem beliebigen Controller ausführen möchten, gehen Sie wie folgt vor:

Definieren Sie in Ihrem Controller eine Funktion wie folgt:

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

Dann können Sie es von einer Aktion wie der folgenden aufrufen:

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

    return new Response($output);
}

Außerdem müssen Sie eine Klasse definieren, die als Ausgabepuffer fungiert, da vom Framework keine bereitgestellt wird:

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

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

Wenn Sie Argumente (und/oder Optionen) übergeben müssen, müssen Sie in v2.0.12 (und für spätere Versionen möglicherweise "true") zuerst InputDefinition angeben, bevor Sie ein Eingabeobjekt .... instanziieren.

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



. Als Nebenbemerkung, wenn Sie verwenden, wenn Sie in Ihrem Befehl getContainer () verwenden, kann die folgende Funktion für Ihre command.php nützlich sein:

/**
 * 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

Sie können dieses Bundle verwenden, um Symfony2-Befehle vom Controller (http-Anforderung) auszuführen und Optionen/Parameter als URL zu übergeben.

https://github.com/mrafalko/CommandRunnerBundle

0
borN_free

Wenn Sie einen Befehl ausführen, der die Option env benötigt, wie assetic:dump

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

Sie müssen einen Symfony\Component\Console\Application erstellen und die Definition so setzen:

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

Sie können die Option env nicht auf den Befehl setzen, da sie nicht in der Definition enthalten ist.

0
Kevin Robatel