1
0
mirror of synced 2024-12-05 03:06:05 +03:00

[2.0] Major refactorings to CLI. New documentation applied. Missing validation and tests

This commit is contained in:
guilhermeblanco 2009-11-17 01:29:20 +00:00
parent ea4f5c172a
commit 67665aa574
20 changed files with 1031 additions and 239 deletions

View File

@ -40,6 +40,12 @@ The new behavior is as if the option were set to FALSE all the time, basically d
# Upgrade from 2.0-ALPHA3 to 2.0-ALPHA4
-
## CLI Controller changes
CLI main object changed its name and namespace. Renamed from Doctrine\ORM\Tools\Cli to Doctrine\ORM\Tools\Cli\CliController.
Doctrine\ORM\Tools\Cli\CliController methods addTasks and addTask are now fluent.
## CLI Tasks documentation
Tasks have implemented a new way to build documentation. Although it is still possible to define the help manually by extending the basicHelp and extendedHelp, they are now optional.
With new required method AbstractTask::buildDocumentation, its implementation defines the TaskDocumentation instance (accessible through AbstractTask::getDocumentation()), basicHelp and extendedHelp are now not necessary to be implemented.

View File

@ -0,0 +1,99 @@
<?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;
/**
* CLI Option 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 Option
{
/** @var string Option name */
private $_name;
/** @var string Option default value */
/** @var string Option description */
private $description;
/**
* Constructs a CLI Option
*
* @param string Option name
* @param integer Option type
* @param string Option description
*/
public function __construct($name, $defaultValue, $description)
{
$this->_name = $name;
$this->_defaultValue = $defaultValue;
$this->_description = $description;
}
/**
* Retrieves the CLI Option name
*
* @return string Option name
*/
public function getName()
{
return $this->_name;
}
/**
* Retrieves the CLI Option default value
*
* @return string|null Option default value
*/
public function getDefaultValue()
{
return $this->_defaultValue;
}
/**
* Retrieves the CLI Option description
*
* @return string Option description
*/
public function getDescription()
{
return $this->_description;
}
/**
* Converts the Option instance into a string representation
*
* @return string CLI Option representation in string
*/
public function __toString()
{
return '--' . $this->_name
. (( ! is_null($this->_defaultValue)) ? '=' . $this->_defaultValue : '');
}
}

View File

@ -0,0 +1,482 @@
<?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;
}
}

View File

@ -19,9 +19,9 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools\Cli\Printers;
namespace Doctrine\Common\Cli\Printers;
use Doctrine\ORM\Tools\Cli\Style;
use Doctrine\Common\Cli\Style;
/**
* CLI Output Printer.
@ -140,16 +140,28 @@ abstract class AbstractPrinter
{
$this->_maxColumnSize = $maxColumnSize;
}
/**
* Writes to the output stream.
*
* @param string $message Message to be outputted
*/
public function output($message)
{
fwrite($this->_stream, $message);
return $this;
}
/**
* Writes to the output stream, formatting it by applying the defined style.
* Formats message applying the defined style and writes to the output stream.
*
* @param string $message Message to be outputted
* @param mixed $style Optional style to be applied in message
*/
public function write($message, $style = 'NONE')
{
fwrite($this->_stream, $this->format($message, $style));
$this->output($this->format($message, $style));
return $this;
}

View File

