controller - كيف يمكنني تشغيل الأمر symfony 2 من وحدة تحكم




command (9)

أنا أتساءل كيف يمكنني تشغيل الأمر Symfony 2 من استعلام المتصفح أو من وحدة التحكم.

لأنه ليس لدي أي إمكانية لاستضافة لتشغيله ويتم تسوية كل وظائف كرون من قبل المشرف.

لا أستطيع حتى تمكين وظيفة exec() حتى عندما أريد اختبارها ، يجب أن أنسخ كل المحتوى من الأمر إلى بعض وحدات التحكم في الاختبار ، وهذا ليس أفضل حل.


Answers

إذا قمت بتشغيل الأمر الذي يحتاج إلى خيار env مثل assetic:dump

$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 للأمر لأنه ليس في تعريفه.



يمكنك ببساطة إنشاء مثيل لأمرك وتشغيله:

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

انظر الوثائق الرسمية حول هذه المسألة للحصول على إصدارات أحدث من Symfony

لا تحتاج إلى خدمات لتنفيذ الأوامر من وحدة التحكم ، وأعتقد أنه من الأفضل استدعاء الأمر عبر طريقة run وليس من خلال إدخال سلسلة وحدة التحكم ، ومع ذلك توحي لك المستندات الرسمية باستدعاء الأمر عبر اسمها المستعار. أيضا ، انظر هذا الجواب . اختبارها على 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 (من إجابة Jbm ) ويكفي التحقق من أن $resultCode is 0 ، وإلا كان هناك خطأ.


في بيئتي (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);
}

سجل الأمر كخدمة ولا تنس أن تستدعي setContainer

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

في وحدة التحكم الخاصة بك ، سيكون عليك فقط الحصول على هذه الخدمة ، واستدعاء طريقة التنفيذ مع وسيطات الحقوق

قم بتعيين الإدخال باستخدام طريقة 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, $ouput);

إليك بديلاً يتيح لك تنفيذ الأوامر كسلاسل بنفس الطريقة التي تستخدمها في وحدة التحكم (لا توجد حاجة إلى تعريف الخدمات بهذه الخدمة).

يمكنك التحقق من وحدة تحكم هذه الحزمة لمعرفة كيف يتم ذلك مع كل التفاصيل. سأقوم هنا بتلخيص ذلك بتفاصيل معينة (مثل التعامل مع البيئة ، لذا سيتم تشغيل جميع الأوامر في نفس البيئة التي يتم استدعاؤها).

إذا كنت تريد فقط تشغيل الأوامر من المستعرض ، فيمكنك استخدام هذه الحزمة كما هي ، ولكن إذا كنت ترغب في تشغيل الأوامر من وحدة تحكم عشوائية ، فإليك كيفية القيام بذلك:

في وحدة التحكم الخاصة بك تحديد وظيفة مثل هذا:

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

إذا كان لديك لتمرير الوسائط (و / أو خيارات) ، ثم في v2.0.12 (وربما يكون صحيحا للإصدارات الأحدث) ، تحتاج إلى تحديد InputDefinition الأول قبل instantiating كائن إدخال.

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

فقط للإشارة إلى أن هذا يتم إضافته الآن في Symfony v2.2 - http://symfony.com/doc/master/components/routing/hostname_pattern.html .

mobile_homepage:
    path:     /
    host:     m.{domain}
    defaults: { _controller: AcmeDemoBundle:Main:mobileHomepage }
    requirements:
        domain: %domain%

homepage:
    path:  /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }




symfony controller command