[+FEATURE] Backport CommandController Implementation
authorMichael Klapper <development@morphodo.com>
Tue, 3 May 2011 11:09:21 +0000 (13:09 +0200)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Tue, 11 Oct 2011 09:31:01 +0000 (11:31 +0200)
Backports the FLOW3 CLI functionality to Extbase
Registers the Extbase bootstrap at the v4 cli_dispatch.phpsh

Use it from commandline like this:
cli_dispatch.phpsh extbase <command identifier> --argumentName=value

for example:
cli_dispatch.phpsh extbase help

NOTE: Unlike in FLOW3 Commands have to be registered explictly
in ext_localconf.php in order to be callable via CLI.

Resolves: #27186

Change-Id: Ia47f1d90558fbdb058767f3aa2c3e23f086a3255

32 files changed:
typo3/sysext/extbase/Classes/Command/HelpCommandController.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/Configuration/AbstractConfigurationManager.php
typo3/sysext/extbase/Classes/Core/Bootstrap.php
typo3/sysext/extbase/Classes/MVC/CLI/Command.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/CommandArgumentDefinition.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/CommandManager.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/Request.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/RequestBuilder.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/RequestHandler.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/CLI/Response.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Controller/CommandController.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Controller/CommandControllerInterface.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/AmbiguousCommandIdentifier.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/Command.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/InvalidArgumentMixing.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/InvalidCommandIdentifier.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/NoSuchCommand.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/Exception/RequiredArgumentMissing.php [new file with mode: 0644]
typo3/sysext/extbase/Classes/MVC/RequestInterface.php
typo3/sysext/extbase/Classes/MVC/Web/Routing/UriBuilder.php
typo3/sysext/extbase/Classes/Reflection/MethodReflection.php
typo3/sysext/extbase/Scripts/CommandLineLauncher.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandManagerTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestBuilderTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/Controller/ActionControllerTest.php
typo3/sysext/extbase/Tests/Unit/MVC/Controller/CommandControllerTest.php [new file with mode: 0644]
typo3/sysext/extbase/Tests/Unit/MVC/Fixture/CLI/Command/MockCommandController.php [new file with mode: 0644]
typo3/sysext/extbase/ext_localconf.php
typo3/sysext/extbase/ext_tables.php
typo3/sysext/extbase/ext_typoscript_setup.txt