@ -19,9 +19,9 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools\Cli\Printers;
namespace Doctrine\Common\Cli\Printers;
use Doctrine\ORM\Tools\Cli\Style;
use Doctrine\Common\Cli\Style;
/**
* CLI Output Printer for ANSI Color terminal
@ -57,11 +57,12 @@ class AnsiColorPrinter extends AbstractPrinter
/**
* @inheritdoc
*/
public function format($message, $style)
public function format($message, $style = 'NONE')
{
if ( ! $this->_supportsColor()) {
return $message;
}
$style = $this->getStyle($style);
$str = $this->_getForegroundString($style->getForeground())
. $this->_getBackgroundString($style->getBackground())

View File

@ -19,9 +19,9 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools\Cli\Printers;
namespace Doctrine\Common\Cli\Printers;
use Doctrine\ORM\Tools\Cli\Style;
use Doctrine\Common\Cli\Style;
/**
* CLI Output Printer for Normal terminal

View File

@ -19,7 +19,7 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools\Cli;
namespace Doctrine\Common\Cli;
/**
* CLI Output Style

View File

@ -0,0 +1,168 @@
<?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,
Doctrine\Common\Cli\OptionGroup,
Doctrine\Common\Cli\Option;
/**
* CLI Task documentation
*
* @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 TaskDocumentation
{
/** @var AbstractPrinter CLI Printer */
private $_printer;
/** @var string CLI Task name */
private $_name;
/** @var string CLI Task description */
private $_description;
/** @var array CLI Task Option Group */
private $_optionGroup;
/**
* Constructs a new CLI Task Documentation
*
* @param AbstractPrinter CLI Printer
*/
public function __construct(AbstractPrinter $printer)
{
$this->_printer = $printer;
$this->_optionGroup = new OptionGroup(OptionGroup::CARDINALITY_M_N);
}
/**
* Defines the CLI Task name
*
* @param string Task name
* @return TaskDocumentation This object instance
*/
public function setName($name)
{
$this->_name = $name;
return $this;
}
/**
* Retrieves the CLI Task name
*
* @return string Task name
*/
public function getName()
{
return $this->_name;
}
/**
* Defines the CLI Task description
*
* @param string Task description
* @return TaskDocumentation This object instance
*/
public function setDescription($description)
{
$this->_description = $description;
return $this;
}
/**
* Retrieves the CLI Task description
*
* @var string Task description
*/
public function getDescription()
{
return $this->_description;
}
/**
* Retrieves the CLI Task Option Group
*
* @return OptionGroup CLI Task Option Group
*/
public function getOptionGroup()
{
return $this->_optionGroup;
}
/**
* Includes a new CLI Option Group to the CLI Task documentation
*
* @param OptionGroup CLI Option Group
* @return TaskDocumentation This object instance
*/
public function addOption($option)
{
if ($option instanceof OptionGroup) {
$this->_optionGroup->addOption($option);
}
return $this;
}
/**
* Retrieves the synopsis of associated CLI Task
*
* @return string CLI Task synopsis
*/
public function getSynopsis()
{
return $this->_printer->format($this->_name, 'KEYWORD') . ' '
. trim($this->_optionGroup->formatPlain($this->_printer));
}
/**
* Retrieve the complete documentation of associated CLI Task
*
* @return string CLI Task complete documentation
*/
public function getCompleteDocumentation()
{
$printer = $this->_printer;
return $printer->format('Task: ')
. $printer->format($this->_name, 'KEYWORD')
. $printer->format(PHP_EOL)
. $printer->format('Synopsis: ')
. $this->getSynopsis()
. $printer->format(PHP_EOL)
. $printer->format('Description: ')
. $printer->format($this->_description)
. $printer->format(PHP_EOL)
. $printer->format('Options: ')
. $printer->format(PHP_EOL)
. $this->_optionGroup->formatWithDescription($printer);
}
}

View File

