[!!!][TASK] Remove support for non namespaced classes in Extbase
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Cli / Command.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Cli;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Extbase\Reflection\ClassSchema;
18
19 /**
20 * Represents a Command
21 *
22 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
23 */
24 class Command
25 {
26 /**
27 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
28 */
29 protected $objectManager;
30
31 /**
32 * @var string
33 */
34 protected $controllerClassName;
35
36 /**
37 * @var string
38 */
39 protected $controllerCommandName;
40
41 /**
42 * @var string
43 */
44 protected $commandIdentifier;
45
46 /**
47 * Name of the extension to which this command belongs
48 *
49 * @var string
50 */
51 protected $extensionName;
52
53 /**
54 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
55 */
56 protected $reflectionService;
57
58 /**
59 * @var ClassSchema
60 */
61 protected $classSchema;
62
63 /**
64 * @var string
65 */
66 protected $controllerCommandMethod;
67
68 /**
69 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
70 */
71 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
72 {
73 $this->objectManager = $objectManager;
74 }
75
76 /**
77 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
78 */
79 public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService)
80 {
81 $this->reflectionService = $reflectionService;
82 }
83
84 /**
85 * Constructor
86 *
87 * @param string $controllerClassName Class name of the controller providing the command
88 * @param string $controllerCommandName Command name, i.e. the method name of the command, without the "Command" suffix
89 * @throws \InvalidArgumentException
90 */
91 public function __construct($controllerClassName, $controllerCommandName)
92 {
93 $this->controllerClassName = $controllerClassName;
94 $this->controllerCommandName = $controllerCommandName;
95 $this->controllerCommandMethod = $this->controllerCommandName . 'Command';
96 $classNameParts = explode('\\', $controllerClassName);
97 if (isset($classNameParts[0]) && $classNameParts[0] === 'TYPO3' && isset($classNameParts[1]) && $classNameParts[1] === 'CMS') {
98 $classNameParts[0] .= '\\' . $classNameParts[1];
99 unset($classNameParts[1]);
100 $classNameParts = array_values($classNameParts);
101 }
102 $numberOfClassNameParts = count($classNameParts);
103 if ($numberOfClassNameParts < 3) {
104 throw new \InvalidArgumentException(
105 'Controller class names must at least consist of three parts: vendor, extension name and path.',
106 1438782187
107 );
108 }
109 if (strpos($classNameParts[$numberOfClassNameParts - 1], 'CommandController') === false) {
110 throw new \InvalidArgumentException(
111 'Invalid controller class name "' . $controllerClassName . '". Class name must end with "CommandController".',
112 1305100019
113 );
114 }
115
116 $this->extensionName = $classNameParts[1];
117 $extensionKey = \TYPO3\CMS\Core\Utility\GeneralUtility::camelCaseToLowerCaseUnderscored($this->extensionName);
118 $this->commandIdentifier = strtolower($extensionKey . ':' . substr($classNameParts[$numberOfClassNameParts - 1], 0, -17) . ':' . $controllerCommandName);
119 }
120
121 public function initializeObject()
122 {
123 $this->classSchema = $this->reflectionService->getClassSchema($this->controllerClassName);
124 }
125
126 /**
127 * @return string
128 */
129 public function getControllerClassName()
130 {
131 return $this->controllerClassName;
132 }
133
134 /**
135 * @return string
136 */
137 public function getControllerCommandName()
138 {
139 return $this->controllerCommandName;
140 }
141
142 /**
143 * Returns the command identifier for this command
144 *
145 * @return string The command identifier for this command, following the pattern extensionname:controllername:commandname
146 */
147 public function getCommandIdentifier()
148 {
149 return $this->commandIdentifier;
150 }
151
152 /**
153 * Returns the name of the extension to which this command belongs
154 *
155 * @return string
156 */
157 public function getExtensionName()
158 {
159 return $this->extensionName;
160 }
161
162 /**
163 * Returns a short description of this command
164 *
165 * @return string A short description
166 */
167 public function getShortDescription()
168 {
169 $lines = explode(LF, $this->classSchema->getMethod($this->controllerCommandMethod)['description']);
170 return !empty($lines) ? trim($lines[0]) : '<no description available>';
171 }
172
173 /**
174 * Returns a longer description of this command
175 * This is the complete method description except for the first line which can be retrieved via getShortDescription()
176 * If The command description only consists of one line, an empty string is returned
177 *
178 * @return string A longer description of this command
179 */
180 public function getDescription()
181 {
182 $lines = explode(LF, $this->classSchema->getMethod($this->controllerCommandMethod)['description']);
183 array_shift($lines);
184 $descriptionLines = [];
185 foreach ($lines as $line) {
186 $trimmedLine = trim($line);
187 if ($descriptionLines !== [] || $trimmedLine !== '') {
188 $descriptionLines[] = $trimmedLine;
189 }
190 }
191 return implode(LF, $descriptionLines);
192 }
193
194 /**
195 * Returns TRUE if this command expects required and/or optional arguments, otherwise FALSE
196 *
197 * @return bool
198 */
199 public function hasArguments()
200 {
201 return !empty($this->classSchema->getMethod($this->controllerCommandMethod)['params']);
202 }
203
204 /**
205 * Returns an array of \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition that contains
206 * information about required/optional arguments of this command.
207 * If the command does not expect any arguments, an empty array is returned
208 *
209 * @return array<\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition>
210 */
211 public function getArgumentDefinitions()
212 {
213 if (!$this->hasArguments()) {
214 return [];
215 }
216 $commandArgumentDefinitions = [];
217 $commandParameters = $this->classSchema->getMethod($this->controllerCommandMethod)['params'];
218 $commandParameterTags = $this->classSchema->getMethod($this->controllerCommandMethod)['tags']['param'];
219 $i = 0;
220 foreach ($commandParameters as $commandParameterName => $commandParameterDefinition) {
221 $explodedAnnotation = preg_split('/\s+/', $commandParameterTags[$i], 3);
222 $description = !empty($explodedAnnotation[2]) ? $explodedAnnotation[2] : '';
223 $required = $commandParameterDefinition['optional'] !== true;
224 $commandArgumentDefinitions[] = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition::class, $commandParameterName, $required, $description);
225 $i++;
226 }
227 return $commandArgumentDefinitions;
228 }
229
230 /**
231 * Tells if this command is internal and thus should not be exposed through help texts, user documentation etc.
232 * Internall commands are still accessible through the regular command line interface, but should not be used
233 * by users.
234 *
235 * @return bool
236 */
237 public function isInternal()
238 {
239 return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['internal']);
240 }
241
242 /**
243 * Tells if this command is meant to be used on CLI only.
244 *
245 * @return bool
246 */
247 public function isCliOnly()
248 {
249 return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['cli']);
250 }
251
252 /**
253 * Tells if this command flushes all caches and thus needs special attention in the interactive shell.
254 *
255 * Note that neither this method nor the @flushesCaches annotation is currently part of the official API.
256 *
257 * @return bool
258 */
259 public function isFlushingCaches()
260 {
261 return isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['flushesCaches']);
262 }
263
264 /**
265 * Returns an array of command identifiers which were specified in the "@see"
266 * annotation of a command method.
267 *
268 * @return array
269 */
270 public function getRelatedCommandIdentifiers()
271 {
272 if (!isset($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['see'])) {
273 return [];
274 }
275 $relatedCommandIdentifiers = [];
276 foreach ($this->classSchema->getMethod($this->controllerCommandMethod)['tags']['see'] as $tagValue) {
277 if (preg_match('/^[\\w\\d\\.]+:[\\w\\d]+:[\\w\\d]+$/', $tagValue) === 1) {
278 $relatedCommandIdentifiers[] = $tagValue;
279 }
280 }
281 return $relatedCommandIdentifiers;
282 }
283 }