1
0
mirror of synced 2024-12-15 23:56:02 +03:00
doctrine2/lib/Doctrine/Common/Cli/OptionGroup.php
2010-01-09 21:25:51 +00:00

482 lines
15 KiB
PHP

<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
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 <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
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;
}
}