7306b5d940006669490c23b4aebf046646f7dae2
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Cli / RequestBuilder.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 * All rights reserved
5 *
6 * This class is a backport of the corresponding class of FLOW3.
7 * All credits go to the v5 team.
8 *
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.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 *
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.
22 *
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
25 /**
26 * Builds a CLI request object from the raw command call
27 *
28 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
29 */
30 class Tx_Extbase_MVC_CLI_RequestBuilder {
31
32 /**
33 * @var Tx_Extbase_Object_ObjectManagerInterface
34 */
35 protected $objectManager;
36
37 /**
38 * @var Tx_Extbase_Reflection_Service
39 */
40 protected $reflectionService;
41
42 /**
43 * @var Tx_Extbase_MVC_CLI_CommandManager
44 */
45 protected $commandManager;
46
47 /**
48 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
49 * @return void
50 */
51 public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
52 $this->objectManager = $objectManager;
53 }
54
55 /**
56 * @param Tx_Extbase_Reflection_Service $reflectionService
57 * @return void
58 */
59 public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
60 $this->reflectionService = $reflectionService;
61 }
62
63 /**
64 * @param Tx_Extbase_MVC_CLI_CommandManager $commandManager
65 * @return void
66 */
67 public function injectCommandManager(Tx_Extbase_MVC_CLI_CommandManager $commandManager) {
68 $this->commandManager = $commandManager;
69 }
70
71 /**
72 * Builds a CLI request object from a command line.
73 *
74 * The given command line may be a string (e.g. "myextension:foo do-that-thing --force") or
75 * an array consisting of the individual parts. The array must not include the script
76 * name (like in $argv) but start with command right away.
77 *
78 * @param mixed $commandLine The command line, either as a string or as an array
79 * @return Tx_Extbase_MVC_CLI_Request The CLI request as an object
80 * @author Robert Lemke <robert@typo3.org>
81 */
82 public function build($commandLine = '') {
83 $request = $this->objectManager->get('Tx_Extbase_MVC_CLI_Request');
84 $request->setControllerObjectName('Tx_Extbase_Command_HelpCommandController');
85 $rawCommandLineArguments = is_array($commandLine) ? $commandLine : explode(' ', $commandLine);
86 if (count($rawCommandLineArguments) === 0) {
87 $request->setControllerCommandName('helpStub');
88 return $request;
89 }
90 $commandIdentifier = trim(array_shift($rawCommandLineArguments));
91 try {
92 $command = $this->commandManager->getCommandByIdentifier($commandIdentifier);
93 } catch (Tx_Extbase_MVC_Exception_Command $exception) {
94 $request->setArgument('exception', $exception);
95 $request->setControllerCommandName('error');
96 return $request;
97 }
98 $controllerObjectName = $command->getControllerClassName();
99 $controllerCommandName = $command->getControllerCommandName();
100 $request->setControllerObjectName($controllerObjectName);
101 $request->setControllerCommandName($controllerCommandName);
102 list($commandLineArguments, $exceedingCommandLineArguments) = $this->parseRawCommandLineArguments($rawCommandLineArguments, $controllerObjectName, $controllerCommandName);
103 $request->setArguments($commandLineArguments);
104 $request->setExceedingArguments($exceedingCommandLineArguments);
105 return $request;
106 }
107
108 /**
109 * Takes an array of unparsed command line arguments and options and converts it separated
110 * by named arguments, options and unnamed arguments.
111 *
112 * @param array $rawCommandLineArguments The unparsed command parts (such as "--foo") as an array
113 * @param string $controllerObjectName Object name of the designated command controller
114 * @param string $controllerCommandName Command name of the recognized command (ie. method name without "Command" suffix)
115 * @return array All and exceeding command line arguments
116 * @author Robert Lemke <robert@typo3.org>
117 */
118 protected function parseRawCommandLineArguments(array $rawCommandLineArguments, $controllerObjectName, $controllerCommandName) {
119 $commandLineArguments = array();
120 $exceedingArguments = array();
121 $commandMethodName = $controllerCommandName . 'Command';
122 $commandMethodParameters = $this->reflectionService->getMethodParameters($controllerObjectName, $commandMethodName);
123 $requiredArguments = array();
124 $optionalArguments = array();
125 $argumentNames = array();
126 foreach ($commandMethodParameters as $parameterName => $parameterInfo) {
127 $argumentNames[] = $parameterName;
128 if ($parameterInfo['optional'] === FALSE) {
129 $requiredArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
130 } else {
131 $optionalArguments[strtolower($parameterName)] = array('parameterName' => $parameterName, 'type' => $parameterInfo['type']);
132 }
133 }
134 $decidedToUseNamedArguments = FALSE;
135 $decidedToUseUnnamedArguments = FALSE;
136 $argumentIndex = 0;
137 while (count($rawCommandLineArguments) > 0) {
138 $rawArgument = array_shift($rawCommandLineArguments);
139 if ($rawArgument[0] === '-') {
140 if ($rawArgument[1] === '-') {
141 $rawArgument = substr($rawArgument, 2);
142 } else {
143 $rawArgument = substr($rawArgument, 1);
144 }
145 $argumentName = $this->extractArgumentNameFromCommandLinePart($rawArgument);
146 if (isset($optionalArguments[$argumentName])) {
147 $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $optionalArguments[$argumentName]['type']);
148 $commandLineArguments[$optionalArguments[$argumentName]['parameterName']] = $argumentValue;
149 } elseif (isset($requiredArguments[$argumentName])) {
150 if ($decidedToUseUnnamedArguments) {
151 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);
152 }
153 $decidedToUseNamedArguments = TRUE;
154 $argumentValue = $this->getValueOfCurrentCommandLineOption($rawArgument, $rawCommandLineArguments, $requiredArguments[$argumentName]['type']);
155 $commandLineArguments[$requiredArguments[$argumentName]['parameterName']] = $argumentValue;
156 unset($requiredArguments[$argumentName]);
157 }
158 } else {
159 if (count($requiredArguments) > 0) {
160 if ($decidedToUseNamedArguments) {
161 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);
162 }
163 $argument = array_shift($requiredArguments);
164 $commandLineArguments[$argument['parameterName']] = $rawArgument;
165 $decidedToUseUnnamedArguments = TRUE;
166 } else {
167 if ($argumentIndex < count($argumentNames)) {
168 $commandLineArguments[$argumentNames[$argumentIndex]] = $rawArgument;
169 } else {
170 $exceedingArguments[] = $rawArgument;
171 }
172 }
173 }
174 $argumentIndex++;
175 }
176 return array($commandLineArguments, $exceedingArguments);
177 }
178
179 /**
180 * Extracts the option or argument name from the name / value pair of a command line.
181 *
182 * @param string $commandLinePart Part of the command line, e.g. "my-important-option=SomeInterestingValue
183 * @return string The lowercased argument name, e.g. "myimportantoption
184 */
185 protected function extractArgumentNameFromCommandLinePart($commandLinePart) {
186 $nameAndValue = explode('=', $commandLinePart, 2);
187 return strtolower(str_replace('-', '', $nameAndValue[0]));
188 }
189
190 /**
191 * Returns the value of the first argument of the given input array. Shifts the parsed argument off the array.
192 *
193 * @param string $currentArgument The current argument
194 * @param array &$rawCommandLineArguments Array of the remaining command line arguments
195 * @param string $expectedArgumentType The expected type of the current argument, because booleans get special attention
196 * @return string The value of the first argument
197 * @author Andreas Förthner <andreas.foerthner@netlogix.de>
198 * @author Robert Lemke <robert@typo3.org>
199 */
200 protected function getValueOfCurrentCommandLineOption($currentArgument, array &$rawCommandLineArguments, $expectedArgumentType) {
201 if (!isset($rawCommandLineArguments[0]) && strpos($currentArgument, '=') === FALSE || (isset($rawCommandLineArguments[0]) && $rawCommandLineArguments[0][0] === '-') && strpos($currentArgument, '=') === FALSE) {
202 return TRUE;
203 }
204 if (strpos($currentArgument, '=') === FALSE) {
205 $possibleValue = trim(array_shift($rawCommandLineArguments));
206 if (strpos($possibleValue, '=') === FALSE) {
207 if ($expectedArgumentType !== 'boolean') {
208 return $possibleValue;
209 }
210 if (array_search($possibleValue, array('on', '1', 'y', 'yes', 'true', 'TRUE')) !== FALSE) {
211 return TRUE;
212 }
213 if (array_search($possibleValue, array('off', '0', 'n', 'no', 'false', 'FALSE')) !== FALSE) {
214 return FALSE;
215 }
216 array_unshift($rawCommandLineArguments, $possibleValue);
217 return TRUE;
218 }
219 $currentArgument .= $possibleValue;
220 }
221 $splitArgument = explode('=', $currentArgument, 2);
222 while ((!isset($splitArgument[1]) || trim($splitArgument[1]) === '') && count($rawCommandLineArguments) > 0) {
223 $currentArgument .= array_shift($rawCommandLineArguments);
224 $splitArgument = explode('=', $currentArgument);
225 }
226 $value = isset($splitArgument[1]) ? $splitArgument[1] : '';
227 return $value;
228 }
229
230 }
231
232 ?>