[!!!][TASK] Remove support for non namespaced classes in Extbase
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Scheduler / FieldProvider.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Scheduler;
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\Utility\TypeHandlingUtility;
18 use TYPO3\CMS\Scheduler\Controller\SchedulerModuleController;
19 use TYPO3\CMS\Scheduler\Task\AbstractTask;
20
21 /**
22 * Field provider for Extbase CommandController Scheduler task
23 */
24 class FieldProvider implements \TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface
25 {
26 /**
27 * @var \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager
28 */
29 protected $commandManager;
30
31 /**
32 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
33 */
34 protected $objectManager;
35
36 /**
37 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
38 */
39 protected $reflectionService;
40
41 /**
42 * @var \TYPO3\CMS\Extbase\Scheduler\Task
43 */
44 protected $task;
45
46 /**
47 * Constructor
48 *
49 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
50 * @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager
51 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
52 */
53 public function __construct(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager = null, \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager $commandManager = null, \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService = null)
54 {
55 $this->objectManager = $objectManager ?? \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
56 $this->commandManager = $commandManager ?? $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Cli\CommandManager::class);
57 $this->reflectionService = $reflectionService ?? $this->objectManager->get(\TYPO3\CMS\Extbase\Reflection\ReflectionService::class);
58 }
59
60 /**
61 * Render additional information fields within the scheduler backend.
62 *
63 * @param array &$taskInfo Array information of task to return
64 * @param AbstractTask|null $task When editing, reference to the current task. NULL when adding.
65 * @param SchedulerModuleController $schedulerModule Reference to the calling object (BE module of the Scheduler)
66 * @return array Additional fields
67 * @see \TYPO3\CMS\Scheduler\AdditionalFieldProvider#getAdditionalFields($taskInfo, $task, $schedulerModule)
68 */
69 public function getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $schedulerModule)
70 {
71 $this->task = $task;
72 if ($this->task !== null) {
73 $this->task->setScheduler();
74 }
75 $fields = [];
76 $fields['action'] = $this->getCommandControllerActionField();
77 if ($this->task !== null && $this->task->getCommandIdentifier()) {
78 $command = $this->commandManager->getCommandByIdentifier($this->task->getCommandIdentifier());
79 $fields['description'] = $this->getCommandControllerActionDescriptionField();
80 $argumentFields = $this->getCommandControllerActionArgumentFields($command->getArgumentDefinitions());
81 $fields = array_merge($fields, $argumentFields);
82 $this->task->save();
83 }
84 return $fields;
85 }
86
87 /**
88 * Validates additional selected fields
89 *
90 * @param array &$submittedData
91 * @param SchedulerModuleController $schedulerModule
92 * @return bool
93 */
94 public function validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule)
95 {
96 return true;
97 }
98
99 /**
100 * Saves additional field values
101 *
102 * @param array $submittedData
103 * @param AbstractTask $task
104 * @return bool
105 */
106 public function saveAdditionalFields(array $submittedData, AbstractTask $task)
107 {
108 $task->setCommandIdentifier($submittedData['task_extbase']['action']);
109 $task->setArguments((array)$submittedData['task_extbase']['arguments']);
110 return true;
111 }
112
113 /**
114 * Get description of selected command
115 *
116 * @return string
117 */
118 protected function getCommandControllerActionDescriptionField()
119 {
120 $command = $this->commandManager->getCommandByIdentifier($this->task->getCommandIdentifier());
121 return [
122 'code' => '',
123 'label' => '<strong>' . $command->getDescription() . '</strong>'
124 ];
125 }
126
127 /**
128 * Gets a select field containing all possible CommandController actions
129 *
130 * @return array
131 */
132 protected function getCommandControllerActionField()
133 {
134 $commands = $this->commandManager->getAvailableCommands();
135 $options = [];
136 foreach ($commands as $command) {
137 if ($command->isInternal() === true || $command->isCliOnly() === true) {
138 continue;
139 }
140 $className = $command->getControllerClassName();
141 $classNameParts = explode('\\', $className);
142 // Skip vendor and product name for core classes
143 if (strpos($className, 'TYPO3\\CMS\\') === 0) {
144 $classPartsToSkip = 2;
145 } else {
146 $classPartsToSkip = 1;
147 }
148 $classNameParts = array_slice($classNameParts, $classPartsToSkip);
149 $extensionName = $classNameParts[0];
150 $controllerName = $classNameParts[2];
151 $identifier = $command->getCommandIdentifier();
152 $options[$identifier] = $extensionName . ' ' . str_replace('CommandController', '', $controllerName) . ': ' . $command->getControllerCommandName();
153 }
154 $name = 'action';
155 $currentlySelectedCommand = $this->task !== null ? $this->task->getCommandIdentifier() : null;
156 return [
157 'code' => $this->renderSelectField($name, $options, $currentlySelectedCommand),
158 'label' => $this->getActionLabel()
159 ];
160 }
161
162 /**
163 * Gets a set of fields covering arguments which must be sent to $currentControllerAction.
164 * Also registers the default values of those fields with the Task, allowing
165 * them to be read upon execution.
166 *
167 * @param array $argumentDefinitions
168 * @return array
169 */
170 protected function getCommandControllerActionArgumentFields(array $argumentDefinitions)
171 {
172 $fields = [];
173 $argumentValues = $this->task->getArguments();
174 foreach ($argumentDefinitions as $argument) {
175 $name = $argument->getName();
176 $defaultValue = $this->getDefaultArgumentValue($argument);
177 $this->task->addDefaultValue($name, $defaultValue);
178 $value = $argumentValues[$name] ?? $defaultValue;
179 $fields[$name] = [
180 'code' => $this->renderField($argument, $value),
181 'label' => $this->getArgumentLabel($argument)
182 ];
183 }
184 return $fields;
185 }
186
187 /**
188 * Gets a label for $key based on either provided extension or currently
189 * selected CommandController extension,ยด
190 *
191 * @param string $localLanguageKey
192 * @param string $extensionName
193 * @return string
194 */
195 protected function getLanguageLabel($localLanguageKey, $extensionName = null)
196 {
197 if (!$extensionName) {
198 list($extensionName, $commandControllerName, $commandName) = explode(':', $this->task->getCommandIdentifier());
199 }
200 $label = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($localLanguageKey, $extensionName);
201 return $label;
202 }
203
204 /**
205 * Gets the data type required for the argument value
206 *
207 * @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument
208 * @return string the argument type
209 */
210 protected function getArgumentType(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument)
211 {
212 $command = $this->commandManager->getCommandByIdentifier($this->task->getCommandIdentifier());
213 $controllerClassName = $command->getControllerClassName();
214 $methodName = $command->getControllerCommandName() . 'Command';
215 $tags = $this->reflectionService->getMethodTagsValues($controllerClassName, $methodName);
216 foreach ($tags['param'] as $tag) {
217 list($argumentType, $argumentVariableName) = explode(' ', $tag);
218 if (substr($argumentVariableName, 1) === $argument->getName()) {
219 return $argumentType;
220 }
221 }
222 return '';
223 }
224
225 /**
226 * Get a human-readable label for a command argument
227 *
228 * @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument
229 * @return string
230 */
231 protected function getArgumentLabel(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument)
232 {
233 $argumentName = $argument->getName();
234 list($extensionName, $commandControllerName, $commandName) = explode(':', $this->task->getCommandIdentifier());
235 $path = ['command', $commandControllerName, $commandName, 'arguments', $argumentName];
236 $labelNameIndex = implode('.', $path);
237 $label = $this->getLanguageLabel($labelNameIndex);
238 if (!$label) {
239 $label = 'Argument: ' . $argumentName;
240 }
241 $descriptionIndex = $labelNameIndex . '.description';
242 $description = $this->getLanguageLabel($descriptionIndex);
243 if ((string)$description === '') {
244 $description = $argument->getDescription();
245 }
246 if ((string)$description !== '') {
247 $label .= '. <em>' . htmlspecialchars($description) . '</em>';
248 }
249 return $label;
250 }
251
252 /**
253 * Gets the default value of argument
254 *
255 * @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument
256 * @return mixed
257 */
258 protected function getDefaultArgumentValue(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument)
259 {
260 $type = $this->getArgumentType($argument);
261 $argumentName = $argument->getName();
262 $command = $this->commandManager->getCommandByIdentifier($this->task->getCommandIdentifier());
263 $argumentReflection = $this->reflectionService->getMethodParameters($command->getControllerClassName(), $command->getControllerCommandName() . 'Command');
264 $defaultValue = $argumentReflection[$argumentName]['defaultValue'];
265 if (TypeHandlingUtility::normalizeType($type) === 'boolean') {
266 $defaultValue = (bool)$defaultValue ? 1 : 0;
267 }
268 return $defaultValue;
269 }
270
271 /**
272 * Get a human-readable label for the action field
273 *
274 * @return string
275 */
276 protected function getActionLabel()
277 {
278 $index = 'task.action';
279 $label = $this->getLanguageLabel($index, 'extbase');
280 if (!$label) {
281 $label = 'CommandController Command. <em>Save and reopen to define command arguments</em>';
282 }
283 return $label;
284 }
285
286 /**
287 * Render a select field with name $name and options $options
288 *
289 * @param string $name
290 * @param array $options
291 * @param string $selectedOptionValue
292 * @return string
293 */
294 protected function renderSelectField($name, array $options, $selectedOptionValue)
295 {
296 $html = [
297 '<select class="form-control" name="tx_scheduler[task_extbase][' . htmlspecialchars($name) . ']">'
298 ];
299 foreach ($options as $optionValue => $optionLabel) {
300 $selected = $optionValue === $selectedOptionValue ? ' selected="selected"' : '';
301 $html[] = '<option title="test" value="' . htmlspecialchars($optionValue) . '"' . $selected . '>' . htmlspecialchars($optionLabel) . '</option>';
302 }
303 $html[] = '</select>';
304 return implode(LF, $html);
305 }
306
307 /**
308 * Renders a field for defining an argument's value
309 *
310 * @param \TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument
311 * @param mixed $currentValue
312 * @return string
313 */
314 protected function renderField(\TYPO3\CMS\Extbase\Mvc\Cli\CommandArgumentDefinition $argument, $currentValue)
315 {
316 $type = $this->getArgumentType($argument);
317 $name = $argument->getName();
318 $fieldName = 'tx_scheduler[task_extbase][arguments][' . htmlspecialchars($name) . ']';
319 if (TypeHandlingUtility::normalizeType($type) === 'boolean') {
320 // checkbox field for boolean values.
321 $html = '<input type="hidden" name="' . $fieldName . '" value="0">';
322 $html .= '<div class="checkbox"><label><input type="checkbox" name="' . $fieldName . '" value="1" ' . ((bool)$currentValue ? ' checked="checked"' : '') . '></label></div>';
323 } else {
324 // regular string, also the default field type
325 $html = '<input class="form-control" type="text" name="' . $fieldName . '" value="' . htmlspecialchars($currentValue) . '"> ';
326 }
327 return $html;
328 }
329 }