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