diff --git a/typo3/sysext/extbase/Classes/Command/HelpCommandController.php b/typo3/sysext/extbase/Classes/Command/HelpCommandController.php
new file mode 100644 (file)
index 0000000..6981c20
--- /dev/null
@@ -0,0 +1,244 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * A Command Controller which provides help for available commands
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_Command_HelpCommandController extends Tx_Extbase_MVC_Controller_CommandController {
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_CommandManager
+        */
+       protected $commandManager;
+
+       /**
+        * @var array
+        */
+       protected $commandsByExtensionsAndControllers = array();
+
+       /**
+        * @param Tx_Extbase_MVC_CLI_CommandManager $commandManager
+        * @return void
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function injectCommandManager(Tx_Extbase_MVC_CLI_CommandManager $commandManager) {
+               $this->commandManager = $commandManager;
+       }
+
+       /**
+        * Displays a short, general help message
+        *
+        * This only outputs the Extbase version number, context and some hint about how to
+        * get more help about commands.
+        *
+        * @return void
+        * @internal
+        */
+       public function helpStubCommand() {
+               $this->outputLine('Extbase %s', array(t3lib_extMgm::getExtensionVersion('extbase')));
+               $this->outputLine('usage: ./cli_dispatch.phpsh extbase <command identifier>');
+               $this->outputLine();
+               $this->outputLine('See \'./cli_dispatch.phpsh extbase help\' for a list of all available commands.');
+               $this->outputLine();
+       }
+
+       /**
+        * Display help for a command
+        *
+        * The help command displays help for a given command:
+        * ./cli_dispatch.phpsh extbase help <command identifier>
+        *
+        * @param string $commandIdentifier Identifier of a command for more details
+        * @return void
+        */
+       public function helpCommand($commandIdentifier = NULL) {
+               if ($commandIdentifier === NULL) {
+                       $this->displayHelpIndex();
+               } else {
+                       try {
+                               $command = $this->commandManager->getCommandByIdentifier($commandIdentifier);
+                       } catch (Tx_Extbase_MVC_Exception_Command $exception) {
+                               $this->outputLine($exception->getMessage());
+                               return;
+                       }
+                       $this->displayHelpForCommand($command);
+               }
+       }
+
+       /**
+        * @return void
+        */
+       protected function displayHelpIndex() {
+               $this->buildCommandsIndex();
+
+               $this->outputLine('Extbase %s', array(t3lib_extMgm::getExtensionVersion('extbase')));
+               $this->outputLine('usage: ./cli_dispatch.phpsh extbase <command identifier>');
+               $this->outputLine();
+               $this->outputLine('The following commands are currently available:');
+
+               foreach ($this->commandsByExtensionsAndControllers as $extensionKey => $commandControllers) {
+                       $this->outputLine('');
+                       $this->outputLine('EXTENSION "%s":', array(strtoupper($extensionKey)));
+                       $this->outputLine(str_repeat('-', self::MAXIMUM_LINE_LENGTH));
+                       foreach ($commandControllers as $commands) {
+                               foreach ($commands as $command) {
+                                       $description = wordwrap($command->getShortDescription(), self::MAXIMUM_LINE_LENGTH - 43, PHP_EOL . str_repeat(' ', 43), TRUE);
+                                       $shortCommandIdentifier = $this->commandManager->getShortestIdentifierForCommand($command);
+                                       $this->outputLine('%-2s%-40s %s', array(' ', $shortCommandIdentifier , $description));
+                               }
+                               $this->outputLine();
+                       }
+               }
+               $this->outputLine('See \'./cli_dispatch.phpsh extbase help <command identifier>\' for more information about a specific command.');
+               $this->outputLine();
+       }
+
+       /**
+        * Render help text for a single command
+        *
+        * @param Tx_Extbase_MVC_CLI_Command $command
+        * @return void
+        */
+       protected function displayHelpForCommand(Tx_Extbase_MVC_CLI_Command $command) {
+               $this->outputLine();
+               $this->outputLine($command->getShortDescription());
+               $this->outputLine();
+
+               $this->outputLine('COMMAND:');
+               $this->outputLine('%-2s%s', array(' ', $command->getCommandIdentifier()));
+
+               $commandArgumentDefinitions = $command->getArgumentDefinitions();
+               $usage = '';
+               $hasOptions = FALSE;
+               foreach ($commandArgumentDefinitions as $commandArgumentDefinition) {
+                       if (!$commandArgumentDefinition->isRequired()) {
+                               $hasOptions = TRUE;
+                       } else {
+                               $usage .= sprintf(' <%s>', strtolower(preg_replace('/([A-Z])/', ' $1', $commandArgumentDefinition->getName())));
+                       }
+               }
+
+               $usage = './cli_dispatch.phpsh extbase ' . $this->commandManager->getShortestIdentifierForCommand($command) . ($hasOptions ? ' [<options>]' : '') . $usage;
+
+               $this->outputLine();
+               $this->outputLine('USAGE:');
+               $this->outputLine('  ' . $usage);
+
+               $argumentDescriptions = array();
+               $optionDescriptions = array();
+
+               if ($command->hasArguments()) {
+                       foreach ($commandArgumentDefinitions as $commandArgumentDefinition) {
+                               $argumentDescription = $commandArgumentDefinition->getDescription();
+                               $argumentDescription = wordwrap($argumentDescription, self::MAXIMUM_LINE_LENGTH - 23, PHP_EOL . str_repeat(' ', 23), TRUE);
+                               if ($commandArgumentDefinition->isRequired()) {
+                                       $argumentDescriptions[] = vsprintf('  %-20s %s', array($commandArgumentDefinition->getDashedName(), $argumentDescription));
+                               } else {
+                                       $optionDescriptions[] = vsprintf('  %-20s %s', array($commandArgumentDefinition->getDashedName(), $argumentDescription));
+                               }
+                       }
+               }
+
+               if (count($argumentDescriptions) > 0) {
+                       $this->outputLine();
+                       $this->outputLine('ARGUMENTS:');
+                       foreach ($argumentDescriptions as $argumentDescription) {
+                               $this->outputLine($argumentDescription);
+                       }
+               }
+
+               if (count($optionDescriptions) > 0) {
+                       $this->outputLine();
+                       $this->outputLine('OPTIONS:');
+                       foreach ($optionDescriptions as $optionDescription) {
+                               $this->outputLine($optionDescription);
+                       }
+               }
+
+               if ($command->getDescription() !== '') {
+                       $this->outputLine();
+                       $this->outputLine('DESCRIPTION:');
+                       $descriptionLines = explode(chr(10), $command->getDescription());
+                       foreach ($descriptionLines as $descriptionLine) {
+                               $this->outputLine('%-2s%s', array(' ', $descriptionLine));
+                       }
+               }
+
+               $relatedCommandIdentifiers = $command->getRelatedCommandIdentifiers();
+               if ($relatedCommandIdentifiers !== array()) {
+                       $this->outputLine();
+                       $this->outputLine('SEE ALSO:');
+                       foreach ($relatedCommandIdentifiers as $commandIdentifier) {
+                               $command = $this->commandManager->getCommandByIdentifier($commandIdentifier);
+                               $this->outputLine('%-2s%s (%s)', array(' ', $commandIdentifier, $command->getShortDescription()));
+                       }
+               }
+
+               $this->outputLine();
+       }
+
+       /**
+        * Displays an error message
+        *
+        * @internal
+        * @param Tx_Extbase_MVC_Exception_Command $exception
+        * @return void
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function errorCommand(Tx_Extbase_MVC_Exception_Command $exception) {
+               $this->outputLine($exception->getMessage());
+               if ($exception instanceof Tx_Extbase_MVC_Exception_AmbiguousCommandIdentifier) {
+                       $this->outputLine('Please specify the complete command identifier. Matched commands:');
+                       foreach ($exception->getMatchingCommands() as $matchingCommand) {
+                               $this->outputLine('    %s', array($matchingCommand->getCommandIdentifier()));
+                       }
+               }
+               $this->outputLine('');
+               $this->outputLine('Enter "./cli_dispatch.phpsh extbase help" for an overview of all available commands');
+               $this->outputLine('or "./cli_dispatch.phpsh extbase help <command identifier>" for a detailed description of the corresponding command.');
+       }
+
+       /**
+        * Builds an index of available commands. For each of them a Command object is
+        * added to the commands array of this class.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       protected function buildCommandsIndex() {
+               $availableCommands = $this->commandManager->getAvailableCommands();
+               foreach ($availableCommands as $command) {
+                       if ($command->isInternal()) {
+                               continue;
+                       }
+                       $commandIdentifier = $command->getCommandIdentifier();
+                       $extensionKey = strstr($commandIdentifier, ':', TRUE);
+                       $commandControllerClassName = $command->getControllerClassName();
+                       $commandName = $command->getControllerCommandName();
+                       $this->commandsByExtensionsAndControllers[$extensionKey][$commandControllerClassName][$commandName] = $command;
+               }
+       }
+}
+?>
index 8a94bfa..5c80024 100755 (executable)
@@ -120,8 +120,8 @@ abstract class Tx_Extbase_Configuration_AbstractConfigurationManager implements
                // reset 1st level cache
                $this->configurationCache = array();
 
-               $this->extensionName = $configuration['extensionName'];
-               $this->pluginName = $configuration['pluginName'];
+               $this->extensionName = isset($configuration['extensionName']) ? $configuration['extensionName'] : NULL;
+               $this->pluginName = isset($configuration['pluginName']) ? $configuration['pluginName'] : NULL;
                $this->configuration = $this->typoScriptService->convertTypoScriptArrayToPlainArray($configuration);
        }
 
index 4672458..6049a88 100644 (file)
@@ -73,11 +73,6 @@ class Tx_Extbase_Core_Bootstrap {
        protected $persistenceManager;
 
        /**
-        * @var boolean
-        */
-       protected $isInitialized = FALSE;
-
-       /**
         * Explicitly initializes all necessary Extbase objects by invoking the various initialize* methods.
         *
         * Usually this method is only called from unit tests or other applications which need a more fine grained control over
@@ -89,11 +84,13 @@ class Tx_Extbase_Core_Bootstrap {
         * @api
         */
        public function initialize($configuration) {
-               if (!isset($configuration['extensionName']) || strlen($configuration['extensionName']) === 0) {
-                       throw new RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
-               }
-               if (!isset($configuration['pluginName']) || strlen($configuration['pluginName']) === 0) {
-                       throw new RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
+               if (!defined('TYPO3_cliMode') || TYPO3_cliMode !== TRUE) {
+                       if (!isset($configuration['extensionName']) || strlen($configuration['extensionName']) === 0) {
+                               throw new RuntimeException('Invalid configuration: "extensionName" is not set', 1290623020);
+                       }
+                       if (!isset($configuration['pluginName']) || strlen($configuration['pluginName']) === 0) {
+                               throw new RuntimeException('Invalid configuration: "pluginName" is not set', 1290623027);
+                       }
                }
                $this->initializeObjectManager();
                $this->initializeConfiguration($configuration);
@@ -102,7 +99,6 @@ class Tx_Extbase_Core_Bootstrap {
                $this->initializeReflection();
                $this->initializePersistence();
                $this->initializeBackwardsCompatibility();
-               $this->isInitialized = TRUE;
        }
 
        /**
@@ -118,6 +114,7 @@ class Tx_Extbase_Core_Bootstrap {
        /**
         * Initializes the Object framework.
         *
+        * @param array $configuration
         * @return void
         * @see initialize()
         */
@@ -200,20 +197,45 @@ class Tx_Extbase_Core_Bootstrap {
         * Runs the the Extbase Framework by resolving an appropriate Request Handler and passing control to it.
         * If the Framework is not initialized yet, it will be initialized.
         *
-        * @param string $content The content
+        * @param string $content The content. Not used
         * @param array $configuration The TS configuration array
         * @return string $content The processed content
         * @api
         */
        public function run($content, $configuration) {
-               //var_dump(Tx_Extbase_Utility_Extension::createAutoloadRegistryForExtension('extbase', t3lib_extMgm::extPath('extbase'), array(
-               //      'tx_extbase_basetestcase' => '$extensionClassesPath . \'../Tests/BaseTestCase.php\'',
-               //      'tx_extbase_tests_unit_basetestcase' => '$extensionClassesPath . \'../Tests/Unit/BaseTestCase.php\'',
-               //)));
-               //die("autoload registry");
-
                $this->initialize($configuration);
 
+                       // CLI
+               if (defined('TYPO3_cliMode') && TYPO3_cliMode === TRUE) {
+                       $content = $this->handleCommandLineRequest();
+               } else {
+                       $content = $this->handleWebRequest();
+               }
+               return $content;
+       }
+
+       /**
+        * @return string
+        */
+       protected function handleCommandLineRequest() {
+               $commandLine = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
+
+               $request = $this->objectManager->get('Tx_Extbase_MVC_CLI_RequestBuilder')->build(array_slice($commandLine, 1));
+               $response = $this->objectManager->get('Tx_Extbase_MVC_CLI_Response');
+               $extensionName = $request->getControllerExtensionName();
+               $this->configurationManager->setConfiguration(array('extensionName' => $extensionName));
+               $this->objectManager->get('Tx_Extbase_MVC_Dispatcher')->dispatch($request, $response);
+
+               $content = $response->getContent();
+
+               $this->resetSingletons();
+               return $content;
+       }
+
+       /**
+        * @return string
+        */
+       protected function handleWebRequest() {
                $requestHandlerResolver = $this->objectManager->get('Tx_Extbase_MVC_RequestHandlerResolver');
                $requestHandler = $requestHandlerResolver->resolveRequestHandler();
 
@@ -285,5 +307,6 @@ class Tx_Extbase_Core_Bootstrap {
                print $content;
                return TRUE;
        }
+
 }
 ?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/Command.php b/typo3/sysext/extbase/Classes/MVC/CLI/Command.php
new file mode 100644 (file)
index 0000000..51de74f
--- /dev/null
@@ -0,0 +1,249 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Represents a Command
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_CLI_Command {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @var string
+        */
+       protected $controllerClassName;
+
+       /**
+        * @var string
+        */
+       protected $controllerCommandName;
+
+       /**
+        * @var string
+        */
+       protected $commandIdentifier;
+
+       /**
+        * @var Tx_Extbase_Reflection_MethodReflection
+        */
+       protected $commandMethodReflection;
+
+       /**
+        * Reflection service
+        * @var Tx_Extbase_Reflection_Service
+        */
+       private $reflectionService;
+
+       /**
+        * Constructor
+        *
+        * @param string $controllerClassName Class name of the controller providing the command
+        * @param string $controllerCommandName Command name, i.e. the method name of the command, without the "Command" suffix
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function __construct($controllerClassName, $controllerCommandName) {
+               $this->controllerClassName = $controllerClassName;
+               $this->controllerCommandName = $controllerCommandName;
+
+               $classNameParts = explode('_', $controllerClassName);
+               if (count($classNameParts) !== 4 || strpos($classNameParts[3], 'CommandController') === FALSE) {
+                       throw new InvalidArgumentException('Invalid controller class name "' . $controllerClassName . '"', 1305100019);
+               }
+               $extensionKey = t3lib_div::camelCaseToLowerCaseUnderscored($classNameParts[1]);
+               $this->commandIdentifier = strtolower($extensionKey . ':' . substr($classNameParts[3], 0, -17) . ':' . $controllerCommandName);
+       }
+
+       /**
+        * @param Tx_Extbase_Reflection_Service $reflectionService Reflection service
+        */
+       public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
+               $this->reflectionService = $reflectionService;
+       }
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager A reference to the object manager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @return string
+        */
+       public function getControllerClassName() {
+               return $this->controllerClassName;
+       }
+
+       /**
+        * @return string
+        */
+       public function getControllerCommandName() {
+               return $this->controllerCommandName;
+       }
+
+       /**
+        * Returns the command identifier for this command
+        *
+        * @return string The command identifier for this command, following the pattern extensionname:controllername:commandname
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getCommandIdentifier() {
+               return $this->commandIdentifier;
+       }
+
+       /**
+        * Returns a short description of this command
+        *
+        * @return string A short description
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getShortDescription() {
+               $lines = explode(chr(10), $this->getCommandMethodReflection()->getDescription());
+               return (count($lines) > 0) ? trim($lines[0]) : '<no description available>';
+       }
+
+       /**
+        * Returns a longer description of this command
+        * This is the complete method description except for the first line which can be retrieved via getShortDescription()
+        * If The command description only consists of one line, an empty string is returned
+        *
+        * @return string A longer description of this command
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getDescription() {
+               $lines = explode(chr(10), $this->getCommandMethodReflection()->getDescription());
+               array_shift($lines);
+               $descriptionLines = array();
+               foreach ($lines as $line) {
+                       $trimmedLine = trim($line);
+                       if ($descriptionLines !== array() || $trimmedLine !== '') {
+                               $descriptionLines[] = $trimmedLine;
+                       }
+               }
+               return implode(chr(10), $descriptionLines);
+       }
+
+       /**
+        * Returns TRUE if this command expects required and/or optional arguments, otherwise FALSE
+        *
+        * @return boolean
+        */
+       public function hasArguments() {
+               return count($this->getCommandMethodReflection()->getParameters()) > 0;
+       }
+
+       /**
+        * Returns an array of Tx_Extbase_MVC_CLI_CommandArgumentDefinition that contains
+        * information about required/optional arguments of this command.
+        * If the command does not expect any arguments, an empty array is returned
+        *
+        * @return array<Tx_Extbase_MVC_CLI_CommandArgumentDefinition>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getArgumentDefinitions() {
+               if (!$this->hasArguments()) {
+                       return array();
+               }
+               $commandArgumentDefinitions = array();
+               $commandMethodReflection = $this->getCommandMethodReflection();
+               $annotations = $commandMethodReflection->getTagsValues();
+               $commandParameters = $this->reflectionService->getMethodParameters($this->controllerClassName, $this->controllerCommandName . 'Command');
+               $i = 0;
+               foreach ($commandParameters as $commandParameterName => $commandParameterDefinition) {
+                       $explodedAnnotation = explode(' ', $annotations['param'][$i]);
+                       array_shift($explodedAnnotation);
+                       array_shift($explodedAnnotation);
+                       $description = implode(' ', $explodedAnnotation);
+                       $required = $commandParameterDefinition['optional'] !== TRUE;
+                       $commandArgumentDefinitions[] = $this->objectManager->get('Tx_Extbase_MVC_CLI_CommandArgumentDefinition', $commandParameterName, $required, $description);
+                       $i ++;
+               }
+               return $commandArgumentDefinitions;
+       }
+
+       /**
+        * Tells if this command is internal and thus should not be exposed through help texts, user documentation etc.
+        * Internall commands are still accessible through the regular command line interface, but should not be used
+        * by users.
+        *
+        * @return boolean
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function isInternal() {
+               return $this->getCommandMethodReflection()->isTaggedWith('internal');
+       }
+
+       /**
+        * Tells if this command flushes all caches and thus needs special attention in the interactive shell.
+        *
+        * Note that neither this method nor the @flushesCaches annotation is currently part of the official API.
+        *
+        * @return boolean
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function isFlushingCaches() {
+               return $this->getCommandMethodReflection()->isTaggedWith('flushesCaches');
+       }
+
+       /**
+        * Returns an array of command identifiers which were specified in the "@see"
+        * annotation of a command method.
+        *
+        * @return array
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getRelatedCommandIdentifiers() {
+               $commandMethodReflection = $this->getCommandMethodReflection();
+               if (!$commandMethodReflection->isTaggedWith('see')) {
+                       return array();
+               }
+
+               $relatedCommandIdentifiers = array();
+               foreach ($commandMethodReflection->getTagValues('see') as $tagValue) {
+                       if (preg_match('/^[\w\d\.]+:[\w\d]+:[\w\d]+$/', $tagValue) === 1) {
+                               $relatedCommandIdentifiers[] = $tagValue;
+                       }
+               }
+               return $relatedCommandIdentifiers;
+       }
+
+       /**
+        * @return Tx_Extbase_Reflection_MethodReflection
+        */
+       protected function getCommandMethodReflection() {
+               if ($this->commandMethodReflection === NULL) {
+                       $this->commandMethodReflection = $this->objectManager->get('Tx_Extbase_Reflection_MethodReflection', $this->controllerClassName, $this->controllerCommandName . 'Command');
+               }
+               return $this->commandMethodReflection;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/CommandArgumentDefinition.php b/typo3/sysext/extbase/Classes/MVC/CLI/CommandArgumentDefinition.php
new file mode 100644 (file)
index 0000000..e30e2e1
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Represents a CommandArgumentDefinition
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_CLI_CommandArgumentDefinition {
+
+       /**
+        * @var string
+        */
+       protected $name = '';
+
+       /**
+        * @var boolean
+        */
+       protected $required = FALSE;
+
+       /**
+        * @var string
+        */
+       protected $description = '';
+
+       /**
+        * Constructor
+        *
+        * @param string $name name of the command argument (= parameter name)
+        * @param boolean $required defines whether this argument is required or optional
+        * @param string $description description of the argument
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function __construct($name, $required, $description) {
+               $this->name = $name;
+               $this->required = $required;
+               $this->description = $description;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * Returns the lowercased name with dashes as word separator
+        *
+        * @return string
+        */
+       public function getDashedName() {
+               $dashedName = ucfirst($this->name);
+               $dashedName = preg_replace('/([A-Z][a-z0-9]+)/', '$1-', $dashedName);
+               return '--' . strtolower(substr($dashedName, 0, -1));
+       }
+
+       /**
+        * @return string
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+
+       /**
+        * @return string
+        */
+       public function isRequired() {
+               return $this->required;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/CommandManager.php b/typo3/sysext/extbase/Classes/MVC/CLI/CommandManager.php
new file mode 100644 (file)
index 0000000..e2c058d
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * A helper for CLI commands
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_CLI_CommandManager implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @var array<Tx_Extbase_MVC_CLI_Command>
+        */
+       protected $availableCommands = NULL;
+
+       /**
+        * @var array
+        */
+       protected $shortCommandIdentifiers = NULL;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager A reference to the object manager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * Returns an array of all commands
+        *
+        * @return array<Tx_Extbase_MVC_CLI_Command>
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        * @api
+        */
+       public function getAvailableCommands() {
+               if ($this->availableCommands === NULL) {
+                       $this->availableCommands = array();
+
+                       $commandControllerClassNames = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'];
+                       foreach ($commandControllerClassNames as $className) {
+                               if (!class_exists($className)) {
+                                       continue;
+                               }
+                               foreach (get_class_methods($className) as $methodName) {
+                                       if (substr($methodName, -7, 7) === 'Command') {
+                                               $this->availableCommands[] = $this->objectManager->get('Tx_Extbase_MVC_CLI_Command', $className, substr($methodName, 0, -7));
+                                       }
+                               }
+                       }
+               }
+               return $this->availableCommands;
+       }
+
+       /**
+        * Returns a Command that matches the given identifier.
+        * If no Command could be found a CommandNotFoundException is thrown
+        * If more than one Command matches an AmbiguousCommandIdentifierException is thrown that contains the matched Commands
+        *
+        * @param string $commandIdentifier command identifier in the format foo:bar:baz
+        * @return Tx_Extbase_MVC_CLI_Command
+        * @throws Tx_Extbase_MVC_Exception_NoSuchCommand if no matching command is available
+        * @throws Tx_Extbase_MVC_Exception_AmbiguousCommandIdentifier if more than one Command matches the identifier (the exception contains the matched commands)
+        * @api
+        */
+       public function getCommandByIdentifier($commandIdentifier) {
+               $commandIdentifier = strtolower(trim($commandIdentifier));
+               if ($commandIdentifier === 'help') {
+                       $commandIdentifier = 'extbase:help:help';
+               }
+               $matchedCommands = array();
+               $availableCommands = $this->getAvailableCommands();
+               foreach ($availableCommands as $command) {
+                       if ($this->commandMatchesIdentifier($command, $commandIdentifier)) {
+                               $matchedCommands[] = $command;
+                       }
+               }
+               if (count($matchedCommands) === 0) {
+                       throw new Tx_Extbase_MVC_Exception_NoSuchCommand('No command could be found that matches the command identifier "' . $commandIdentifier . '".', 1310556663);
+               }
+               if (count($matchedCommands) > 1) {
+                       throw new Tx_Extbase_MVC_Exception_AmbiguousCommandIdentifier('More than one command matches the command identifier "' . $commandIdentifier . '"', 1310557169, NULL, $matchedCommands);
+               }
+               return current($matchedCommands);
+       }
+
+       /**
+        * Returns the shortest, non-ambiguous command identifier for the given command
+        *
+        * @param Tx_Extbase_MVC_CLI_Command $command The command
+        * @return string The shortest possible command identifier
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        * @api
+        */
+       public function getShortestIdentifierForCommand(Tx_Extbase_MVC_CLI_Command $command) {
+               if ($command->getCommandIdentifier() === 'extbase:help:help') {
+                       return 'help';
+               }
+               $shortCommandIdentifiers = $this->getShortCommandIdentifiers();
+               if (!isset($shortCommandIdentifiers[$command->getCommandIdentifier()])) {
+                       $command->getCommandIdentifier();
+               }
+               return $shortCommandIdentifiers[$command->getCommandIdentifier()];
+       }
+
+       /**
+        * Returns an array that contains all available command identifiers and their shortest non-ambiguous alias
+        *
+        * @return array in the format array('full.command:identifier1' => 'alias1', 'full.command:identifier2' => 'alias2')
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       protected function getShortCommandIdentifiers() {
+               if ($this->shortCommandIdentifiers === NULL) {
+                       $commandsByCommandName = array();
+                       foreach ($this->getAvailableCommands() as $availableCommand) {
+                               list($extensionKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier());
+                               if (!isset($commandsByCommandName[$commandName])) {
+                                       $commandsByCommandName[$commandName] = array();
+                               }
+                               if (!isset($commandsByCommandName[$commandName][$controllerName])) {
+                                       $commandsByCommandName[$commandName][$controllerName] = array();
+                               }
+                               $commandsByCommandName[$commandName][$controllerName][] = $extensionKey;
+                       }
+                       foreach ($this->getAvailableCommands() as $availableCommand) {
+                               list($extensionKey, $controllerName, $commandName) = explode(':', $availableCommand->getCommandIdentifier());
+                               if (count($commandsByCommandName[$commandName][$controllerName]) > 1) {
+                                       $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s:%s', $extensionKey, $controllerName, $commandName);;
+                               } else {
+                                       $this->shortCommandIdentifiers[$availableCommand->getCommandIdentifier()] = sprintf('%s:%s', $controllerName, $commandName);;
+                               }
+                       }
+               }
+               return $this->shortCommandIdentifiers;
+       }
+
+       /**
+        * Returns TRUE if the specified command identifier matches the identifier of the specified command.
+        * This is the case, if the identifiers are the same or if at least the last two command parts match (case sensitive).
+        *
+        * @param Tx_Extbase_MVC_CLI_Command $command
+        * @param string $commandIdentifier command identifier in the format foo:bar:baz (all lower case)
+        * @return boolean TRUE if the specified command identifier matches this commands identifier
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       protected function commandMatchesIdentifier(Tx_Extbase_MVC_CLI_Command $command, $commandIdentifier) {
+               $commandIdentifierParts = explode(':', $command->getCommandIdentifier());
+               $searchedCommandIdentifierParts = explode(':', $commandIdentifier);
+               $extensionKey = array_shift($commandIdentifierParts);
+               if (count($searchedCommandIdentifierParts) === 3) {
+                       $searchedExtensionKey = array_shift($searchedCommandIdentifierParts);
+                       if ($searchedExtensionKey !== $extensionKey) {
+                               return FALSE;
+                       }
+               }
+               if (count($searchedCommandIdentifierParts) !== 2) {
+                       return FALSE;
+               }
+               return $searchedCommandIdentifierParts === $commandIdentifierParts;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/Request.php b/typo3/sysext/extbase/Classes/MVC/CLI/Request.php
new file mode 100644 (file)
index 0000000..638f27f
--- /dev/null
@@ -0,0 +1,265 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Represents a CLI request.
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ * @api
+ */
+class Tx_Extbase_MVC_CLI_Request implements Tx_Extbase_MVC_RequestInterface {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @var string
+        */
+       protected $controllerObjectName;
+
+       /**
+        * @var string
+        */
+       protected $controllerCommandName = 'default';
+
+       /**
+        * @var string Name of the extension which is supposed to handle this request.
+        */
+       protected $controllerExtensionName = NULL;
+
+       /**
+        * The arguments for this request
+        * @var array
+        */
+       protected $arguments = array();
+
+       /**
+        * @var array
+        */
+       protected $exceedingArguments = array();
+
+       /**
+        * If this request has been changed and needs to be dispatched again
+        * @var boolean
+        */
+       protected $dispatched = FALSE;
+
+       /**
+        *
+        * @var array
+        */
+       protected $commandLineArguments;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager A reference to the object manager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * Sets the dispatched flag
+        *
+        * @param boolean $flag If this request has been dispatched
+        * @return void
+        */
+       public function setDispatched($flag) {
+               $this->dispatched = $flag ? TRUE : FALSE;
+       }
+
+       /**
+        * If this request has been dispatched and addressed by the responsible
+        * controller and the response is ready to be sent.
+        *
+        * The dispatcher will try to dispatch the request again if it has not been
+        * addressed yet.
+        *
+        * @return boolean TRUE if this request has been disptached successfully
+        */
+       public function isDispatched() {
+               return $this->dispatched;
+       }
+
+       /**
+        * Sets the object name of the controller
+        *
+        * @param string $controllerObjectName The fully qualified controller object name
+        * @return void
+        */
+       public function setControllerObjectName($controllerObjectName) {
+               $matches = array();
+               preg_match('/
+                       ^Tx
+                       _(?P<extensionName>[^_]+)
+                       _
+                       (
+                               Command
+                       |
+                               (?P<subpackageKey>.+)_Controller
+                       )
+                       _(?P<controllerName>[a-z_]+)Controller
+                       $/ix', $controllerObjectName, $matches
+               );
+
+               $this->controllerExtensionName = $matches['extensionName'];
+               $this->controllerObjectName = $controllerObjectName;
+               $this->command = NULL;
+       }
+
+       /**
+        * Returns the object name of the controller
+        *
+        * @return string The controller's object name
+        */
+       public function getControllerObjectName() {
+               return $this->controllerObjectName;
+       }
+
+       /**
+        * Returns the extension name of the specified controller.
+        *
+        * @return string The extension name
+        */
+       public function getControllerExtensionName() {
+               return $this->controllerExtensionName;
+       }
+
+       /**
+        * Sets the name of the command contained in this request.
+        *
+        * Note that the command name must start with a lower case letter and is case sensitive.
+        *
+        * @param string $commandName Name of the command to execute by the controller
+        * @return void
+        */
+       public function setControllerCommandName($commandName) {
+               $this->controllerCommandName = $commandName;
+               $this->command = NULL;
+       }
+
+       /**
+        * Returns the name of the command the controller is supposed to execute.
+        *
+        * @return string Command name
+        */
+       public function getControllerCommandName() {
+               return $this->controllerCommandName;
+       }
+
+       /**
+        * Returns the command object for this request
+        *
+        * @return Tx_Extbase_MVC_CLI_Command
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getCommand() {
+               if ($this->command === NULL) {
+                       $this->command = $this->objectManager->get('Tx_Extbase_MVC_CLI_Command', $this->controllerObjectName, $this->controllerCommandName);
+               }
+               return $this->command;
+       }
+
+       /**
+        * Sets the value of the specified argument
+        *
+        * @param string $argumentName Name of the argument to set
+        * @param mixed $value The new value
+        * @return void
+        */
+       public function setArgument($argumentName, $value) {
+               if (!is_string($argumentName) || $argumentName === '') throw new Tx_Extbase_MVC_Exception_InvalidArgumentName('Invalid argument name.', 1300893885);
+               $this->arguments[$argumentName] = $value;
+       }
+
+       /**
+        * Sets the whole arguments ArrayObject and therefore replaces any arguments
+        * which existed before.
+        *
+        * @param array $arguments An array of argument names and their values
+        * @return void
+        */
+       public function setArguments(array $arguments) {
+               $this->arguments = $arguments;
+       }
+
+       /**
+        * Returns the value of the specified argument
+        *
+        * @param string $argumentName Name of the argument
+        * @return string Value of the argument
+        * @throws Tx_Extbase_MVC_Exception_NoSuchArgument if such an argument does not exist
+        */
+       public function getArgument($argumentName) {
+               if (!isset($this->arguments[$argumentName])) throw new Tx_Extbase_MVC_Exception_NoSuchArgument('An argument "' . $argumentName . '" does not exist for this request.', 1300893886);
+               return $this->arguments[$argumentName];
+       }
+
+       /**
+        * Checks if an argument of the given name exists (is set)
+        *
+        * @param string $argumentName Name of the argument to check
+        * @return boolean TRUE if the argument is set, otherwise FALSE
+        */
+       public function hasArgument($argumentName) {
+               return isset($this->arguments[$argumentName]);
+       }
+
+       /**
+        * Returns an ArrayObject of arguments and their values
+        *
+        * @return array Array of arguments and their values (which may be arguments and values as well)
+        */
+       public function getArguments() {
+               return $this->arguments;
+       }
+
+       /**
+        * Sets the exceeding arguments
+        *
+        * @param array $exceedingArguments Numeric array of exceeding arguments
+        * @return void
+        */
+       public function setExceedingArguments(array $exceedingArguments) {
+               $this->exceedingArguments = $exceedingArguments;
+       }
+
+       /**
+        * Returns additional unnamed arguments (if any) which have been passed through the command line after all
+        * required arguments (if any) have been specified.
+        *
+        * For a command method with the signature ($argument1, $argument2) and for the command line
+        * cli_dispatch.phpsh extbase some-key someaction acme:foo --argument1 Foo --argument2 Bar baz quux
+        * this method would return array(0 => 'baz', 1 => 'quux')
+        *
+        * @return array Numeric array of exceeding argument values
+        */
+       public function getExceedingArguments() {
+               return $this->exceedingArguments;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/RequestBuilder.php b/typo3/sysext/extbase/Classes/MVC/CLI/RequestBuilder.php
new file mode 100644 (file)
index 0000000..6289ba3
--- /dev/null
@@ -0,0 +1,243 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Builds a CLI request object from the raw command call
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_CLI_RequestBuilder {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @var Tx_Extbase_Reflection_Service
+        */
+       protected $reflectionService;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_CommandManager
+        */
+       protected $commandManager;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @param Tx_Extbase_Reflection_Service $reflectionService
+        * @return void
+        */
+       public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
+               $this->reflectionService = $reflectionService;
+       }
+
+       /**
+        * @param Tx_Extbase_MVC_CLI_CommandManager $commandManager
+        * @return void
+        */
+       public function injectCommandManager(Tx_Extbase_MVC_CLI_CommandManager $commandManager) {
+               $this->commandManager = $commandManager;
+       }
+
+       /**
+        * Builds a CLI request object from a command line.
+        *
+        * The given command line may be a string (e.g. "myextension:foo do-that-thing --force") or
+        * an array consisting of the individual parts. The array must not include the script
+        * name (like in $argv) but start with command right away.
+        *
+        * @param mixed $commandLine The command line, either as a string or as an array
+        * @return Tx_Extbase_MVC_CLI_Request The CLI request as an object
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function build($commandLine) {
+               $request = $this->objectManager->get('Tx_Extbase_MVC_CLI_Request');
+               $request->setControllerObjectName('Tx_Extbase_Command_HelpCommandController');
+
+               $rawCommandLineArguments = is_array($commandLine) ? $commandLine : explode(' ', $commandLine);
+               if (count($rawCommandLineArguments) === 0) {
+                       $request->setControllerCommandName('helpStub');
+                       return $request;
+               }
+               $commandIdentifier = trim(array_shift($rawCommandLineArguments));
+               try {
+                       $command = $this->commandManager->getCommandByIdentifier($commandIdentifier);
+               } catch (Tx_Extbase_MVC_Exception_Command $exception) {
+                       $request->setArgument('exception', $exception);
+                       $request->setControllerCommandName('error');
+                       return $request;
+               }
+               $controllerObjectName = $command->getControllerClassName();
+               $controllerCommandName = $command->getControllerCommandName();
+               $request->setControllerObjectName($controllerObjectName);
+               $request->setControllerCommandName($controllerCommandName);
+
+               list($commandLineArguments, $exceedingCommandLineArguments) = $this->parseRawCommandLineArguments($rawCommandLineArguments, $controllerObjectName, $controllerCommandName);
+               $request->setArguments($commandLineArguments);
+               $request->setExceedingArguments($exceedingCommandLineArguments);
+
+               return $request;
+       }
+
+       /**
+        * Takes an array of unparsed command line arguments and options and converts it separated
+        * by named arguments, options and unnamed arguments.
+        *
+        * @param array $rawCommandLineArguments The unparsed command parts (such as "--foo") as an array
+        * @param string $controllerObjectName Object name of the designated command controller
+        * @param string $controllerCommandName Command name of the recognized command (ie. method name without "Command" suffix)
+        * @return array All and exceeding command line arguments
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function parseRawCommandLineArguments(array $rawCommandLineArguments, $controllerObjectName, $controllerCommandName) {
+               $commandLineArguments = array();
+               $exceedingArguments = array();
+               $commandMethodName = $controllerCommandName . 'Command';
+               $commandMethodParameters = $this->reflectionService->getMethodParameters($controllerObjectName, $commandMethodName);
+
+               $requiredArguments = array();
+               $optionalArguments = array();
+               $argumentNames = array();
+               foreach ($commandMethodParameters as $parameterName => $parameterInfo) {
+                       $argumentNames[] = $parameterName;
+                       if ($parameterInfo['optional'] === FALSE) {
+                               $requiredArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
+                       } else {
+                               $optionalArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
+                       }
+               }
+
+               $decidedToUseNamedArguments = FALSE;
+               $decidedToUseUnnamedArguments = FALSE;
+               $argumentIndex = 0;
+               while (count($rawCommandLineArguments) > 0) {
+
+                       $rawArgument = array_shift($rawCommandLineArguments);
+
+                       if ($rawArgument[0] === '-') {
+                               if ($rawArgument[1] === '-') {
+                                       $rawArgument = substr($rawArgument, 2);
+                               } else {
+                                       $rawArgument = substr($rawArgument, 1);
+                               }
+                               $argumentName = $this->extractArgumentNameFromCommandLinePart($rawArgument);
+
+                               if (isset($optionalArguments[$argumentName])) {
+                                       $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $optionalArguments[$argumentName]['type']);
+                                       $commandLineArguments[$optionalArguments[$argumentName]['parameterName']] = $argumentValue;
+                               } elseif(isset($requiredArguments[$argumentName])) {
+                                       if ($decidedToUseUnnamedArguments) {
+                                               throw new Tx_Extbase_MVC_Exception_InvalidArgumentMixing(sprintf('Unexpected named argument "%s". If you use unnamed arguments, all required arguments must be passed without a name.', $argumentName), 1309971821);
+                                       }
+                                       $decidedToUseNamedArguments = TRUE;
+                                       $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $requiredArguments[$argumentName]['type']);
+                                       $commandLineArguments[$requiredArguments[$argumentName]['parameterName']] = $argumentValue;
+                                       unset($requiredArguments[$argumentName]);
+                               }
+                       } else {
+                               if (count($requiredArguments) > 0) {
+                                       if ($decidedToUseNamedArguments) {
+                                               throw new Tx_Extbase_MVC_Exception_InvalidArgumentMixing(sprintf('Unexpected unnamed argument "%s". If you use named arguments, all required arguments must be passed named.', $rawArgument), 1309971820);
+                                       }
+                                       $argument = array_shift($requiredArguments);
+                                       $commandLineArguments[$argument['parameterName']] = $rawArgument;
+                                       $decidedToUseUnnamedArguments = TRUE;
+                               } else {
+                                       if ($argumentIndex < count($argumentNames)) {
+                                               $commandLineArguments[$argumentNames[$argumentIndex]] = $rawArgument;
+                                       } else {
+                                               $exceedingArguments[] = $rawArgument;
+                                       }
+                               }
+                       }
+                       $argumentIndex ++;
+               }
+
+               return array($commandLineArguments, $exceedingArguments);
+       }
+
+       /**
+        * Extracts the option or argument name from the name / value pair of a command line.
+        *
+        * @param string $commandLinePart Part of the command line, e.g. "my-important-option=SomeInterestingValue"
+        * @return string The lowercased argument name, e.g. "myimportantoption"
+        */
+       protected function extractArgumentNameFromCommandLinePart($commandLinePart) {
+               $nameAndValue = explode('=', $commandLinePart, 2);
+               return strtolower(str_replace('-', '', $nameAndValue[0]));
+       }
+
+       /**
+        * Returns the value of the first argument of the given input array. Shifts the parsed argument off the array.
+        *
+        * @param string $currentArgument The current argument
+        * @param array &$rawCommandLineArguments Array of the remaining command line arguments
+        * @param string $expectedArgumentType The expected type of the current argument, because booleans get special attention
+        * @return string The value of the first argument
+        * @author Andreas Förthner <andreas.foerthner@netlogix.de>
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function getValueOfCurrentCommandLineOption($currentArgument, array &$rawCommandLineArguments, $expectedArgumentType) {
+               if (!isset($rawCommandLineArguments[0]) || (isset($rawCommandLineArguments[0]) && $rawCommandLineArguments[0][0] === '-' && (strpos($currentArgument, '=') === FALSE))) {
+                       return TRUE;
+               }
+
+               if (strpos($currentArgument, '=') === FALSE) {
+                       $possibleValue = trim(array_shift($rawCommandLineArguments));
+                       if (strpos($possibleValue, '=') === FALSE) {
+                               if ($expectedArgumentType !== 'boolean') {
+                                       return $possibleValue;
+                               }
+                               if (array_search($possibleValue, array('on', '1', 'y', 'yes', 'true', 'TRUE')) !== FALSE) {
+                                       return TRUE;
+                               }
+                               if (array_search($possibleValue, array('off', '0', 'n', 'no', 'false', 'FALSE')) !== FALSE) {
+                                       return FALSE;
+                               }
+                               array_unshift($rawCommandLineArguments, $possibleValue);
+                               return TRUE;
+                       }
+                       $currentArgument .= $possibleValue;
+               }
+
+               $splitArgument = explode('=', $currentArgument, 2);
+               while ((!isset($splitArgument[1]) || trim($splitArgument[1]) === '') && count($rawCommandLineArguments) > 0) {
+                       $currentArgument .= array_shift($rawCommandLineArguments);
+                       $splitArgument = explode('=', $currentArgument);
+               }
+
+               $value = (isset($splitArgument[1])) ? $splitArgument[1] : '';
+               return $value;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/RequestHandler.php b/typo3/sysext/extbase/Classes/MVC/CLI/RequestHandler.php
new file mode 100644 (file)
index 0000000..a4e6764
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * The generic command line interface request handler for the MVC framework.
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_CLI_RequestHandler implements Tx_Extbase_MVC_RequestHandlerInterface {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @var Tx_Extbase_MVC_Dispatcher
+        */
+       protected $dispatcher;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_RequestBuilder
+        */
+       protected $requestBuilder;
+
+       /**
+        * @var Tx_Extbase_MVC_Controller_FlashMessages
+        * @deprecated since Extbase 1.1; will be removed in Extbase 1.6
+        */
+       protected $flashMessages;
+
+       /**
+        * @var Tx_Extbase_MVC_Controller_FlashMessages
+        */
+       protected $flashMessageContainer;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @param Tx_Extbase_MVC_Controller_FlashMessages $flashMessageContainer
+        * @return void
+        */
+       public function injectFlashMessageContainer(Tx_Extbase_MVC_Controller_FlashMessages $flashMessageContainer) {
+               $this->flashMessageContainer = $flashMessageContainer;
+                       // @deprecated since Extbase 1.1; will be removed in Extbase 1.6
+               $this->flashMessages = $flashMessageContainer;
+       }
+
+       /**
+        * @param Tx_Extbase_MVC_Dispatcher $dispatcher
+        * @return void
+        */
+       public function injectDispatcher(Tx_Extbase_MVC_Dispatcher $dispatcher) {
+               $this->dispatcher = $dispatcher;
+       }
+
+       /**
+        * @param Tx_Extbase_MVC_CLI_RequestBuilder $requestBuilder
+        * @return void
+        */
+       public function injectRequestBuilder(Tx_Extbase_MVC_CLI_RequestBuilder $requestBuilder) {
+               $this->requestBuilder = $requestBuilder;
+       }
+
+       /**
+        * Handles the request
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function handleRequest() {
+               $request = $this->requestBuilder->build();
+               $response = $this->objectManager->create('Tx_Extbase_MVC_CLI_Response');
+               $this->dispatcher->dispatch($request, $response);
+               $response->send();
+       }
+
+       /**
+        * This request handler can handle any command line request.
+        *
+        * @return boolean If the request is a command line request, TRUE otherwise FALSE
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function canHandleRequest() {
+               return (PHP_SAPI === 'cli');
+       }
+
+       /**
+        * Returns the priority - how eager the handler is to actually handle the
+        * request.
+        *
+        * @return integer The priority of the request handler.
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getPriority() {
+               return 110;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/CLI/Response.php b/typo3/sysext/extbase/Classes/MVC/CLI/Response.php
new file mode 100644 (file)
index 0000000..1195bd2
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * A CLI specific response implementation
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ * @scope prototype
+ */
+class Tx_Extbase_MVC_CLI_Response extends Tx_Extbase_MVC_Response {
+
+       /**
+        * @var integer
+        */
+       private $exitCode = 0;
+
+       /**
+        * Sets the numerical exit code which should be returned when exiting this application.
+        *
+        * @param integer $exitCode
+        * @return void
+        * @api
+        */
+       public function setExitCode($exitCode) {
+               if (!is_integer($exitCode)) {
+                       throw new InvalidArgumentException(sprintf('Tried to set invalid exit code. The value must be integer, %s given.', gettype($exitCode)), 1312222064);
+               }
+               $this->exitCode = $exitCode;
+       }
+
+       /**
+        * Rets the numerical exit code which should be returned when exiting this application.
+        *
+        * @return integer
+        * @api
+        */
+       public function getExitCode() {
+               return $this->exitCode;
+       }
+
+       /**
+        * Renders and sends the whole web response
+        *
+        * @return void
+        * @api
+        */
+       public function send() {
+               if ($this->content !== NULL) {
+                       echo $this->getContent();
+               }
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Controller/CommandController.php b/typo3/sysext/extbase/Classes/MVC/Controller/CommandController.php
new file mode 100644 (file)
index 0000000..5285df6
--- /dev/null
@@ -0,0 +1,280 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * A controller which processes requests from the command line
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_Controller_CommandController implements Tx_Extbase_MVC_Controller_CommandControllerInterface {
+
+       const MAXIMUM_LINE_LENGTH = 79;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Request
+        */
+       protected $request;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Response
+        */
+       protected $response;
+
+       /**
+        * @var Tx_Extbase_MVC_Controller_Arguments
+        */
+       protected $arguments;
+
+       /**
+        * Name of the command method
+        *
+        * @var string
+        */
+       protected $commandMethodName = '';
+
+       /**
+        * @var Tx_Extbase_Reflection_Service
+        */
+       protected $reflectionService;
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * @param Tx_Extbase_Reflection_Service $reflectionService
+        * @return void
+        */
+       public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
+               $this->reflectionService = $reflectionService;
+       }
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+               $this->arguments = $this->objectManager->create('Tx_Extbase_MVC_Controller_Arguments');
+       }
+
+       /**
+        * Checks if the current request type is supported by the controller.
+        *
+        * @param Tx_Extbase_MVC_RequestInterface $request The current request
+        * @return boolean TRUE if this request type is supported, otherwise FALSE
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function canProcessRequest(Tx_Extbase_MVC_RequestInterface $request) {
+               return $request instanceof Tx_Extbase_MVC_CLI_Request;
+       }
+
+       /**
+        * Processes a command line request.
+        *
+        * @param \TYPO3\FLOW3\MVC\RequestInterface $request The request object
+        * @param \TYPO3\FLOW3\MVC\ResponseInterface $response The response, modified by this controller
+        * @return void
+        * @throws \TYPO3\FLOW3\MVC\Exception\UnsupportedRequestTypeException if the controller doesn't support the current request type
+        * @author Robert Lemke <robert@typo3.org>
+        * @api
+        */
+       public function processRequest(Tx_Extbase_MVC_RequestInterface $request, Tx_Extbase_MVC_ResponseInterface $response) {
+               if (!$this->canProcessRequest($request)) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType(get_class($this) . ' does not support requests of type "' . get_class($request) . '".' , 1300787096);
+
+               $this->request = $request;
+               $this->request->setDispatched(TRUE);
+               $this->response = $response;
+
+               $this->commandMethodName = $this->resolveCommandMethodName();
+               $this->initializeCommandMethodArguments();
+               $this->mapRequestArgumentsToControllerArguments();
+               $this->callCommandMethod();
+       }
+
+       /**
+        * Resolves and checks the current command method name
+        *
+        * Note: The resulting command method name might not have the correct case, which isn't a problem because PHP is
+        *       case insensitive regarding method names.
+        *
+        * @return string Method name of the current command
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function resolveCommandMethodName() {
+               $commandMethodName = $this->request->getControllerCommandName() . 'Command';
+               if (!is_callable(array($this, $commandMethodName))) {
+                       throw new Tx_Extbase_MVC_Exception_NoSuchCommand('A command method "' . $commandMethodName . '()" does not exist in controller "' . get_class($this) . '".', 1300902143);
+               }
+               return $commandMethodName;
+       }
+
+       /**
+        * Initializes the arguments array of this controller by creating an empty argument object for each of the
+        * method arguments found in the designated command method.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function initializeCommandMethodArguments() {
+               $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), $this->commandMethodName);
+
+               foreach ($methodParameters as $parameterName => $parameterInfo) {
+                       $dataType = NULL;
+                       if (isset($parameterInfo['type'])) {
+                               $dataType = $parameterInfo['type'];
+                       } elseif ($parameterInfo['array']) {
+                               $dataType = 'array';
+                       }
+                       if ($dataType === NULL) throw new Tx_Extbase_MVC_Exception_InvalidArgumentType('The argument type for parameter $' . $parameterName . ' of method ' . get_class($this) . '->' . $this->commandMethodName . '() could not be detected.' , 1306755296);
+                       $defaultValue = (isset($parameterInfo['defaultValue']) ? $parameterInfo['defaultValue'] : NULL);
+                       $this->arguments->addNewArgument($parameterName, $dataType, ($parameterInfo['optional'] === FALSE), $defaultValue);
+               }
+       }
+
+       /**
+        * Maps arguments delivered by the request object to the local controller arguments.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       protected function mapRequestArgumentsToControllerArguments() {
+               foreach ($this->arguments as $argument) {
+                       $argumentName = $argument->getName();
+
+                       if ($this->request->hasArgument($argumentName)) {
+                               $argument->setValue($this->request->getArgument($argumentName));
+                       } elseif ($argument->isRequired()) {
+                               $exception = new Tx_Extbase_MVC_Exception_Command('Required argument "' . $argumentName  . '" is not set.', 1306755520);
+                               $this->forward('error', 'TYPO3\FLOW3\Command\HelpCommandController', array('exception' => $exception));
+                       }
+               }
+       }
+
+       /**
+        * Forwards the request to another command and / or CommandController.
+        *
+        * Request is directly transferred to the other command / controller
+        * without the need for a new request.
+        *
+        * @param string $commandName
+        * @param string $controllerObjectName
+        * @param array $arguments
+        * @return void
+        */
+       protected function forward($commandName, $controllerObjectName = NULL, array $arguments = array()) {
+               $this->request->setDispatched(FALSE);
+               $this->request->setControllerCommandName($commandName);
+               if ($controllerObjectName !== NULL) {
+                       $this->request->setControllerObjectName($controllerObjectName);
+               }
+               $this->request->setArguments($arguments);
+
+               $this->arguments->removeAll();
+               throw new Tx_Extbase_MVC_Exception_StopAction();
+       }
+
+       /**
+        * Calls the specified command method and passes the arguments.
+        *
+        * If the command returns a string, it is appended to the content in the
+        * response object. If the command doesn't return anything and a valid
+        * view exists, the view is rendered automatically.
+        *
+        * @return void
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       protected function callCommandMethod() {
+               $preparedArguments = array();
+               foreach ($this->arguments as $argument) {
+                       $preparedArguments[] = $argument->getValue();
+               }
+
+               $commandResult = call_user_func_array(array($this, $this->commandMethodName), $preparedArguments);
+
+               if (is_string($commandResult) && strlen($commandResult) > 0) {
+                       $this->response->appendContent($commandResult);
+               } elseif (is_object($commandResult) && method_exists($commandResult, '__toString')) {
+                       $this->response->appendContent((string)$commandResult);
+               }
+       }
+
+       /**
+        * Outputs specified text to the console window
+        * You can specify arguments that will be passed to the text via sprintf
+        * @see http://www.php.net/sprintf
+        *
+        * @param string $text Text to output
+        * @param array $arguments Optional arguments to use for sprintf
+        * @return void
+        */
+       protected function output($text, array $arguments = array()) {
+               if ($arguments !== array()) {
+                       $text = vsprintf($text, $arguments);
+               }
+               $this->response->appendContent($text);
+       }
+
+       /**
+        * Outputs specified text to the console window and appends a line break
+        *
+        * @param string $text Text to output
+        * @param array $arguments Optional arguments to use for sprintf
+        * @return void
+        * @see output()
+        */
+       protected function outputLine($text = '', array $arguments = array()) {
+               return $this->output($text . PHP_EOL, $arguments);
+       }
+
+       /**
+        * Exits the CLI through the dispatcher
+        * An exit status code can be specified @see http://www.php.net/exit
+        *
+        * @param integer $exitCode Exit code to return on exit
+        * @return void
+        */
+       protected function quit($exitCode = 0) {
+               $this->response->setExitCode($exitCode);
+               throw new Tx_Extbase_MVC_Exception_StopAction();
+       }
+
+       /**
+        * Sends the response and exits the CLI without any further code execution
+        * Should be used for commands that flush code caches.
+        *
+        * @param integer $exitCode Exit code to return on exit
+        * @return void
+        */
+       protected function sendAndExit($exitCode = 0) {
+               $this->response->send();
+               exit($exitCode);
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Controller/CommandControllerInterface.php b/typo3/sysext/extbase/Classes/MVC/Controller/CommandControllerInterface.php
new file mode 100644 (file)
index 0000000..9aa994c
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * Interface for command controllers
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+interface Tx_Extbase_MVC_Controller_CommandControllerInterface extends Tx_Extbase_MVC_Controller_ControllerInterface {
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/AmbiguousCommandIdentifier.php b/typo3/sysext/extbase/Classes/MVC/Exception/AmbiguousCommandIdentifier.php
new file mode 100644 (file)
index 0000000..684db12
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Extbase Team
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An "Ambiguous command identifier" exception
+ *
+ * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
+ */
+class Tx_Extbase_MVC_Exception_AmbiguousCommandIdentifier extends Tx_Extbase_MVC_Exception_Command {
+
+       /**
+        * @var array<Tx_Extbase_MVC_CLI_Command>
+        */
+       protected $matchingCommands = array();
+
+       /**
+        * Overwrites parent constructor to be able to inject matching commands.
+        *
+        * @param string $message
+        * @param integer $code
+        * @param Exception $previousException
+        * @param array<Tx_Extbase_MVC_CLI_Command> $matchingCommands Commands that matched the command identifier
+        * @see Exception
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function __construct($message = '', $code = 0, Exception $previousException = NULL, array $matchingCommands) {
+               $this->matchingCommands = $matchingCommands;
+               parent::__construct($message, $code, $previousException);
+       }
+
+       /**
+        * @return array<Tx_Extbase_MVC_CLI_Command>
+        */
+       public function getMatchingCommands() {
+               return $this->matchingCommands;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/Command.php b/typo3/sysext/extbase/Classes/MVC/Exception/Command.php
new file mode 100644 (file)
index 0000000..2672cce
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Extbase Team
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Base command exception
+ *
+ * @package Extbase
+ * @subpackage MVC\Exception
+ */
+class Tx_Extbase_MVC_Exception_Command extends Tx_Extbase_MVC_Exception {
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/InvalidArgumentMixing.php b/typo3/sysext/extbase/Classes/MVC/Exception/InvalidArgumentMixing.php
new file mode 100644 (file)
index 0000000..2cda4c5
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3. 
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An "Invalid Argument Name" exception
+ *
+ * @package Extbase
+ * @subpackage MVC\Exception
+ * @version $Id$
+ */
+class Tx_Extbase_MVC_Exception_InvalidArgumentMixing extends Tx_Extbase_MVC_Exception {
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/InvalidCommandIdentifier.php b/typo3/sysext/extbase/Classes/MVC/Exception/InvalidCommandIdentifier.php
new file mode 100644 (file)
index 0000000..57b205e
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Extbase Team
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An "Invalid Command Identifier" exception
+ */
+class Tx_Extbase_MVC_Exception_InvalidCommandIdentifier extends Tx_Extbase_MVC_Exception {
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/NoSuchCommand.php b/typo3/sysext/extbase/Classes/MVC/Exception/NoSuchCommand.php
new file mode 100644 (file)
index 0000000..91e5c4f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * A "No Such Command" exception
+ */
+class Tx_Extbase_MVC_Exception_NoSuchCommand extends Tx_Extbase_MVC_Exception_Command {
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Classes/MVC/Exception/RequiredArgumentMissing.php b/typo3/sysext/extbase/Classes/MVC/Exception/RequiredArgumentMissing.php
new file mode 100644 (file)
index 0000000..60ef297
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * An "Required Argument Missing" exception
+ *
+ * @package Extbase
+ */
+class Tx_Extbase_MVC_Exception_RequiredArgumentMissing extends Tx_Extbase_MVC_Exception {
+
+}
+?>
\ No newline at end of file
index 4632283..6a9ed4c 100644 (file)
@@ -66,64 +66,6 @@ interface Tx_Extbase_MVC_RequestInterface {
        public function getControllerObjectName();
 
        /**
-        * Sets the extension name of the controller.
-        *
-        * @param string $extensionName The extension name.
-        * @return void
-        * @throws Tx_Extbase_MVC_Exception_InvalidPackageKey if the package key is not valid
-        * @api
-        */
-       public function setControllerExtensionName($extensionName);
-
-       /**
-        * Returns the extension name of the specified controller.
-        *
-        * @return string The package key
-        * @api
-        */
-       public function getControllerExtensionName();
-
-       /**
-        * Sets the name of the controller which is supposed to handle the request.
-        * Note: This is not the object name of the controller!
-        *
-        * @param string $controllerName Name of the controller
-        * @return void
-        * @api
-        */
-       public function setControllerName($controllerName);
-
-       /**
-        * Returns the object name of the controller supposed to handle this request, if one
-        * was set already (if not, the name of the default controller is returned)
-        *
-        * @return string Object name of the controller
-        * @api
-        */
-       public function getControllerName();
-
-       /**
-        * Sets the name of the action contained in this request.
-        *
-        * Note that the action name must start with a lower case letter.
-        *
-        * @param string $actionName: Name of the action to execute by the controller
-        * @return void
-        * @throws Tx_Extbase_MVC_Exception_InvalidActionName if the action name is not valid
-        * @api
-        */
-       public function setControllerActionName($actionName);
-
-       /**
-        * Returns the name of the action the controller is supposed to execute.
-        *
-        * @return string Action name
-        * @author Robert Lemke <robert@typo3.org>
-        * @api
-        */
-       public function getControllerActionName();
-
-       /**
         * Sets the value of the specified argument
         *
         * @param string $argumentName Name of the argument to set
@@ -170,39 +112,5 @@ interface Tx_Extbase_MVC_RequestInterface {
         */
        public function getArguments();
 
-       /**
-        * Sets the requested representation format
-        *
-        * @param string $format The desired format, something like "html", "xml", "png", "json" or the like.
-        * @return void
-        * @api
-        */
-       public function setFormat($format);
-
-       /**
-        * Returns the requested representation format
-        *
-        * @return string The desired format, something like "html", "xml", "png", "json" or the like.
-        * @api
-        */
-       public function getFormat();
-
-       /**
-        * Set the request errors that occured during the request
-        *
-        * @param array $errors An array of Tx_Extbase_Error_Error objects
-        * @return void
-        * @api
-        */
-       public function setErrors(array $errors);
-
-       /**
-        * Get the request errors that occured during the request
-        *
-        * @return array An array of Tx_Extbase_Error_Error objects
-        * @api
-        */
-       public function getErrors();
-
 }
 ?>
\ No newline at end of file
index d9cb9f5..38082fb 100644 (file)
@@ -143,10 +143,10 @@ class Tx_Extbase_MVC_Web_Routing_UriBuilder {
        /**
         * Sets the current request
         *
-        * @param Tx_Extbase_MVC_Web_Request $request
+        * @param Tx_Extbase_MVC_Request $request
         * @return Tx_Extbase_MVC_Web_Routing_UriBuilder the current UriBuilder to allow method chaining
         */
-       public function setRequest(Tx_Extbase_MVC_Web_Request $request) {
+       public function setRequest(Tx_Extbase_MVC_Request $request) {
                $this->request = $request;
                return $this;
        }
index fad3e67..b649081 100644 (file)
@@ -39,9 +39,8 @@ class Tx_Extbase_Reflection_MethodReflection extends ReflectionMethod {
        /**
         * The constructor, initializes the reflection class
         *
-        * @param  string $className Name of the method's class
-        * @param  string $methodName Name of the method to reflect
-        * @return void
+        * @param string $className Name of the method's class
+        * @param string $methodName Name of the method to reflect
         */
        public function __construct($className, $methodName) {
                parent::__construct($className, $methodName);
@@ -103,6 +102,15 @@ class Tx_Extbase_Reflection_MethodReflection extends ReflectionMethod {
        }
 
        /**
+        * Returns the description part of the doc comment
+        *
+        * @return string Doc comment description
+        */
+       public function getDescription() {
+               return $this->getDocCommentParser()->getDescription();
+       }
+
+       /**
         * Returns an instance of the doc comment parser and
         * runs the parse() method.
         *
diff --git a/typo3/sysext/extbase/Scripts/CommandLineLauncher.php b/typo3/sysext/extbase/Scripts/CommandLineLauncher.php
new file mode 100644 (file)
index 0000000..f87089c
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Dennis Ahrens <dennis.ahrens@fh-hannover.de>
+ * (c) 2011 Bastian Waidelich <bastian@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Launcher for the bootstrap when executing via cli.
+ *
+ * ONLY USED INTERNALLY, MIGHT CHANGE WITHOUT NOTICE!
+ */
+
+require_once(t3lib_extMgm::extPath('extbase', 'Classes/Core/Bootstrap.php'));
+
+$bootstrap = t3lib_div::makeInstance('Tx_Extbase_Core_Bootstrap');
+echo $bootstrap->run('', array());;
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandManagerTest.php b/typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandManagerTest.php
new file mode 100644 (file)
index 0000000..67f5be6
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+require_once(__DIR__ . '/../Fixture/CLI/Command/MockCommandController.php');
+
+/**
+ * Testcase for the CLI CommandManager class
+ */
+class Tx_Extbase_Tests_Unit_MVC_CLI_CommandManagerTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
+
+       /**
+        * @var array
+        */
+       protected $commandControllerBackup = array();
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $mockObjectManager;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_CommandManager
+        */
+       protected $commandManager;
+
+       public function setUp() {
+               $this->commandControllerBackup = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'];
+               $this->commandManager = $this->getMock('Tx_Extbase_MVC_CLI_CommandManager', array('getAvailableCommands'));
+               $this->mockObjectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
+               $this->commandManager->injectObjectManager($this->mockObjectManager);
+       }
+
+       public function tearDown() {
+               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'] = $this->commandControllerBackup;
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getAvailableCommandsReturnsAllAvailableCommands() {
+               $commandManager = new Tx_Extbase_MVC_CLI_CommandManager();
+               $commandManager->injectObjectManager($this->mockObjectManager);
+               $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'] = array(
+                       'Tx_Extbase_MVC_Fixture_CLI_Command_MockACommandController',
+                       'Tx_Extbase_MVC_Fixture_CLI_Command_MockBCommandController'
+               );
+               $mockCommand1 = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand2 = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand3 = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $this->mockObjectManager->expects($this->at(0))->method('get')->with('Tx_Extbase_MVC_CLI_Command', 'Tx_Extbase_MVC_Fixture_CLI_Command_MockACommandController', 'foo')->will($this->returnValue($mockCommand1));
+               $this->mockObjectManager->expects($this->at(1))->method('get')->with('Tx_Extbase_MVC_CLI_Command', 'Tx_Extbase_MVC_Fixture_CLI_Command_MockACommandController', 'bar')->will($this->returnValue($mockCommand2));
+               $this->mockObjectManager->expects($this->at(2))->method('get')->with('Tx_Extbase_MVC_CLI_Command', 'Tx_Extbase_MVC_Fixture_CLI_Command_MockBCommandController', 'baz')->will($this->returnValue($mockCommand3));
+
+               $commands = $commandManager->getAvailableCommands();
+               $this->assertEquals(3, count($commands));
+               $this->assertSame($mockCommand1, $commands[0]);
+               $this->assertSame($mockCommand2, $commands[1]);
+               $this->assertSame($mockCommand3, $commands[2]);
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getCommandByIdentifierReturnsCommandIfIdentifierIsEqual() {
+               $mockCommand = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extensionkey:controller:command'));
+               $mockCommands = array($mockCommand);
+               $this->commandManager->expects($this->once())->method('getAvailableCommands')->will($this->returnValue($mockCommands));
+
+               $this->assertSame($mockCommand, $this->commandManager->getCommandByIdentifier('extensionkey:controller:command'));
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getCommandByIdentifierWorksCaseInsensitive() {
+               $mockCommand = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extensionkey:controller:command'));
+               $mockCommands = array($mockCommand);
+               $this->commandManager->expects($this->once())->method('getAvailableCommands')->will($this->returnValue($mockCommands));
+
+               $this->assertSame($mockCommand, $this->commandManager->getCommandByIdentifier('   ExtensionKey:conTroLler:Command  '));
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_NoSuchCommand
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getCommandByIdentifierThrowsExceptionIfNoMatchingCommandWasFound() {
+               $mockCommand = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extensionkey:controller:command'));
+               $mockCommands = array($mockCommand);
+               $this->commandManager->expects($this->once())->method('getAvailableCommands')->will($this->returnValue($mockCommands));
+
+               $this->commandManager->getCommandByIdentifier('extensionkey:controller:someothercommand');
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_AmbiguousCommandIdentifier
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getCommandByIdentifierThrowsExceptionIfMoreThanOneMatchingCommandWasFound() {
+               $mockCommand1 = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand1->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('extensionkey:controller:command'));
+               $mockCommand2 = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $mockCommand2->expects($this->once())->method('getCommandIdentifier')->will($this->returnValue('otherextensionkey:controller:command'));
+               $mockCommands = array($mockCommand1, $mockCommand2);
+               $this->commandManager->expects($this->once())->method('getAvailableCommands')->will($this->returnValue($mockCommands));
+
+               $this->commandManager->getCommandByIdentifier('controller:command');
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandTest.php b/typo3/sysext/extbase/Tests/Unit/MVC/CLI/CommandTest.php
new file mode 100644 (file)
index 0000000..e6d8989
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the CLI Command class
+ */
+class Tx_Extbase_Tests_Unit_MVC_CLI_CommandTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Command
+        */
+       protected $command;
+
+       /**
+        * @var Tx_Extbase_Reflection_MethodReflection
+        */
+       protected $mockMethodReflection;
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $mockObjectManager;
+
+       /**
+        * @return void
+        */
+       public function setUp() {
+               $this->command = $this->getAccessibleMock('Tx_Extbase_MVC_CLI_Command', array('getCommandMethodReflection'), array(), '', FALSE);
+               $this->mockMethodReflection = $this->getMock('Tx_Extbase_Reflection_MethodReflection', array(), array(), '', FALSE);
+               $this->command->expects($this->any())->method('getCommandMethodReflection')->will($this->returnValue($this->mockMethodReflection));
+               $this->mockObjectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
+               $this->command->injectObjectManager($this->mockObjectManager);
+       }
+
+       /**
+        * @return array
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function commandIdentifiers() {
+               return array(
+                       array('Tx_ExtensionKey_Command_CacheCommandController', 'flush', 'extension_key:cache:flush'),
+                       array('Tx_Ext_Command_CookieCommandController', 'bake', 'ext:cookie:bake')
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider commandIdentifiers
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function constructRendersACommandIdentifierByTheGivenControllerAndCommandName($controllerClassName, $commandName, $expectedCommandIdentifier) {
+               $command = new Tx_Extbase_MVC_CLI_Command($controllerClassName, $commandName);
+               $this->assertEquals($expectedCommandIdentifier, $command->getCommandIdentifier());
+       }
+
+       /**
+        * @return array
+        */
+       public function invalidCommandClassNames() {
+               return array(
+                       array(''), // CommandClassName must not be empty
+                       array('Tx_OtherExtensionKey_Foo_Faa_Fuuum_Command_CoffeeCommandController'), // CommandControllers in subpackages are not supported
+                       array('Foo') // CommandClassName must start with "Tx_"
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider invalidCommandClassNames
+        * @expectedException InvalidArgumentException
+        */
+       public function constructThrowsExceptionIfCommandClassNameIsInvalid($controllerClassName) {
+               new Tx_Extbase_MVC_CLI_Command($controllerClassName, 'foo');
+       }
+
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function hasArgumentsReturnsFalseIfCommandExpectsNoArguments() {
+               $this->mockMethodReflection->expects($this->atLeastOnce())->method('getParameters')->will($this->returnValue(array()));
+               $this->assertFalse($this->command->hasArguments());
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function hasArgumentsReturnsTrueIfCommandExpectsArguments() {
+               $mockParameterReflection = $this->getMock('Tx_Extbase_Reflection_ParameterReflection', array(), array(), '', FALSE);
+               $this->mockMethodReflection->expects($this->atLeastOnce())->method('getParameters')->will($this->returnValue(array($mockParameterReflection)));
+               $this->assertTrue($this->command->hasArguments());
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getArgumentDefinitionsReturnsEmptyArrayIfCommandExpectsNoArguments() {
+               $this->mockMethodReflection->expects($this->atLeastOnce())->method('getParameters')->will($this->returnValue(array()));
+               $this->assertSame(array(), $this->command->getArgumentDefinitions());
+       }
+
+       /**
+        * @test
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function getArgumentDefinitionsReturnsArrayOfArgumentDefinitionIfCommandExpectsArguments() {
+               $mockParameterReflection = $this->getMock('Tx_Extbase_Reflection_ParameterReflection', array(), array(), '', FALSE);
+               $mockReflectionService = $this->getMock('Tx_Extbase_Reflection_Service');
+               $mockMethodParameters = array('argument1' => array('optional' => FALSE), 'argument2' => array('optional' => TRUE));
+               $mockReflectionService->expects($this->atLeastOnce())->method('getMethodParameters')->will($this->returnValue($mockMethodParameters));
+               $this->command->injectReflectionService($mockReflectionService);
+               $this->mockMethodReflection->expects($this->atLeastOnce())->method('getParameters')->will($this->returnValue(array($mockParameterReflection)));
+               $this->mockMethodReflection->expects($this->atLeastOnce())->method('getTagsValues')->will($this->returnValue(array('param' => array('@param $argument1 argument1 description', '@param $argument2 argument2 description'))));
+
+               $mockCommandArgumentDefinition1 = $this->getMock('Tx_Extbase_MVC_CLI_CommandArgumentDefinition', array(), array(), '', FALSE);
+               $mockCommandArgumentDefinition2 = $this->getMock('Tx_Extbase_MVC_CLI_CommandArgumentDefinition', array(), array(), '', FALSE);
+               $this->mockObjectManager->expects($this->at(0))->method('get')->with('Tx_Extbase_MVC_CLI_CommandArgumentDefinition', 'argument1', TRUE, 'argument1 description')->will($this->returnValue($mockCommandArgumentDefinition1));
+               $this->mockObjectManager->expects($this->at(1))->method('get')->with('Tx_Extbase_MVC_CLI_CommandArgumentDefinition', 'argument2', FALSE, 'argument2 description')->will($this->returnValue($mockCommandArgumentDefinition2));
+
+               $expectedResult = array($mockCommandArgumentDefinition1, $mockCommandArgumentDefinition2);
+               $actualResult = $this->command->getArgumentDefinitions();
+               $this->assertSame($expectedResult, $actualResult);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestBuilderTest.php b/typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestBuilderTest.php
new file mode 100644 (file)
index 0000000..48d71ea
--- /dev/null
@@ -0,0 +1,363 @@
+<?php
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the MVC CLI Request Builder
+ */
+class Tx_Extbase_Tests_Unit_MVC_CLI_RequestBuilderTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_RequestBuilder
+        */
+       protected $requestBuilder;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Request
+        */
+       protected $request;
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $mockObjectManager;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Command
+        */
+       protected $mockCommand;
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_CommandManager
+        */
+       protected $mockCommandManager;
+
+       /**
+        * @var Tx_Extbase_Reflection_Service
+        */
+       protected $mockReflectionService;
+
+       /**
+        * Sets up this test case
+        *
+        * @author  Robert Lemke <robert@typo3.org>
+        */
+       public function setUp() {
+               $this->request = $this->getAccessibleMock('Tx_Extbase_MVC_CLI_Request', array('dummy'));
+
+               $this->mockObjectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
+               $this->mockObjectManager->expects($this->any())->method('get')->with('Tx_Extbase_MVC_CLI_Request')->will($this->returnValue($this->request));
+
+               $this->mockCommand = $this->getMock('Tx_Extbase_MVC_CLI_Command', array(), array(), '', FALSE);
+               $this->mockCommand->expects($this->any())->method('getControllerClassName')->will($this->returnValue('Tx_SomeExtensionName_Command_DefaultCommandController'));
+               $this->mockCommand->expects($this->any())->method('getControllerCommandName')->will($this->returnValue('list'));
+
+               $this->mockCommandManager = $this->getMock('Tx_Extbase_MVC_CLI_CommandManager');
+               $this->mockCommandManager->expects($this->any())->method('getCommandByIdentifier')->with('some_extension_name:default:list')->will($this->returnValue($this->mockCommand));
+
+               $this->mockReflectionService = $this->getMock('Tx_Extbase_Reflection_Service');
+
+               $this->requestBuilder = new Tx_Extbase_MVC_CLI_RequestBuilder();
+               $this->requestBuilder->injectObjectManager($this->mockObjectManager);
+               $this->requestBuilder->injectReflectionService($this->mockReflectionService);
+               $this->requestBuilder->injectCommandManager($this->mockCommandManager);
+       }
+
+       /**
+        * Checks if a CLI request specifying a package, controller and action name results in the expected request object
+        *
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function cliAccessWithExtensionControllerAndActionNameBuildsCorrectRequest() {
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->will($this->returnValue(array()));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list');
+               $this->assertEquals('Tx_SomeExtensionName_Command_DefaultCommandController', $request->getControllerObjectName());
+               $this->assertEquals('list', $request->getControllerCommandName(), 'The CLI request specifying a package, controller and action name did not return a request object pointing to the expected action.');
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        * @author Bastian Waidelich <bastian@typo3.org>
+        */
+       public function ifCommandCantBeResolvedTheHelpScreenIsShown() {
+                       // The following call is only made to satisfy PHPUnit. For some weird reason PHPUnit complains that the
+                       // mocked method ("getObjectNameByClassName") does not exist _if the mock object is not used_.
+               $this->mockCommandManager->getCommandByIdentifier('some_extension_name:default:list');
+               $mockCommandManager = $this->getMock('Tx_Extbase_MVC_CLI_CommandManager');
+               $mockCommandManager->expects($this->any())->method('getCommandByIdentifier')->with('test:default:list')->will($this->throwException(new Tx_Extbase_MVC_Exception_NoSuchCommand()));
+               $this->requestBuilder->injectCommandManager($mockCommandManager);
+
+               $request = $this->requestBuilder->build('test:default:list');
+               $this->assertEquals('Tx_Extbase_Command_HelpCommandController', $request->getControllerObjectName());
+       }
+
+       /**
+        * Checks if a CLI request specifying some "console style" (--my-argument=value) arguments results in the expected request object
+        *
+        * @test
+        * @author Andreas Förthner <andreas.foerthner@netlogix.de>
+        */
+       public function cliAccessWithExtensionControllerActionAndArgumentsBuildsCorrectRequest() {
+               $methodParameters = array(
+                       'testArgument' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string')
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --test-argument=value --test-argument2=value2');
+               $this->assertTrue($request->hasArgument('testArgument'), 'The given "testArgument" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument2'), 'The given "testArgument2" was not found in the built request.');
+               $this->assertEquals($request->getArgument('testArgument'), 'value', 'The "testArgument" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument2'), 'value2', 'The "testArgument2" had not the given value.');
+       }
+
+       /**
+        * Checks if a CLI request specifying some "console style" (--my-argument =value) arguments with spaces between name and value results in the expected request object
+        *
+        * @test
+        * @author Andreas Förthner <andreas.foerthner@netlogix.de>
+        */
+       public function checkIfCLIAccesWithPackageControllerActionAndArgumentsToleratesSpaces() {
+               $methodParameters = array(
+                       'testArgument' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument3' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument4' => array('optional' => FALSE, 'type' => 'string')
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --test-argument= value --test-argument2 =value2 --test-argument3 = value3 --test-argument4=value4');
+               $this->assertTrue($request->hasArgument('testArgument'), 'The given "testArgument" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument2'), 'The given "testArgument2" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument3'), 'The given "testArgument3" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument4'), 'The given "testArgument4" was not found in the built request.');
+               $this->assertEquals($request->getArgument('testArgument'), 'value', 'The "testArgument" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument2'), 'value2', 'The "testArgument2" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument3'), 'value3', 'The "testArgument3" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument4'), 'value4', 'The "testArgument4" had not the given value.');
+       }
+
+       /**
+        * Checks if a CLI request specifying some short "console style" (-c value or -c=value or -c = value) arguments results in the expected request object
+        *
+        * @test
+        * @author Andreas Förthner <andreas.foerthner@netlogix.de>
+        */
+       public function CLIAccesWithShortArgumentsBuildsCorrectRequest() {
+               $methodParameters = array(
+                       'a' => array('optional' => FALSE, 'type' => 'string'),
+                       'd' => array('optional' => FALSE, 'type' => 'string'),
+                       'f' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list -d valued -f=valuef -a = valuea');
+               $this->assertTrue($request->hasArgument('d'), 'The given "d" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('f'), 'The given "f" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('a'), 'The given "a" was not found in the built request.');
+               $this->assertEquals($request->getArgument('d'), 'valued', 'The "d" had not the given value.');
+               $this->assertEquals($request->getArgument('f'), 'valuef', 'The "f" had not the given value.');
+               $this->assertEquals($request->getArgument('a'), 'valuea', 'The "a" had not the given value.');
+       }
+
+       /**
+        * Checks if a CLI request specifying some mixed "console style" (-c or --my-argument -f=value) arguments with and
+        * without values results in the expected request object
+        *
+        * @test
+        * @author Andreas Förthner <andreas.foerthner@netlogix.de>
+        */
+       public function CLIAccesWithArgumentsWithAndWithoutValuesBuildsCorrectRequest() {
+               $methodParameters = array(
+                       'testArgument' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument3' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument4' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument5' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument6' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument7' => array('optional' => FALSE, 'type' => 'string'),
+                       'f' => array('optional' => FALSE, 'type' => 'string'),
+                       'd' => array('optional' => FALSE, 'type' => 'string'),
+                       'a' => array('optional' => FALSE, 'type' => 'string'),
+                       'c' => array('optional' => FALSE, 'type' => 'string'),
+                       'j' => array('optional' => FALSE, 'type' => 'string'),
+                       'k' => array('optional' => FALSE, 'type' => 'string'),
+                       'm' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --test-argument=value --test-argument2= value2 -k --test-argument-3 = value3 --test-argument4=value4 -f valuef -d=valued -a = valuea -c --testArgument7 --test-argument5 = 5 --test-argument6 -j kjk -m');
+               $this->assertTrue($request->hasArgument('testArgument'), 'The given "testArgument" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument2'), 'The given "testArgument2" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('k'), 'The given "k" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument3'), 'The given "testArgument3" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument4'), 'The given "testArgument4" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('f'), 'The given "f" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('d'), 'The given "d" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('a'), 'The given "a" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('c'), 'The given "d" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument7'), 'The given "testArgument7" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument5'), 'The given "testArgument5" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('testArgument6'), 'The given "testArgument6" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('j'), 'The given "j" was not found in the built request.');
+               $this->assertTrue($request->hasArgument('m'), 'The given "m" was not found in the built request.');
+               $this->assertEquals($request->getArgument('testArgument'), 'value', 'The "testArgument" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument2'), 'value2', 'The "testArgument2" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument3'), 'value3', 'The "testArgument3" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument4'), 'value4', 'The "testArgument4" had not the given value.');
+               $this->assertEquals($request->getArgument('f'), 'valuef', 'The "f" had not the given value.');
+               $this->assertEquals($request->getArgument('d'), 'valued', 'The "d" had not the given value.');
+               $this->assertEquals($request->getArgument('a'), 'valuea', 'The "a" had not the given value.');
+               $this->assertEquals($request->getArgument('testArgument5'), '5', 'The "testArgument4" had not the given value.');
+               $this->assertEquals($request->getArgument('j'), 'kjk', 'The "j" had not the given value.');
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function insteadOfNamedArgumentsTheArgumentsCanBePassedUnnamedInTheCorrectOrder() {
+               $methodParameters = array(
+                       'testArgument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->exactly(2))->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --test-argument1 firstArgumentValue --test-argument2 secondArgumentValue');
+               $this->assertEquals('firstArgumentValue', $request->getArgument('testArgument1'));
+               $this->assertEquals('secondArgumentValue', $request->getArgument('testArgument2'));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list firstArgumentValue secondArgumentValue');
+               $this->assertEquals('firstArgumentValue', $request->getArgument('testArgument1'));
+               $this->assertEquals('secondArgumentValue', $request->getArgument('testArgument2'));
+       }
+
+       /**
+        * @test
+        * @author Karsten Dambekalns <karsten@typo3.org>
+        */
+       public function argumentsAreDetectedAfterOptions() {
+               $methodParameters = array(
+                       'some' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'option' => array('optional' => TRUE, 'type' => 'string'),
+                       'argument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'argument2' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --some -option=value file1 file2');
+               $this->assertEquals('list', $request->getControllerCommandName());
+               $this->assertTrue($request->getArgument('some'));
+               $this->assertEquals('file1', $request->getArgument('argument1'));
+               $this->assertEquals('file2', $request->getArgument('argument2'));
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function exceedingArgumentsMayBeSpecified() {
+               $methodParameters = array(
+                       'testArgument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $expectedArguments = array('testArgument1' => 'firstArgumentValue', 'testArgument2' => 'secondArgumentValue');
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --test-argument1=firstArgumentValue --test-argument2 secondArgumentValue exceedingArgument1');
+               $this->assertEquals($expectedArguments, $request->getArguments());
+               $this->assertEquals(array('exceedingArgument1'), $request->getExceedingArguments());
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_InvalidArgumentMixing
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function ifNamedArgumentsAreUsedAllRequiredArgumentsMustBeNamed() {
+               $methodParameters = array(
+                       'testArgument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'testArgument2' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $this->requestBuilder->build('some_extension_name:default:list --test-argument1 firstArgumentValue secondArgumentValue');
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_InvalidArgumentMixing
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function ifUnnamedArgumentsAreUsedAllRequiredArgumentsMustBeUnnamed() {
+               $methodParameters = array(
+                       'requiredArgument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'requiredArgument2' => array('optional' => FALSE, 'type' => 'string'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $this->requestBuilder->build('some_extension_name:default:list firstArgumentValue --required-argument2 secondArgumentValue');
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function booleanOptionsAreConsideredEvenIfAnUnnamedArgumentFollows() {
+               $methodParameters = array(
+                       'requiredArgument1' => array('optional' => FALSE, 'type' => 'string'),
+                       'requiredArgument2' => array('optional' => FALSE, 'type' => 'string'),
+                       'booleanOption' => array('optional' => TRUE, 'type' => 'boolean'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $expectedArguments = array('requiredArgument1' => 'firstArgumentValue', 'requiredArgument2' => 'secondArgumentValue', 'booleanOption' => TRUE);
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --booleanOption firstArgumentValue secondArgumentValue');
+               $this->assertEquals($expectedArguments, $request->getArguments());
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function booleanOptionsCanHaveOnlyCertainValuesIfTheValueIsAssignedWithoutEqualSign() {
+               $methodParameters = array(
+                       'b1' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'b2' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'b3' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'b4' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'b5' => array('optional' => TRUE, 'type' => 'boolean'),
+                       'b6' => array('optional' => TRUE, 'type' => 'boolean'),
+               );
+               $this->mockReflectionService->expects($this->once())->method('getMethodParameters')->with('Tx_SomeExtensionName_Command_DefaultCommandController', 'listCommand')->will($this->returnValue($methodParameters));
+
+               $expectedArguments = array('b1' => TRUE, 'b2' => TRUE, 'b3' => TRUE, 'b4' => FALSE, 'b5' => FALSE, 'b6' => FALSE);
+
+               $request = $this->requestBuilder->build('some_extension_name:default:list --b2 y --b1 1 --b3 true --b4 false --b5 n --b6 0');
+               $this->assertEquals($expectedArguments, $request->getArguments());
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestTest.php b/typo3/sysext/extbase/Tests/Unit/MVC/CLI/RequestTest.php
new file mode 100644 (file)
index 0000000..53f818c
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * Testcase for the CLI Request class
+ */
+class Tx_Extbase_Tests_Unit_MVC_CLI_RequestTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
+
+       /**
+        * @var Tx_Extbase_MVC_CLI_Request
+        */
+       protected $request;
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $mockObjectManager;
+
+       /**
+        * Sets up this test case
+        */
+       public function setUp() {
+               $this->request = new Tx_Extbase_MVC_CLI_Request();
+
+               $this->mockObjectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
+               $this->request->injectObjectManager($this->mockObjectManager);
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function getCommandReturnsTheCommandObjectReflectingTheRequestInformation() {
+               $this->request->setControllerObjectName('Tx_Extbase_Command_CacheCommandController');
+               $this->request->setControllerCommandName('flush');
+
+               $this->mockObjectManager->expects($this->once())->method('get')->with('Tx_Extbase_MVC_CLI_Command', 'Tx_Extbase_Command_CacheCommandController', 'flush');
+               $this->request->getCommand();
+       }
+
+       /**
+        * @test
+        * @author Robert Lemke <robert@typo3.org>
+        */
+       public function setControllerObjectNameAndSetControllerCommandNameUnsetTheBuiltCommandObject() {
+               $this->request->setControllerObjectName('Tx_Extbase_Command_CacheCommandController');
+               $this->request->setControllerCommandName('flush');
+               $this->request->getCommand();
+
+               $this->request->setControllerObjectName('Tx_SomeExtension_Command_BeerCommandController');
+               $this->request->setControllerCommandName('drink');
+
+               $this->mockObjectManager->expects($this->once())->method('get')->with('Tx_Extbase_MVC_CLI_Command', 'Tx_SomeExtension_Command_BeerCommandController', 'drink');
+               $this->request->getCommand();
+       }
+}
+?>
\ No newline at end of file
index 99b07dd..cc63c19 100644 (file)
@@ -98,7 +98,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function callActionMethodAppendsStringsReturnedByActionMethodToTheResponseObject() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockResponse = $this->getMock('Tx_Extbase_MVC_ResponseInterface', array(), array(), '', FALSE);
                $mockResponse->expects($this->once())->method('appendContent')->with('the returned string');
@@ -124,7 +124,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function callActionMethodRendersTheViewAutomaticallyIfTheActionReturnedNullAndAViewExists() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockResponse = $this->getMock('Tx_Extbase_MVC_ResponseInterface', array(), array(), '', FALSE);
                $mockResponse->expects($this->once())->method('appendContent')->with('the view output');
@@ -154,7 +154,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function callActionMethodCallsTheErrorActionIfTheMappingResultsHaveErrors() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockResponse = $this->getMock('Tx_Extbase_MVC_ResponseInterface', array(), array(), '', FALSE);
                $mockResponse->expects($this->once())->method('appendContent')->with('the returned string');
@@ -181,7 +181,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Sebastian Kurfürst <sebastian@typo3.org>
         */
        public function callActionMethodPassesDefaultValuesAsArguments() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockResponse = $this->getMock('Tx_Extbase_MVC_ResponseInterface', array(), array(), '', FALSE);
 
@@ -233,7 +233,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Bastian Waidelich <bastian@typo3.org>
         */
        public function resolveViewObjectNameUsesViewObjectNamePatternToResolveViewObjectName() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
                $mockRequest->expects($this->once())->method('getControllerExtensionName')->will($this->returnValue('MyPackage'));
                $mockRequest->expects($this->once())->method('getControllerName')->will($this->returnValue('MyController'));
                $mockRequest->expects($this->once())->method('getControllerActionName')->will($this->returnValue('MyAction'));
@@ -254,7 +254,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function resolveActionMethodNameReturnsTheCurrentActionMethodNameFromTheRequest() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
                $mockRequest->expects($this->once())->method('getControllerActionName')->will($this->returnValue('fooBar'));
 
                $mockController = $this->getAccessibleMock('Tx_Extbase_MVC_Controller_ActionController', array('fooBarAction'), array(), '', FALSE);
@@ -269,7 +269,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function resolveActionMethodNameThrowsAnExceptionIfTheActionDefinedInTheRequestDoesNotExist() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
                $mockRequest->expects($this->once())->method('getControllerActionName')->will($this->returnValue('fooBar'));
 
                $mockController = $this->getAccessibleMock('Tx_Extbase_MVC_Controller_ActionController', array('otherBarAction'), array(), '', FALSE);
@@ -283,7 +283,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function initializeActionMethodArgumentsRegistersArgumentsFoundInTheSignatureOfTheCurrentActionMethod() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockArguments = $this->getMock('Tx_Extbase_MVC_Controller_Arguments', array('addNewArgument', 'removeAll'), array(), '', FALSE);
                $mockArguments->expects($this->at(0))->method('addNewArgument')->with('stringArgument', 'string', TRUE);
@@ -334,7 +334,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @author Robert Lemke <robert@typo3.org>
         */
        public function initializeActionMethodArgumentsRegistersOptionalArgumentsAsSuch() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockArguments = $this->getMock('Tx_Extbase_MVC_Controller_Arguments', array(), array(), '', FALSE);
                $mockArguments->expects($this->at(0))->method('addNewArgument')->with('arg1', 'string', TRUE);
@@ -387,7 +387,7 @@ class Tx_Extbase_Tests_Unit_MVC_Controller_ActionControllerTest extends Tx_Extba
         * @expectedException Tx_Extbase_MVC_Exception_InvalidArgumentType
         */
        public function initializeActionMethodArgumentsThrowsExceptionIfDataTypeWasNotSpecified() {
-               $mockRequest = $this->getMock('Tx_Extbase_MVC_RequestInterface', array(), array(), '', FALSE);
+               $mockRequest = $this->getMock('Tx_Extbase_MVC_Request', array(), array(), '', FALSE);
 
                $mockArguments = $this->getMock('Tx_Extbase_MVC_Controller_Arguments', array(), array(), '', FALSE);
 
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/Controller/CommandControllerTest.php b/typo3/sysext/extbase/Tests/Unit/MVC/Controller/CommandControllerTest.php
new file mode 100644 (file)
index 0000000..6dbbea7
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  All rights reserved
+*
+*  This class is a backport of the corresponding class of FLOW3.
+*  All credits go to the v5 team.
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Testcase for the Command Controller
+ */
+class Tx_Extbase_Tests_Unit_MVC_Controller_CommandControllerTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
+
+       /**
+        * @var Tx_Extbase_MVC_Controller_CommandController
+        */
+       protected $commandController;
+
+       public function setUp() {
+               $this->commandController = $this->getAccessibleMock('Tx_Extbase_MVC_Controller_CommandController', array('dummy'));
+       }
+
+       /**
+        * @test
+        */
+       public function outputAppendsGivenStringToTheResponseContent() {
+               $mockResponse = $this->getMock('Tx_Extbase_MVC_CLI_Response');
+               $mockResponse->expects($this->once())->method('appendContent')->with('some text');
+               $this->commandController->_set('response', $mockResponse);
+               $this->commandController->_call('output', 'some text');
+       }
+
+       /**
+        * @test
+        */
+       public function outputReplacesArgumentsInGivenString() {
+               $mockResponse = $this->getMock('Tx_Extbase_MVC_CLI_Response');
+               $mockResponse->expects($this->once())->method('appendContent')->with('some text');
+               $this->commandController->_set('response', $mockResponse);
+               $this->commandController->_call('output', '%2$s %1$s', array('text', 'some'));
+       }
+
+       /**
+        * @test
+        */
+       public function outputLineAppendsGivenStringAndNewlineToTheResponseContent() {
+               $mockResponse = $this->getMock('Tx_Extbase_MVC_CLI_Response');
+               $mockResponse->expects($this->once())->method('appendContent')->with('some text' . PHP_EOL);
+               $this->commandController->_set('response', $mockResponse);
+               $this->commandController->_call('outputLine', 'some text');
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_StopAction
+        */
+       public function quitThrowsStopActionException() {
+               $mockResponse = $this->getMock('Tx_Extbase_MVC_CLI_Response');
+               $this->commandController->_set('response', $mockResponse);
+               $this->commandController->_call('quit');
+       }
+
+       /**
+        * @test
+        * @expectedException Tx_Extbase_MVC_Exception_StopAction
+        */
+       public function quitSetsResponseExitCode() {
+               $mockResponse = $this->getMock('Tx_Extbase_MVC_CLI_Response');
+               $mockResponse->expects($this->once())->method('setExitCode')->with(123);
+               $this->commandController->_set('response', $mockResponse);
+               $this->commandController->_call('quit', 123);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extbase/Tests/Unit/MVC/Fixture/CLI/Command/MockCommandController.php b/typo3/sysext/extbase/Tests/Unit/MVC/Fixture/CLI/Command/MockCommandController.php
new file mode 100644 (file)
index 0000000..b653f49
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/*                                                                        *
+ * This script belongs to the Extbase framework.                            *
+ *                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License, or (at your *
+ * option) any later version.                                             *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+
+/**
+ * A mock CLI Command
+ */
+class Tx_Extbase_MVC_Fixture_CLI_Command_MockACommandController extends Tx_Extbase_MVC_CLI_Command {
+
+       public function fooCommand() {
+       }
+
+       public function barCommand($someArgument) {
+       }
+}
+
+/**
+ * Another mock CLI Command
+ */
+class Tx_Extbase_MVC_Fixture_CLI_Command_MockBCommandController extends Tx_Extbase_MVC_CLI_Command {
+
+       public function bazCommand() {
+       }
+}
+?>
\ No newline at end of file
index ce2303d..20e961b 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-if (!defined ('TYPO3_MODE'))   die ('Access denied.');
+if (!defined ('TYPO3_MODE')) die ('Access denied.');
 
 require_once(t3lib_extMgm::extPath('extbase') . 'Classes/Dispatcher.php');
 require_once(t3lib_extMgm::extPath('extbase') . 'Classes/Utility/Extension.php');
@@ -34,4 +34,14 @@ Tx_Extbase_Utility_Extension::registerTypeConverter('Tx_Extbase_Property_TypeCon
 Tx_Extbase_Utility_Extension::registerTypeConverter('Tx_Extbase_Property_TypeConverter_PersistentObjectConverter');
 Tx_Extbase_Utility_Extension::registerTypeConverter('Tx_Extbase_Property_TypeConverter_StringConverter');
 # $GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:extbase/Classes/Persistence/Hook/TCEMainValueObjectUpdater.php:tx_Extbase_Persistence_Hook_TCEMainValueObjectUpdater';
+
+if (TYPO3_MODE === 'BE') {
+       // registers Extbase at the cli_dispatcher with key "extbase".
+       $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys']['extbase'] = array(
+               'EXT:extbase/Scripts/CommandLineLauncher.php',
+               '_CLI_lowlevel'
+       );
+       // register help command
+       $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'Tx_Extbase_Command_HelpCommandController';
+}
 ?>
\ No newline at end of file
index 07e877d..f9c12aa 100644 (file)
@@ -2,6 +2,7 @@
 if (!defined ('TYPO3_MODE')) die ('Access denied.');
 
 if (TYPO3_MODE == 'BE') {
+       // register Extbase dispatcher for modules
        $TBE_MODULES['_dispatcher'][] = 'Tx_Extbase_Core_Bootstrap';
 }
 
index aed7e6e..161b61b 100644 (file)
@@ -11,6 +11,7 @@ config.tx_extbase {
                requestHandlers {
                        Tx_Extbase_MVC_Web_FrontendRequestHandler = Tx_Extbase_MVC_Web_FrontendRequestHandler
                        Tx_Extbase_MVC_Web_BackendRequestHandler = Tx_Extbase_MVC_Web_BackendRequestHandler
+                       Tx_Extbase_MVC_CLI_RequestHandler = Tx_Extbase_MVC_CLI_RequestHandler
                }
                throwPageNotFoundExceptionIfActionCantBeResolved = 0
        }