2012-05-08 13 views
37

से symfony 2 रन कमांड कैसे चला सकता हूं, मैं सोच रहा हूं कि मैं Symfony 2 ब्राउज़र क्वेरी या नियंत्रक से कमांड कैसे चला सकता हूं।मैं नियंत्रक

ऐसा इसलिए है क्योंकि मुझे इसे चलाने के लिए होस्टिंग पर कोई संभावना नहीं है और प्रत्येक क्रॉन नौकरियां व्यवस्थापक द्वारा निर्धारित की जाती हैं।

मैंने exec() फ़ंक्शन को भी सक्षम नहीं किया है, इसलिए जब मैं इसका परीक्षण करना चाहता हूं, तो मुझे कमांड से सभी सामग्री को कुछ परीक्षण नियंत्रक में कॉपी करना होगा और यह सबसे अच्छा समाधान नहीं है।

उत्तर

54

Symfony के नए संस्करण के लिए इस मुद्दे पर official documentation देखें


आप नियंत्रक से आदेश के निष्पादन के लिए सेवाओं की जरूरत नहीं है और मुझे लगता है कि यह run विधि के माध्यम से कमांड कॉल करने के लिए बेहतर है और कंसोल स्ट्रिंग इनपुट के माध्यम से नहीं, हालांकि official docs आपको इसके उपनाम के माध्यम से कमांड कॉल करने का सुझाव देता है।इसके अलावा, this answer देखें। सिम्फनी 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, अन्यथा कोई त्रुटि हुई थी कि जाँच करने के लिए पर्याप्त है।

+3

'--some-option' उदाहरण के लिए +1 – gondo

+0

मुझे 2.4 – RedactedProfile

+0

@DJDarkViper में' setContainer' विधि नहीं मिलती है अद्यतन उत्तर देखें। – Dmitriy

55

एक सेवा के रूप में अपने आदेश रजिस्टर और भूल नहीं है setContainer

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

अपने नियंत्रक में कॉल करने के लिए, तो आप सिर्फ इस सेवा प्राप्त करने के लिए होगा, और अधिकार तर्क के साथ विधि पर अमल फोन

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

कॉल आदेश की run विधि:

setArgument विधि के साथ इनपुट सेट

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

हाँ, यह बहुत बेहतर है, thx! – PayteR

+0

$ आउटपुट var कंसोल उत्तर कैप्चर करने के लिए है? धन्यवाद –

+0

हां, कंसोल – Reuven

10

मेरे पर्यावरण में (सिमनी 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); 
} 
3

यहाँ एक विकल्प के आप आदेश पर अमल के रूप में एक ही तरह से आप कंसोल पर होगा तार देता है कि है (इस एक के साथ सेवाओं को परिभाषित करने के लिए कोई जरूरत नहीं है)।

आप सभी विवरणों के साथ यह देखने के लिए this bundle's controller देख सकते हैं। यहां मैं कुछ विवरणों को उजागर करने के लिए संक्षेप में जा रहा हूं (जैसे पर्यावरण को संभालना, इसलिए यहां सभी आदेश उसी वातावरण में चलेंगे जो उन्हें बुलाया जाता है)।

तुम सिर्फ ब्राउज़र से आदेश चलाना चाहते हैं, तो आप उस बंडल के रूप में यह है उपयोग कर सकते हैं, लेकिन अगर आप एक मनमाना नियंत्रक से आदेश चलाना चाहते हैं यहाँ इसे कैसे करना है:

अपने नियंत्रक में परिभाषित इस तरह एक समारोह:

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

    return new Response($output); 
} 

इसके अलावा, आप उत्पादन बफर के रूप में कार्य करने के लिए एक वर्ग को परिभाषित करने की जरूरत है, ख:

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

तो फिर तुम इसे इस तरह एक कार्रवाई से आह्वान कर सकते हैं ecause कोई भी रूपरेखा के द्वारा प्रदान की जाती है:

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

वहाँ भी php का उपयोग करता है LiipFunctionalTestBundle में एक काफी अच्छा कार्यान्वयन है: // StreamOutput में बनाया के साथ अस्थायी धारा आउटपुट को कैप्चर करने के लिए कक्षा ताकि आपको दूसरी आउटपुट बफर क्लास बनाने की आवश्यकता न हो। https://github.com/liip/LiipFunctionalTestBundle/blob/master/Test/WebTestCase.php#L102 – Cvuorinen

+2

बस यह कहना एक नोट है कि 'BufferedOutput' अब सिम्फनी 2.4 के बाद उपलब्ध है। – noisebleed

1

यदि आपको तर्क (और/या विकल्प) पास करना है, तो v2.0.12 (और बाद के संस्करणों के लिए सच हो सकता है) में, आपको इनपुट ऑब्जेक्ट को तुरंत चालू करने से पहले इनपुट डिफिनेशन निर्दिष्ट करना होगा।

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

ही @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

तुम बस केवल एक instanc बना सकते हैं अपने आदेश की ई और इसे चलाने:

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

आप नियंत्रक (http अनुरोध) से Symfony2 आदेश चलाने के लिए और URL में विकल्प/पैरामीटर पास करने के बंडल का उपयोग कर सकते हैं।

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

आप कर सकते हैं:

https://github.com/mrafalko/CommandRunnerBundle

0

आप एक कमांड env विकल्प की तरह assetic:dump

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

जरूरत है कि चलाते हैं आप एक Symfony\Component\Console\Application बना सकते हैं और इस तरह परिभाषा सेट करने के लिए विकल्प को env विकल्प पर सेट नहीं करें क्योंकि यह इसकी परिभाषा में नहीं है ।

+0

सिलेक्स एप्लिकेशन पिंपल कंटेनर बढ़ाता है और HttpKernelInterface, TerminableInterface लागू करता है, और इसमें 'setDefinition' विधि नहीं है। – Trix

संबंधित मुद्दे