2 /***************************************************************
6 * This class is a backport of the corresponding class of FLOW3.
7 * All credits go to the v5 team.
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
18 * This script is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
27 * Builds a CLI request object from the raw command call
29 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
31 class Tx_Extbase_MVC_CLI_RequestBuilder
{
34 * @var Tx_Extbase_Object_ObjectManagerInterface
36 protected $objectManager;
39 * @var Tx_Extbase_Reflection_Service
41 protected $reflectionService;
44 * @var Tx_Extbase_MVC_CLI_CommandManager
46 protected $commandManager;
49 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
52 public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface
$objectManager) {
53 $this->objectManager
= $objectManager;
57 * @param Tx_Extbase_Reflection_Service $reflectionService
60 public function injectReflectionService(Tx_Extbase_Reflection_Service
$reflectionService) {
61 $this->reflectionService
= $reflectionService;
65 * @param Tx_Extbase_MVC_CLI_CommandManager $commandManager
68 public function injectCommandManager(Tx_Extbase_MVC_CLI_CommandManager
$commandManager) {
69 $this->commandManager
= $commandManager;
73 * Builds a CLI request object from a command line.
75 * The given command line may be a string (e.g. "myextension:foo do-that-thing --force") or
76 * an array consisting of the individual parts. The array must not include the script
77 * name (like in $argv) but start with command right away.
79 * @param mixed $commandLine The command line, either as a string or as an array
80 * @return Tx_Extbase_MVC_CLI_Request The CLI request as an object
81 * @author Robert Lemke <robert@typo3.org>
83 public function build($commandLine = '') {
84 $request = $this->objectManager
->get('Tx_Extbase_MVC_CLI_Request');
85 $request->setControllerObjectName('Tx_Extbase_Command_HelpCommandController');
87 $rawCommandLineArguments = is_array($commandLine) ?
$commandLine : explode(' ', $commandLine);
88 if (count($rawCommandLineArguments) === 0) {
89 $request->setControllerCommandName('helpStub');
92 $commandIdentifier = trim(array_shift($rawCommandLineArguments));
94 $command = $this->commandManager
->getCommandByIdentifier($commandIdentifier);
95 } catch (Tx_Extbase_MVC_Exception_Command
$exception) {
96 $request->setArgument('exception', $exception);
97 $request->setControllerCommandName('error');
100 $controllerObjectName = $command->getControllerClassName();
101 $controllerCommandName = $command->getControllerCommandName();
102 $request->setControllerObjectName($controllerObjectName);
103 $request->setControllerCommandName($controllerCommandName);
105 list($commandLineArguments, $exceedingCommandLineArguments) = $this->parseRawCommandLineArguments($rawCommandLineArguments, $controllerObjectName, $controllerCommandName);
106 $request->setArguments($commandLineArguments);
107 $request->setExceedingArguments($exceedingCommandLineArguments);
113 * Takes an array of unparsed command line arguments and options and converts it separated
114 * by named arguments, options and unnamed arguments.
116 * @param array $rawCommandLineArguments The unparsed command parts (such as "--foo") as an array
117 * @param string $controllerObjectName Object name of the designated command controller
118 * @param string $controllerCommandName Command name of the recognized command (ie. method name without "Command" suffix)
119 * @return array All and exceeding command line arguments
120 * @author Robert Lemke <robert@typo3.org>
122 protected function parseRawCommandLineArguments(array $rawCommandLineArguments, $controllerObjectName, $controllerCommandName) {
123 $commandLineArguments = array();
124 $exceedingArguments = array();
125 $commandMethodName = $controllerCommandName . 'Command';
126 $commandMethodParameters = $this->reflectionService
->getMethodParameters($controllerObjectName, $commandMethodName);
128 $requiredArguments = array();
129 $optionalArguments = array();
130 $argumentNames = array();
131 foreach ($commandMethodParameters as $parameterName => $parameterInfo) {
132 $argumentNames[] = $parameterName;
133 if ($parameterInfo['optional'] === FALSE) {
134 $requiredArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
136 $optionalArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
140 $decidedToUseNamedArguments = FALSE;
141 $decidedToUseUnnamedArguments = FALSE;
143 while (count($rawCommandLineArguments) > 0) {
145 $rawArgument = array_shift($rawCommandLineArguments);
147 if ($rawArgument[0] === '-') {
148 if ($rawArgument[1] === '-') {
149 $rawArgument = substr($rawArgument, 2);
151 $rawArgument = substr($rawArgument, 1);
153 $argumentName = $this->extractArgumentNameFromCommandLinePart($rawArgument);
155 if (isset($optionalArguments[$argumentName])) {
156 $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $optionalArguments[$argumentName]['type']);
157 $commandLineArguments[$optionalArguments[$argumentName]['parameterName']] = $argumentValue;
158 } elseif(isset($requiredArguments[$argumentName])) {
159 if ($decidedToUseUnnamedArguments) {
160 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);
162 $decidedToUseNamedArguments = TRUE;
163 $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $requiredArguments[$argumentName]['type']);
164 $commandLineArguments[$requiredArguments[$argumentName]['parameterName']] = $argumentValue;
165 unset($requiredArguments[$argumentName]);
168 if (count($requiredArguments) > 0) {
169 if ($decidedToUseNamedArguments) {
170 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);
172 $argument = array_shift($requiredArguments);
173 $commandLineArguments[$argument['parameterName']] = $rawArgument;
174 $decidedToUseUnnamedArguments = TRUE;
176 if ($argumentIndex < count($argumentNames)) {
177 $commandLineArguments[$argumentNames[$argumentIndex]] = $rawArgument;
179 $exceedingArguments[] = $rawArgument;
186 return array($commandLineArguments, $exceedingArguments);
190 * Extracts the option or argument name from the name / value pair of a command line.
192 * @param string $commandLinePart Part of the command line, e.g. "my-important-option=SomeInterestingValue"
193 * @return string The lowercased argument name, e.g. "myimportantoption"
195 protected function extractArgumentNameFromCommandLinePart($commandLinePart) {
196 $nameAndValue = explode('=', $commandLinePart, 2);
197 return strtolower(str_replace('-', '', $nameAndValue[0]));
201 * Returns the value of the first argument of the given input array. Shifts the parsed argument off the array.
203 * @param string $currentArgument The current argument
204 * @param array &$rawCommandLineArguments Array of the remaining command line arguments
205 * @param string $expectedArgumentType The expected type of the current argument, because booleans get special attention
206 * @return string The value of the first argument
207 * @author Andreas Förthner <andreas.foerthner@netlogix.de>
208 * @author Robert Lemke <robert@typo3.org>
210 protected function getValueOfCurrentCommandLineOption($currentArgument, array &$rawCommandLineArguments, $expectedArgumentType) {
211 if (!isset($rawCommandLineArguments[0]) ||
(isset($rawCommandLineArguments[0]) && $rawCommandLineArguments[0][0] === '-' && (strpos($currentArgument, '=') === FALSE))) {
215 if (strpos($currentArgument, '=') === FALSE) {
216 $possibleValue = trim(array_shift($rawCommandLineArguments));
217 if (strpos($possibleValue, '=') === FALSE) {
218 if ($expectedArgumentType !== 'boolean') {
219 return $possibleValue;
221 if (array_search($possibleValue, array('on', '1', 'y', 'yes', 'true', 'TRUE')) !== FALSE) {
224 if (array_search($possibleValue, array('off', '0', 'n', 'no', 'false', 'FALSE')) !== FALSE) {
227 array_unshift($rawCommandLineArguments, $possibleValue);
230 $currentArgument .= $possibleValue;
233 $splitArgument = explode('=', $currentArgument, 2);
234 while ((!isset($splitArgument[1]) ||
trim($splitArgument[1]) === '') && count($rawCommandLineArguments) > 0) {
235 $currentArgument .= array_shift($rawCommandLineArguments);
236 $splitArgument = explode('=', $currentArgument);
239 $value = (isset($splitArgument[1])) ?
$splitArgument[1] : '';