@ -19,20 +19,20 @@
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools;
namespace Doctrine\ORM\Tools\Cli;
use Doctrine\Common\Util\Inflector,
Doctrine\ORM\Tools\Cli\Printers\AbstractPrinter,
Doctrine\ORM\Tools\Cli\Tasks\AbstractTask,
Doctrine\ORM\Tools\Cli\Printers\AnsiColorPrinter;
Doctrine\Common\Cli\Printers\AbstractPrinter,
Doctrine\Common\Cli\Printers\AnsiColorPrinter,
Doctrine\ORM\Tools\Cli\Tasks\AbstractTask;
/**
* Generic CLI Runner of Tasks
* Generic CLI Controller of Tasks execution
*
* To include a new Task support, create a task:
*
* [php]
* class MyProject\Tools\Cli\Tasks\MyTask extends Doctrine\ORM\Tools\Cli\AbstractTask
* class MyProject\Tools\Cli\Tasks\MyTask extends Doctrine\ORM\Tools\Cli\Tasks\AbstractTask
* {
* public function run();
* public function basicHelp();
@ -43,7 +43,7 @@ use Doctrine\Common\Util\Inflector,
* And then, include the support to it in your command-line script:
*
* [php]
* $cli = new Doctrine\ORM\Tools\Cli();
* $cli = new Doctrine\ORM\Tools\Cli\CliController();
* $cli->addTask('myTask', 'MyProject\Tools\Cli\Tasks\MyTask');
*
* To execute, just type any classify-able name:
@ -58,7 +58,7 @@ use Doctrine\Common\Util\Inflector,
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class Cli
class CliController
{
/**
* @var AbstractPrinter CLI Printer instance
@ -107,12 +107,15 @@ class Cli
* ));
*
* @param array $tasks CLI Tasks to be included
* @return CliController This object instance
*/
public function addTasks($tasks)
{
foreach ($tasks as $name => $class) {
$this->addTask($name, $class);
}
return $this;
}
/**
@ -124,6 +127,7 @@ class Cli
*
* @param string $name CLI Task name
* @param string $class CLI Task class (FQCN - Fully Qualified Class Name)
* @return CliController This object instance
*/
public function addTask($name, $class)
{
@ -132,6 +136,8 @@ class Cli
$name = $this->_processTaskName($name);
$this->_tasks[$name] = $class;
return $this;
}
/**
@ -170,10 +176,9 @@ class Cli
$em = $this->_initializeEntityManager($processedArgs, $taskArguments);
// Instantiate and execute the task
$task = new $this->_tasks[$taskName]();
$task = new $this->_tasks[$taskName]($this->_printer);
$task->setAvailableTasks($this->_tasks);
$task->setEntityManager($em);
$task->setPrinter($this->_printer);
$task->setArguments($taskArguments);
if (

View File

@ -21,7 +21,10 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\Cli\Printers\AbstractPrinter;
use Doctrine\Common\Cli\Printers\AbstractPrinter,
Doctrine\Common\Cli\TaskDocumentation,
Doctrine\Common\Cli\OptionGroup,
Doctrine\Common\Cli\Option;
/**
* Base class for CLI Tasks.
@ -50,6 +53,11 @@ abstract class AbstractTask
*/
protected $_printer;
/**
* @var TaskDocumentation CLI Task Documentation
*/
protected $_documentation;
/**
* @var array CLI argument options
*/
@ -66,13 +74,24 @@ abstract class AbstractTask
protected $_em;
/**
* Defines a CLI Output Printer
* Constructor of CLI Task
*
* @param AbstractPrinter CLI Output Printer
*/
public function setPrinter(AbstractPrinter $printer)
public function __construct(AbstractPrinter $printer)
{
$this->_printer = $printer;
$this->_documentation = new TaskDocumentation($printer);
// Include configuration option
$configGroup = new OptionGroup(OptionGroup::CARDINALITY_0_1);
$configGroup->addOption(
new Option('config', '<FILE_PATH>', 'Configuration file for EntityManager.')
);
$this->_documentation->addOption($configGroup);
// Complete the CLI Task Documentation creation
$this->buildDocumentation();
}
/**
@ -145,6 +164,16 @@ abstract class AbstractTask
return $this->_em;
}
/**
* Retrieves the CLI Task Documentation
*
* @return TaskDocumentation
*/
public function getDocumentation()
{
return $this->_documentation;
}
/**
* Expose to CLI Output Printer the extended help of the given task.
* This means it should detail all parameters, options and the meaning
@ -155,7 +184,10 @@ abstract class AbstractTask
* ./doctrine task --help
*
*/
abstract public function extendedHelp();
public function extendedHelp()
{
$this->_printer->output($this->_documentation->getCompleteDocumentation());
}
/**
* Expose to CLI Output Printer the basic help of the given task.
@ -173,7 +205,14 @@ abstract class AbstractTask
* ./doctrine --help
*
*/
abstract public function basicHelp();
public function basicHelp()
{
$this->_printer
->output($this->_documentation->getSynopsis())
->output(PHP_EOL)
->output(' ' . $this->_documentation->getDescription())
->output(PHP_EOL . PHP_EOL);
}
/**
* Assures the given arguments matches with required/optional ones.
@ -190,4 +229,9 @@ abstract class AbstractTask
* what is supposed to do.
*/
abstract public function run();
/**
* Generate the CLI Task Documentation
*/
abstract public function buildDocumentation();
}

