web-dev-qa-db-ja.com

コントローラーからsymfony 2 runコマンドを実行するにはどうすればよいですか

ブラウザクエリまたはコントローラからSymfony 2コマンドを実行するにはどうすればよいのでしょうか。

その理由は、ホスティングで実行する可能性がなく、すべてのcronジョブが管理者によって設定されるためです。

exec()関数を有効にしていないため、テストする場合は、コマンドからすべてのコンテンツをテストコントローラーにコピーする必要がありますが、これは最適なソリューションではありません。

44
PayteR

Symfonyの新しいバージョンについては、この問題に関する 公式ドキュメント を参照してください


コントローラからコマンドを実行するためのサービスは必要ありません。コンソール文字列入力ではなく、runメソッドを介してコマンドを呼び出すことをお勧めしますが、 official docs を推奨しますエイリアス経由でコマンドを呼び出します。また、 この回答 を参照してください。 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(fromJbm'sanswer)は不要で、$resultCode is 0、それ以外の場合はエラーが発生しました。

65
Dmitriy

コマンドをサービスとして登録し、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, $output);
56
Reuven

私の環境(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);
}
10
malloc4k

コマンドのインスタンスを作成して実行するだけです:

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

コンソールで行うのと同じ方法でコマンドを文字列として実行できる代替手段を次に示します(これでサービスを定義する必要はありません)。

このバンドルのコントローラー をチェックして、すべての詳細がどのように行われているかを確認できます。ここでは、特定の詳細(環境の処理など)を省略して要約します。したがって、ここではすべてのコマンドは、呼び出された同じ環境で実行されます。

ブラウザからコマンドを実行したいだけなら、そのバンドルをそのまま使用できますが、任意のコントローラーからコマンドを実行したい場合は、次のようにします。

コントローラーで、次のような関数を定義します。

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

次に、次のようなアクションから呼び出すことができます。

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

    return new Response($output);
}

また、フレームワークによって提供されるものがないため、出力バッファーとして機能するクラスを定義する必要があります。

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

@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

引数(および/またはオプション)を渡す必要がある場合、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();
}
1
aTTozk

このバンドルを使用して、Symfony2コマンドをコントローラー(httpリクエスト)から実行し、URLでオプション/パラメーターを渡すことができます。

https://github.com/mrafalko/CommandRunnerBundle

0
borN_free

assetic:dumpのようなenvオプションを必要とするコマンドを実行する場合

$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を設定することはできません。これはコマンドの定義にないためです。

0
Kevin Robatel