2016-05-31 26 views
1

假設我有一個命令,做了簡單的人:如何共享沒有繼承的命令配置?

class PlainTextHelloWorldCommand extends Command 
{ 
    protected function configure() 
    { 
     $this 
      ->setName('text:hello') 
      ->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?'); 
    } 


    /** 
    * @param InputInterface $input 
    * @param OutputInterface $output 
    * @return int|null|void 
    */ 
    protected function execute(InputInterface $input, OutputInterface $output) 
    { 
     $receiver = $input->getArgument('receiver'); 
     $output->writeln("Hello {$receiver}!"); 
    } 
} 

另一個命令現在也需要receiver說法:

class HtmlHelloCommand extends Command 
{ 
    /** 
    * 
    * @throws InvalidArgumentException 
    */ 
    protected function configure() 
    { 
     $this 
      ->setName('html:hello') 
      ->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?'); 
    } 


    /** 
    * @param InputInterface $input 
    * @param OutputInterface $output 
    * @return int|null|void 
    */ 
    protected function execute(InputInterface $input, OutputInterface $output) 
    { 
     $receiver = $input->getArgument('receiver'); 
     $output->writeln("<html><h1>Hello {$receiver}!</h1></html>"); 
    } 
} 

現在我在想如何不重複自己。

我想共享邏輯來添加參數和解析輸入,以便它在一個地方。

我知道我可以創建一個「ReceiverAwareCommand」,但如果我獲得更多參數會發生什麼?

我不想讓SendEmailCommand擴展MessageAwareGreeterCommand擴展receiverAwareCommand ...`。這條路似乎導致了地獄,因此我喜歡避免繼承。

此外,我的示例被簡化,只要兩個示例命令基本相同。事實並非如此。此外,我有大約10個參數,而每個命令最多可能需要4個參數。

我只想在沒有我自己的情況下設置這些參數。

我正在考慮裝飾模式的方向,但我有點困惑如何設置它們在這種情況下,所以它感覺錯誤。

因此,我想知道:這是如何實現的?

+0

你試圖調用*父::配置(); *添加新的論據之前用'$ this-> setName('html:hello')...'給子類?它應該將參數添加到父類參數中。 –

+0

@ A.L重點是避免繼承。是的,那麼我需要做'parent :: configure()'和'parent :: execute()'。這只是我不想要的路線,因爲一個命令需要不同形式的多個參數。 – k0pernikus

+0

您是否嘗試過僅使用一個帶有多個可選參數的命令?您將能夠在html或文本輸入等之間切換。 –

回答

0

(我知道你不想繼承,但我不能找到一個更好的主意)


可以定義BaseCommand,您通過添加方法add…Argument定義所有的參數:

class BaseCommand extends Command 
{ 
    static $format = '%s'; 

    protected function configure() 
    { 
     parent::configure(); 

     // Define a fake command (IIRC Symfony throws an error without this). 
     $this 
      ->setName('command:base') 
      ->setDescription('Base command') 
     ; 
    } 

    protected function execute(InputInterface $input, OutputInterface $output) 
    { 
     parent::initialize($input, $output); //initialize parent class method 

     $receiver = $input->getArgument('receiver'); 
     $output->writeln(sprintf($this::$format, $receiver)); 
    } 

    /***** Define arguments *****/ 
    protected function addReceiverArgument() 
    { 
     $this 
      ->addArgument('receiver', InputArgument::REQUIRED, 'Who do you want to greet?') 
     ; 

     return $this; 
    } 

    protected function addOtherArgument() 
    { 
     $this 
      ->addArgument('other', InputArgument::REQUIRED, 'Other argument') 
     ; 

     return $this; 
    } 
} 

然後你可以在子類中重新使用這些方法:

class PlainTextHelloWorldCommand extends BaseCommand 
{ 
    protected function configure() 
    { 
     parent::configure(); 

     $this 
      ->setName('text:hello'); 

     $this 
      ->addReceiverArgument() 
     ; 
    } 
} 

如果另一個命令需要2個參數,很容易:

class HtmlHelloCommand extends BaseCommand 
{ 
    // Change the output formatting. 
    static $format = '<html><h1>Hello %s!</h1></html>'; 

    protected function configure() 
    { 
     parent::configure(); 

     $this 
      ->setName('html:hello') 
     ; 

     $this 
      ->addReceiverArgument() 
      ->addOtherArgument() 
     ; 
    } 
} 

然後就可以調用的命令:

$ php app/console text:hello aaa 
Hello aaa! 
$ php app/console html:hello aaa 


    [Symfony\Component\Console\Exception\RuntimeException] 
    Not enough arguments (missing: "other").     

$ php app/console html:hello aaa bbb 
<html><h1>Hello aaa!</h1></html>