View File

@ -21,7 +21,11 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\Common\Cache\AbstractDriver;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Util\Debug,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup,
Doctrine\Common\Cache\AbstractDriver;
/**
* CLI Task to clear the cache of the various cache drivers
@ -36,45 +40,32 @@ use Doctrine\Common\Cache\AbstractDriver;
*/
class ClearCacheTask extends AbstractTask
{
public function basicHelp()
/**
* @inheritdoc
*/
public function buildDocumentation()
{
$this->_writeSynopsis($this->getPrinter());
}
public function extendedHelp()
{
$printer = $this->getPrinter();
$printer->write('Task: ')->writeln('clear-cache', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$printer->writeln('Description: Clear cache from configured query, result and metadata drivers.')
->writeln('Options:')
->write('--query', 'OPT_ARG')
->writeln("\t\t\tClear the query cache.")
->write('--result', 'OPT_ARG')
->writeln("\t\tClear the result cache.")
->write('--metadata', 'OPT_ARG')
->writeln("\t\tClear the metadata cache.")
->write('--id=<ID>', 'REQ_ARG')
->writeln("\t\tThe id of the cache entry to delete (accepts * wildcards).")
->write('--regex=<REGEX>', 'REQ_ARG')
->writeln("\t\tDelete cache entries that match the given regular expression.")
->write('--prefix=<PREFIX>', 'REQ_ARG')
->writeln("\tDelete cache entries that have the given prefix.")
->write('--suffix=<SUFFIX>', 'REQ_ARG')
->writeln("\tDelete cache entries that have the given suffix.");
}
private function _writeSynopsis($printer)
{
$printer->write('clear-cache', 'KEYWORD')
->write(' (--query | --result | --metadata)', 'OPT_ARG')
->write(' [--id=<ID>]', 'REQ_ARG')
->write(' [--regex=<REGEX>]', 'REQ_ARG')
->write(' [--prefix=<PREFIX>]', 'REQ_ARG')
->writeln(' [--suffix=<SUFFIX>]', 'REQ_ARG');
$cacheOptions = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option('query', null, 'Clear the query cache.'),
new Option('metadata', null, 'Clear the metadata cache.'),
new OptionGroup(OptionGroup::CARDINALITY_M_N, array(
new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option('result', null, 'Clear the result cache.')
)),
new OptionGroup(OptionGroup::CARDINALITY_0_N, array(
new Option('id', '<ID>', 'The id of the cache entry to delete (accepts * wildcards).'),
new Option('regex', '<REGEX>', 'Delete cache entries that match the given regular expression.'),
new Option('prefix', '<PREFIX>', 'Delete cache entries that have the given prefix.'),
new Option('suffic', '<SUFFIX>', 'Delete cache entries that have the given suffix.')
))
))
));
$doc = $this->getDocumentation();
$doc->setName('clear-cache')
->setDescription('Clear cache from configured query, result and metadata drivers.')
->getOptionGroup()
->addOption($cacheOptions);
}
public function validate()
@ -90,7 +81,11 @@ class ClearCacheTask extends AbstractTask
|| isset($args['prefix'])
|| isset($args['suffix']))) {
$printer->writeln('When clearing the query or metadata cache do not specify any --id, --regex, --prefix or --suffix.', 'ERROR');
$printer->writeln(
'When clearing the query or metadata cache do not ' .
'specify any --id, --regex, --prefix or --suffix.',
'ERROR'
);
return false;
}
@ -112,6 +107,7 @@ class ClearCacheTask extends AbstractTask
$suffix = isset($args['suffix']) ? $args['suffix'] : null;
$all = false;
if ( ! $query && ! $result && ! $metadata) {
$all = true;
}
@ -206,6 +202,7 @@ class ClearCacheTask extends AbstractTask
} else {
$printer->writeln('No ' . $type . ' cache entries found', 'ERROR');
}
$printer->writeln("");
$printer->write(PHP_EOL);
}
}

View File

