. */ namespace Doctrine\Common\Cli; use Doctrine\Common\Cli\Printers\AbstractPrinter; /** * CLI Option Group definition * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel */ class OptionGroup { /* CLI Option Group CARDINALITY */ /** * Defines the cardinality 0..N to CLI Option Group. * This means options in this group are optional and you can * define more than one CLI Option on a single command. */ const CARDINALITY_0_N = 0; // [...] [...] [...] /** * Defines the cardinality 0..1 to CLI Option Group. * This means all options in this group are optional and you can * define only one CLI Option on a single command. */ const CARDINALITY_0_1 = 1; // [...|...|...] /** * Defines the cardinality 1..1 to CLI Option Group. * This means all options in this group are required and you must * define only one CLI Option on a single command. */ const CARDINALITY_1_1 = 2; // (...|...|...) /** * Defines the cardinality 1..N to CLI Option Group. * This means all options in this group are required and you must * define at least one CLI Option on a single command. */ const CARDINALITY_1_N = 3; // (... ... ...) /** * Defines the cardinality N..N to CLI Option Group. * This means all options in this group are required and you must * define all CLI Options on a single command. */ const CARDINALITY_N_N = 4; // ... ... ... /** * Defines the cardinality M..N to CLI Option Group. * This means all options in this group are either required or * optional and you can CLI Options on a single command. * This is the option to skip CLI Option validation. */ const CARDINALITY_M_N = 5; // ... ... ... /** @var integer Option Group cardinality */ private $_cadinality; /** @var array Option Group list of CLI Options */ private $_options; /** * Constructs a new CLI Option Group * * @param integer Option Group cardinality * @param array CLI Option Group options */ public function __construct($cardinality, $options = array()) { $this->_cardinality = $cardinality; $this->_options = $options; } /** * Retrieves the CLI Option Group cardinality * * @return integer Option Group cardinality */ public function getCardinality() { return $this->_cardinality; } /** * Retrieves the CLI Option Group options * * @return array Option Group options */ public function getOptions() { return $this->_options; } /** * Cleans the CLI Options inside this CLI Option Group * */ public function clear() { $this->_options = array(); } /** * Includes a new CLI Option to the Option Group * * @param Option|OptionGroup CLI Option or CLI Option Group * @return OptionGroup This object instance */ public function addOption($option) { if ($option instanceof Option || $option instanceof OptionGroup) { $this->_options[] = $option; } return $this; } /** * Formats the CLI Option Group into a single line representation * * @param AbstractPrinter CLI Printer * @return string Single line string representation of CLI Option Group */ public function formatPlain(AbstractPrinter $printer) { $numOptions = count($this->_options); if ($numOptions == 0) { return ''; } $style = $this->_getGroupOptionStyle(); $shouldDisplayExtras = ( $numOptions > 1 || $this->_cardinality == self::CARDINALITY_0_1 || $this->_cardinality == self::CARDINALITY_0_N ); $str = ($shouldDisplayExtras) ? $printer->format($this->_startGroupDeclaration(), $style) : ''; // Loop through all CLI Options defined in OptionGroup for ($i = 0; $i < $numOptions; $i++) { $option = $this->_options[$i]; // Check for possible recursive OptionGroup if ($option instanceof OptionGroup) { // Simple increase nesting level by calling format recursively $str .= $option->formatPlain($printer); } else { // Expose the option formatted $str .= $printer->format((string) $option, $style); } // Possibly append content if needed if ($i < $numOptions - 1) { $str .= $printer->format($this->_separatorGroupDeclaration(), $style); } } $str .= ($shouldDisplayExtras) ? $printer->format($this->_endGroupDeclaration(), $style) : ''; return $str; } /** * INTERNAL: * Defines the start Option Group declaration string * * @return string Start Option Group declaration string */ private function _startGroupDeclaration() { $str = ''; // Inspect cardinality of OptionGroup switch ($this->_cardinality) { case self::CARDINALITY_0_1: case self::CARDINALITY_0_N: $str .= '['; break; case self::CARDINALITY_1_1: case self::CARDINALITY_1_N: $str .= '('; break; case self::CARDINALITY_N_N: case self::CARDINALITY_M_N: default: // Does nothing break; } return $str; } /** * INTERNAL: * Defines the separator Option Group declaration string * * @return string Separator Option Group declaration string */ private function _separatorGroupDeclaration() { $str = ''; // Inspect cardinality of OptionGroup switch ($this->_cardinality) { case self::CARDINALITY_0_1: case self::CARDINALITY_1_1: $str .= ' | '; break; case self::CARDINALITY_1_N: case self::CARDINALITY_N_N: case self::CARDINALITY_M_N: $str .= ' '; break; case self::CARDINALITY_0_N: $str .= '] ['; break; default: // Does nothing break; } return $str; } /** * INTERNAL: * Defines the end Option Group declaration string * * @return string End Option Group declaration string */ private function _endGroupDeclaration() { $str = ''; // Inspect cardinality of OptionGroup switch ($this->_cardinality) { case self::CARDINALITY_0_1: case self::CARDINALITY_0_N: $str .= ']'; break; case self::CARDINALITY_1_1: case self::CARDINALITY_1_N: $str .= ')'; break; case self::CARDINALITY_N_N: case self::CARDINALITY_M_N: default: // Does nothing break; } return $str; } /** * INTERNAL: * Retrieve the Option Group style based on defined cardinality * * @return string CLI Style string representation */ private function _getGroupOptionStyle() { $style = 'NONE'; // Inspect cardinality of OptionGroup switch ($this->_cardinality) { case self::CARDINALITY_0_1: case self::CARDINALITY_0_N: $style = 'OPT_ARG'; break; case self::CARDINALITY_1_1: case self::CARDINALITY_1_N: case self::CARDINALITY_N_N: case self::CARDINALITY_M_N: $style = 'REQ_ARG'; break; default: // Does nothing break; } return $style; } /** * Formats the CLI Option Group into a multi-line list with respective description * * @param AbstractPrinter CLI Printer * @return string Multi-line string representation of CLI Option Group */ public function formatWithDescription(AbstractPrinter $printer) { $numOptions = count($this->_options); if ($numOptions == 0) { return 'No available options' . PHP_EOL . PHP_EOL; } $str = ''; // Get list of required and optional and max length options list( $requiredOptions, $optionalOptions, $maxOptionLength ) = $this->_getOrganizedOptions( $this->_options, $this->_cardinality, 0 ); // Array-unique options $requiredOptions = array_unique($requiredOptions); $optionalOptions = array_unique($optionalOptions); // TODO Sort options alphabetically // Displaying required options for ($i = 0, $l = count($requiredOptions); $i < $l; $i++) { $str .= $this->_displayOptionWithDescription( $printer, $requiredOptions[$i], 'REQ_ARG', $maxOptionLength ); // Include extra line breaks between options $str .= PHP_EOL . PHP_EOL; } // Displaying optional options for ($i = 0, $l = count($optionalOptions); $i < $l; $i++) { $str .= $this->_displayOptionWithDescription( $printer, $optionalOptions[$i], 'OPT_ARG', $maxOptionLength ); // Include extra line breaks between options $str .= PHP_EOL . PHP_EOL; } return $str; } /** * Organize the Options into arrays of required and optional options. * Also define the maximum length of CLI Options. * * @param array Array of CLI Option or CLI Option Group * @param integer Current CLI OptionGroup cardinality * @param integer Maximum length of CLI Options * @return array Array containing 3 indexes: required options, optional * options and maximum length of CLI Options */ private function _getOrganizedOptions($options, $cardinality, $maxColumn) { // Calculate maximum length and also organize the // options into required and optional ones $numOptions = count($options); $requiredOptions = array(); $optionalOptions = array(); for ($i = 0; $i < $numOptions; $i++) { $option = $options[$i]; // Check for possible recursive OptionGroup if ($option instanceof OptionGroup) { // Initialize OptionGroup options $groupRequiredOptions = array(); $groupOptionalOptions = array(); // Get nested information list( $groupRequiredOptions, $groupOptionalOptions, $maxGroupColumn ) = $this->_getOrganizedOptions( $option->getOptions(), $option->getCardinality(), $maxColumn ); // Merge nested required and optional options $requiredOptions = array_merge($requiredOptions, $groupRequiredOptions); $optionalOptions = array_merge($optionalOptions, $groupOptionalOptions); // If OptionGroup length is bigger than the current maximum, update if ($maxColumn < $maxGroupColumn) { $maxColumn = $maxGroupColumn; } } else { // Cardinality defines between optional or required options switch ($cardinality) { case self::CARDINALITY_0_1: case self::CARDINALITY_0_N: $optionalOptions[] = $option; break; case self::CARDINALITY_1_1: case self::CARDINALITY_1_N: case self::CARDINALITY_N_N: case self::CARDINALITY_M_N: $requiredOptions[] = $option; break; default: // Does nothing break; } // Build Option string $optionStr = (string) $option; // + 2 = aditional spaces after option $length = strlen($optionStr) + 2; if ($maxColumn < $length) { $maxColumn = $length; } } } return array($requiredOptions, $optionalOptions, $maxColumn); } /** * INTERNAL: * Formats the CLI Option and also include the description * * @param AbstractPrinter CLI Printer * @param Option CLI Option to be formatted * @param string CLI Style string representation * @param integer Maximum CLI Option length * @return string Formats the current CLI Option line(s) */ private function _displayOptionWithDescription($printer, $option, $style, $maxOptionLength) { // Expose the option formatted $optionStr = (string) $option; // Format Option string $str .= $printer->format($optionStr, $style); // Include missing spaces $str .= str_repeat(' ', $maxOptionLength - strlen($optionStr)); // Calculate and display description $str .= str_replace( PHP_EOL, PHP_EOL . str_repeat(' ', $maxOptionLength), $option->getDescription() ); return $str; } }