@ -21,8 +21,10 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\ORM\Tools\Export\ClassMetadataExporter,
Doctrine\Common\DoctrineException;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup,
Doctrine\ORM\Tools\Export\ClassMetadataExporter;
if ( ! class_exists('sfYaml', false)) {
require_once __DIR__ . '/../../../../../vendor/sfYaml/sfYaml.class.php';
@ -47,44 +49,24 @@ class ConvertMappingTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$printer = $this->getPrinter();
$convertOptions = new OptionGroup(OptionGroup::CARDINALITY_N_N, array(
new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option('from', '<SOURCE>', 'The path to the mapping information to convert from (yml, xml, php, annotation).'),
new Option('from-database', null, 'Use this option if you wish to reverse engineer your database to a set of Doctrine mapping files.')
)),
new Option('to', '<TYPE>', 'The format to convert to (yml, xml, php, annotation).'),
new Option('dest', '<PATH>', 'The path to write the converted mapping information.')
));
$doc = $this->getDocumentation();
$doc->setName('convert-mapping')
->setDescription('Convert mapping information between supported formats.')
->getOptionGroup()
->addOption($convertOptions);
}
$printer->write('Task: ')->writeln('convert-mapping', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$printer->writeln('Description: Convert mapping information between supported formats.')
->writeln('Options:')
->write('--from=<SOURCE>', 'REQ_ARG')
->writeln("\tThe path to the mapping information to convert from (yml, xml, php, annotation).")
->write('--from-database', 'REQ_ARG')
->writeln("\tUse this option if you wish to reverse engineer your database to a set of Doctrine mapping files.")
->write('--to=<TYPE>', 'REQ_ARG')
->writeln("\tThe format to convert to (yml, xml, php, annotation).")
->write(PHP_EOL)
->write('--dest=<PATH>', 'REQ_ARG')
->writeln("\tThe path to write the converted mapping information.");
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
private function _writeSynopsis($printer)
{
$printer->write('convert-mapping', 'KEYWORD')
->write(' --from=<SOURCE>', 'REQ_ARG')
->write(' --to=<TYPE>', 'REQ_ARG')
->write(' --dest=<PATH>', 'REQ_ARG')
->writeln(' --from-database', 'OPT_ARG');
}
/**
* @inheritdoc
*/

View File

@ -36,27 +36,19 @@ use Doctrine\Common\Cache\AbstractDriver;
*/
class EnsureProductionSettingsTask extends AbstractTask
{
public function basicHelp()
/**
* @inheritdoc
*/
public function buildDocumentation()
{
$this->_writeSynopsis($this->getPrinter());
}
public function extendedHelp()
{
$printer = $this->getPrinter();
$printer->write('Task: ')->writeln('ensure-production-settings', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$printer->writeln('Description: Verify that Doctrine is properly configured for a production environment.');
}
private function _writeSynopsis($printer)
{
$printer->writeln('ensure-production-settings', 'KEYWORD');
$doc = $this->getDocumentation();
$doc->setName('ensure-production-settings')
->setDescription('Verify that Doctrine is properly configured for a production environment.');
}
/**
* @inheritdoc
*/
public function validate()
{
return true;
@ -65,6 +57,7 @@ class EnsureProductionSettingsTask extends AbstractTask
public function run()
{
$printer = $this->getPrinter();
try {
$this->getEntityManager()->getConfiguration()->ensureProductionSettings();
} catch (\Doctrine\Common\DoctrineException $e) {

View File

@ -2,6 +2,10 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup;
/**
* Task to (re)generate the proxy classes used by doctrine.
*
@ -18,33 +22,17 @@ class GenerateProxiesTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$printer = $this->getPrinter();
$toDir = new OptionGroup(OptionGroup::CARDINALITY_0_1, array(
new Option('to-dir', '<PATH>', 'Generates the classes in the specified directory.')
));
$printer->write('Task: ')->writeln('generate-proxies', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$printer->writeln('Description: Generates proxy classes for entity classes.')
->writeln('Options:')
->write('--to-dir', 'OPT_ARG')
->writeln("\t\tGenerates the classes in the specified directory.")
->write(PHP_EOL);
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
private function _writeSynopsis($printer)
{
$printer->write('generate-proxies', 'KEYWORD')
->writeln(' [--to-dir=<PATH>]', 'OPT_ARG');
$doc = $this->getDocumentation();
$doc->setName('generate-proxies')
->setDescription('Generates proxy classes for entity classes.')
->getOptionGroup()
->addOption($toDir);
}
/**

View File

@ -36,6 +36,14 @@ use Doctrine\Common\Util\Inflector;
*/
class HelpTask extends AbstractTask
{
/**
* @inheritdoc
*/
public function buildDocumentation()
{
// Does nothing
}
/**
* @inheritdoc
*/
@ -77,11 +85,10 @@ class HelpTask extends AbstractTask
ksort($availableTasks);
foreach ($availableTasks as $taskName => $taskClass) {
$task = new $taskClass();
$task = new $taskClass($this->getPrinter());
$task->setAvailableTasks($availableTasks);
$task->setEntityManager($this->getEntityManager());
$task->setPrinter($this->getPrinter());
$task->setArguments($this->getArguments());
$task->basicHelp();

View File

@ -22,7 +22,9 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Util\Debug;
Doctrine\Common\Util\Debug,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup;
/**
* Task for executing DQL in passed EntityManager.
@ -40,36 +42,22 @@ class RunDqlTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$printer = $this->getPrinter();
$dql = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option('dql', '<DQL>', 'The DQL to execute.')
));
$printer->write('Task: ')->writeln('run-dql', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$depth = new OptionGroup(OptionGroup::CARDINALITY_0_1, array(
new Option('depth', '<DEPTH>', 'Dumping depth of Entities graph.')
));
$printer->writeln('Description: Executes DQL in requested EntityManager.')
->writeln('Options:')
->write('--dql=<DQL>', 'REQ_ARG')
->writeln("\tThe DQL to execute.")
->write(PHP_EOL)
->write('--depth=<DEPTH>', 'OPT_ARG')
->writeln("\tDumping depth of Entities graph.");
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
private function _writeSynopsis($printer)
{
$printer->write('run-dql', 'KEYWORD')
->write(' --dql=<DQL>', 'REQ_ARG')
->writeln(' --depth=<DEPTH>', 'OPT_ARG');
$doc = $this->getDocumentation();
$doc->setName('run-dql')
->setDescription('Executes arbitrary DQL directly from the command line.')
->getOptionGroup()
->addOption($dql)
->addOption($depth);
}
/**

View File

@ -22,7 +22,9 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Util\Debug;
Doctrine\Common\Util\Debug,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup;
/**
* Task for executing arbitrary SQL that can come from a file or directly from
@ -41,41 +43,31 @@ class RunSqlTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$printer = $this->getPrinter();
$dqlAndFile = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option(
'sql', '<DQL>',
'The SQL to execute.' . PHP_EOL .
'If defined, --file can not be requested on same task.'
),
new Option(
'file', '<FILE_PATH>',
'The path to the file with the SQL to execute.' . PHP_EOL .
'If defined, --sql can not be requested on same task.'
)
));
$printer->write('Task: ')->writeln('run-sql', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$depth = new OptionGroup(OptionGroup::CARDINALITY_0_1, array(
new Option('depth', '<DEPTH>', 'Dumping depth of Entities graph.')
));
$printer->writeln('Description: Executes arbitrary SQL from a file or directly from the command line.')
->writeln('Options:')
->write('--sql=<SQL>', 'REQ_ARG')
->writeln("\tThe SQL to execute.")
->writeln("\t\tIf defined, --file can not be requested on same task")
->write(PHP_EOL)
->write('--file=<path>', 'REQ_ARG')
->writeln("\tThe path to the file with the SQL to execute.")
->writeln("\t\tIf defined, --sql can not be requested on same task")
->write(PHP_EOL)
->write('--depth=<DEPTH>', 'OPT_ARG')
->writeln("\tDumping depth of ResultSet graph.");
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
private function _writeSynopsis($printer)
{
$printer->write('run-sql', 'KEYWORD')
->write(' (--file=<path> | --sql=<SQL>)', 'REQ_ARG')
->writeln(' --depth=<DEPTH>', 'OPT_ARG');
$doc = $this->getDocumentation();
$doc->setName('run-sql')
->setDescription('Executes arbitrary SQL from a file or directly from the command line.')
->getOptionGroup()
->addOption($dqlAndFile)
->addOption($depth);
}
/**

View File

@ -3,6 +3,8 @@
namespace Doctrine\ORM\Tools\Cli\Tasks;
use Doctrine\Common\DoctrineException,
Doctrine\Common\Cli\Option,
Doctrine\Common\Cli\OptionGroup,
Doctrine\ORM\Tools\SchemaTool,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
@ -46,7 +48,49 @@ class SchemaToolTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$schemaOption = new OptionGroup(OptionGroup::CARDINALITY_1_1, array(
new Option(
'create', null,
'Creates the schema in EntityManager (create tables on Database).' . PHP_EOL .
'If defined, --drop, --update and --re-create can not be requested on same task.'
),
new Option(
'drop', '<metadata|database>',
'Drops the schema of EntityManager (drop tables on Database).' . PHP_EOL .
'Defaults to "metadata" if only --drop is specified.' . PHP_EOL .
'If defined, --create, --update and --re-create can not be requested on same task.'
),
new Option(
'update', null,
'Updates the schema in EntityManager (update tables on Database).' . PHP_EOL .
'If defined, --create, --drop and --re-create can not be requested on same task.'
),
new Option(
're-create', null,
'Runs --drop then --create to re-create the database.' . PHP_EOL .
'If defined, --create, --update and --drop can not be requested on same task.'
)
));
$optionalOptions = new OptionGroup(OptionGroup::CARDINALITY_0_N, array(
new Option('dump-sql', null, 'Instead of try to apply generated SQLs into EntityManager, output them.'),
new Option('class-dir', '<PATH>', 'Optional class directory to fetch for Entities.')
));
$doc = $this->getDocumentation();
$doc->setName('schema-tool')
->setDescription('Processes the schema and either apply it directly on EntityManager or generate the SQL output.')
->getOptionGroup()
->addOption($schemaOption)
->addOption($optionalOptions);
}
/**
* @inheritdoc
*/
/*public function extendedHelp()
{
$printer = $this->getPrinter();
@ -78,12 +122,12 @@ class SchemaToolTask extends AbstractTask
->write('--class-dir=<path>', 'OPT_ARG')
->writeln("\tOptional class directory to fetch for Entities.")
->write(PHP_EOL);
}
}*/
/**
* @inheritdoc
*/
public function basicHelp()
/*public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
@ -93,7 +137,7 @@ class SchemaToolTask extends AbstractTask
$printer->write('schema-tool', 'KEYWORD')
->write(' (--create | --drop=<metadata|database> | --update | --re-create)', 'REQ_ARG')
->writeln(' [--dump-sql] [--class-dir=<path>]', 'OPT_ARG');
}
}*/
/**
* @inheritdoc

View File

@ -37,30 +37,14 @@ class VersionTask extends AbstractTask
/**
* @inheritdoc
*/
public function extendedHelp()
public function buildDocumentation()
{
$printer = $this->getPrinter();
$printer->write('Task: ')->writeln('version', 'KEYWORD')
->write('Synopsis: ');
$this->_writeSynopsis($printer);
$printer->writeln('Description: Displays the current installed Doctrine version.')
->writeln('Options:')
->writeln('No available options', 'INFO');
}
/**
* @inheritdoc
*/
public function basicHelp()
{
$this->_writeSynopsis($this->getPrinter());
}
// There're no options on this task
$this->getDocumentation()->getOptionGroup()->clear();
private function _writeSynopsis($printer)
{
$printer->writeln('version', 'KEYWORD');
$doc = $this->getDocumentation();
$doc->setName('version')
->setDescription('Displays the current installed Doctrine version.');
}
/**
@ -77,6 +61,6 @@ class VersionTask extends AbstractTask
*/
public function run()
{
$this->getPrinter()->writeln('You are currently running Doctrine 2.0.0 Alpha 3', 'INFO');
$this->getPrinter()->writeln('You are currently running Doctrine 2.0.0 Alpha 4', 'INFO');
}
}

View File

@ -6,5 +6,5 @@ $classLoader = new \Doctrine\Common\IsolatedClassLoader('Doctrine');
$classLoader->setBasePath(__DIR__ . '/../../lib');
$classLoader->register();
$cli = new \Doctrine\ORM\Tools\Cli();
$cli = new \Doctrine\ORM\Tools\Cli\CliController();
$cli->run($_SERVER['argv']);