‪TYPO3CMS  ‪main
ExecuteSchedulableCommandAdditionalFieldProvider.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Symfony\Component\Console\Command\Command;
21 use Symfony\Component\Console\Exception\InvalidArgumentException;
22 use Symfony\Component\Console\Input\InputArgument;
23 use Symfony\Component\Console\Input\InputDefinition;
24 use Symfony\Component\Console\Input\InputOption;
34 use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
35 
40 {
44  protected ‪$schedulableCommands = [];
45 
49  protected ‪$task;
50 
51  public function ‪__construct()
52  {
53  $commandRegistry = GeneralUtility::makeInstance(CommandRegistry::class);
54  foreach ($commandRegistry->getSchedulableCommands() as $commandIdentifier => $command) {
55  $this->schedulableCommands[$commandIdentifier] = $command;
56  }
57  ksort($this->schedulableCommands);
58  }
59 
69  public function ‪getAdditionalFields(array &$txSchedulerPostData, ‪$task, ‪SchedulerModuleController $schedulerModule): array
70  {
71  $this->task = ‪$task;
72  if ($this->task !== null) {
73  $this->task->‪setScheduler();
74  }
75 
76  ‪$fields = [
77  'schedulableCommands' => $this->‪getSchedulableCommandsField($txSchedulerPostData),
78  ];
79 
80  if ($this->task !== null && isset($this->schedulableCommands[$this->task->getCommandIdentifier()])) {
81  $command = $this->schedulableCommands[$this->task->getCommandIdentifier()];
82  $argumentFields = $this->‪getCommandArgumentFields($command->getDefinition());
83  ‪$fields = array_merge(‪$fields, $argumentFields);
84  $optionFields = $this->‪getCommandOptionFields($command->getDefinition());
85  ‪$fields = array_merge(‪$fields, $optionFields);
86  // @todo: this seems to be superfluous
87  GeneralUtility::makeInstance(SchedulerTaskRepository::class)->update($this->task);
88  }
89 
90  return ‪$fields;
91  }
92 
96  public function ‪validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule): bool
97  {
98  if (!isset($this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']])) {
99  return false;
100  }
101 
102  $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']];
103 
104  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
105 
106  $hasErrors = false;
107  foreach ($command->getDefinition()->getArguments() as $argument) {
108  foreach ((array)($submittedData['task_executeschedulablecommand']['arguments'] ?? []) as $argumentName => $argumentValue) {
111  if ($argument->getName() !== $argumentName) {
112  continue;
113  }
114 
115  if ($argument->isRequired() && trim($argumentValue) === '') {
116  // Argument is required and argument value is empty0
117  $flashMessageService->getMessageQueueByIdentifier()->addMessage(
118  new FlashMessage(
119  sprintf(
120  $this->‪getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.mandatoryArgumentMissing'),
121  $argumentName
122  ),
123  $this->‪getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateError'),
124  ContextualFeedbackSeverity::ERROR
125  )
126  );
127  $hasErrors = true;
128  }
129  }
130  }
131 
132  foreach ($command->getDefinition()->getOptions() as $optionDefinition) {
133  $optionEnabled = $submittedData['task_executeschedulablecommand']['options'][$optionDefinition->getName()] ?? false;
134  $optionValue = $submittedData['task_executeschedulablecommand']['option_values'][$optionDefinition->getName()] ?? $optionDefinition->getDefault();
135  if ($optionEnabled && $optionDefinition->isValueRequired()) {
136  if ($optionDefinition->isArray()) {
137  $testValues = is_array($optionValue) ? $optionValue : ‪GeneralUtility::trimExplode(',', $optionValue, false);
138  } else {
139  $testValues = [$optionValue];
140  }
141 
142  foreach ($testValues as $testValue) {
143  if ($testValue === null || trim($testValue) === '') {
144  // An option that requires a value is used with an empty value
145  $flashMessageService->getMessageQueueByIdentifier()->addMessage(
146  new FlashMessage(
147  sprintf(
148  $this->‪getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.mandatoryArgumentMissing'),
149  $optionDefinition->getName()
150  ),
151  $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateError'),
152  ContextualFeedbackSeverity::ERROR
153  )
154  );
155  $hasErrors = true;
156  }
157  }
158  }
159  }
160 
161  return $hasErrors === false;
162  }
163 
169  public function ‪saveAdditionalFields(array $submittedData, AbstractTask ‪$task): bool
170  {
171  $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']];
172 
174  ‪$task->‪setCommandIdentifier($submittedData['task_executeschedulablecommand']['command']);
175 
176  $arguments = [];
177  foreach ((array)($submittedData['task_executeschedulablecommand']['arguments'] ?? []) as $argumentName => $argumentValue) {
178  try {
179  $argumentDefinition = $command->getDefinition()->getArgument($argumentName);
180  } catch (InvalidArgumentException $e) {
181  continue;
182  }
183 
184  if ($argumentDefinition->isArray()) {
185  $argumentValue = ‪GeneralUtility::trimExplode(',', $argumentValue, true);
186  }
187 
188  $arguments[$argumentName] = $argumentValue;
189  }
190 
191  $options = [];
192  $optionValues = [];
193  foreach ($command->getDefinition()->getOptions() as $optionDefinition) {
194  $optionEnabled = $submittedData['task_executeschedulablecommand']['options'][$optionDefinition->getName()] ?? false;
195  $options[$optionDefinition->getName()] = (bool)$optionEnabled;
196 
197  if ($optionDefinition->isValueRequired() || $optionDefinition->isValueOptional() || $optionDefinition->isArray()) {
198  $optionValue = $submittedData['task_executeschedulablecommand']['option_values'][$optionDefinition->getName()] ?? $optionDefinition->getDefault();
199  if ($optionDefinition->isArray() && !is_array($optionValue)) {
200  // Do not remove empty array values.
201  // One empty array element indicates the existence of one occurrence of an array option (InputOption::VALUE_IS_ARRAY) without a value.
202  // Empty array elements are also required for command options like "-vvv" (can be entered as ",,").
203  $optionValue = ‪GeneralUtility::trimExplode(',', $optionValue, false);
204  }
205  } else {
206  // boolean flag: option value must be true if option is added or false otherwise
207  $optionValue = (bool)$optionEnabled;
208  }
209  $optionValues[$optionDefinition->getName()] = $optionValue;
210  }
211 
212  ‪$task->‪setArguments($arguments);
213  ‪$task->‪setOptions($options);
214  ‪$task->‪setOptionValues($optionValues);
215  return true;
216  }
217 
221  protected function ‪getSchedulableCommandsField(array $txSchedulerPostData): array
222  {
223  $currentlySelectedCommand = $this->task !== null
224  ? $this->task->getCommandIdentifier()
225  // Use value from POST if given. Happens when 'add task' is re-rendered due to
226  // broken / incomplete input data, and if such a task is added from the
227  // "info" submodule.
228  : $txSchedulerPostData['task_executeschedulablecommand']['command'] ?? '';
229  $options = [];
230  foreach ($this->schedulableCommands as $commandIdentifier => $command) {
231  $options[$commandIdentifier] = $commandIdentifier . ': ' . $command->getDescription();
232  }
233  $fieldCode = $this->‪renderSelectField($options, $currentlySelectedCommand);
234  return [
235  'code' => $fieldCode,
236  'label' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.schedulableCommandName',
237  'type' => 'select',
238  ];
239  }
240 
246  protected function ‪getCommandArgumentFields(InputDefinition $inputDefinition): array
247  {
248  ‪$fields = [];
249  $argumentValues = $this->task->getArguments();
250  foreach ($inputDefinition->getArguments() as $argument) {
251  $name = $argument->getName();
252  $defaultValue = $argument->getDefault();
253  $this->task->addDefaultValue($name, $defaultValue);
254  $value = $argumentValues[$name] ?? $defaultValue;
255 
256  if (is_array($value) && $argument->isArray()) {
257  $value = implode(',', $value);
258  }
259 
260  ‪$fields['arguments_' . $name] = [
261  'code' => $this->‪renderArgumentField($argument, (string)$value),
262  'label' => $this->‪getArgumentLabel($argument),
263  'description' => $this->‪getArgumentDescription($argument),
264  'type' => 'input',
265  ];
266  }
267 
268  return ‪$fields;
269  }
270 
276  protected function ‪getCommandOptionFields(InputDefinition $inputDefinition): array
277  {
278  ‪$fields = [];
279  $enabledOptions = $this->task->getOptions();
280  $optionValues = $this->task->getOptionValues();
281  foreach ($inputDefinition->getOptions() as $option) {
282  $name = $option->getName();
283  $defaultValue = $option->getDefault();
284  $this->task->addDefaultValue($name, $defaultValue);
285  $enabled = $enabledOptions[$name] ?? false;
286  $value = $optionValues[$name] ?? $defaultValue;
287 
288  if (is_array($value) && $option->isArray()) {
289  $value = implode(',', $value);
290  }
291 
292  ‪$fields['options_' . $name] = [
293  'code' => $this->‪renderOptionField($option, (bool)$enabled, (string)$value),
294  'additionalCode' => $this->‪renderOptionField($option, (bool)$enabled, (string)$value),
295  'label' => $this->‪getOptionLabel($option),
296  'description' => $this->‪getOptionDescription($option),
297  'type' => 'commandOption',
298  ];
299  }
300 
301  return ‪$fields;
302  }
303 
307  protected function ‪getArgumentLabel(InputArgument $argument): string
308  {
309  return 'Argument "' . $argument->getName() . '"';
310  }
311 
315  protected function ‪getArgumentDescription(InputArgument $argument): string
316  {
317  return $argument->getDescription();
318  }
319 
323  protected function ‪getOptionLabel(InputOption $option): string
324  {
325  return 'Option "' . $option->getName() . '"';
326  }
327 
331  protected function ‪getOptionDescription(InputOption $option): string
332  {
333  return $option->getDescription();
334  }
335 
336  protected function ‪renderSelectField(array $options, string $selectedOptionValue): string
337  {
338  $selectTag = new TagBuilder();
339  $selectTag->setTagName('select');
340  $selectTag->forceClosingTag(true);
341  $selectTag->addAttribute('id', 'schedulableCommands');
342  $selectTag->addAttribute('class', 'form-select');
343  $selectTag->addAttribute('name', 'tx_scheduler[task_executeschedulablecommand][command]');
344 
345  $optionsHtml = '';
346  foreach ($options as $value => $label) {
347  $optionTag = new TagBuilder();
348  $optionTag->setTagName('option');
349  $optionTag->forceClosingTag(true);
350  $optionTag->addAttribute('title', (string)$label);
351  $optionTag->addAttribute('value', (string)$value);
352  $optionTag->setContent($label);
353 
354  if ($value === $selectedOptionValue) {
355  $optionTag->addAttribute('selected', 'selected');
356  }
357 
358  $optionsHtml .= $optionTag->render();
359  }
360 
361  $selectTag->setContent($optionsHtml);
362  return $selectTag->render();
363  }
364 
368  protected function ‪renderArgumentField(InputArgument $argument, string $currentValue): string
369  {
370  $name = $argument->getName();
371  $fieldName = 'tx_scheduler[task_executeschedulablecommand][arguments][' . $name . ']';
372  $inputTagId = 'arguments_' . $name;
373  $inputTag = new TagBuilder();
374  $inputTag->setTagName('input');
375  $inputTag->addAttribute('type', 'text');
376  $inputTag->addAttribute('name', $fieldName);
377  $inputTag->addAttribute('value', $currentValue);
378  $inputTag->addAttribute('class', 'form-control form-control-clearable t3js-clearable');
379  $inputTag->addAttribute('id', $inputTagId);
380 
381  return $inputTag->render();
382  }
383 
387  protected function ‪renderOptionField(InputOption $option, bool $enabled, string $currentValue): array
388  {
389  $name = $option->getName();
390 
391  $checkboxFieldName = 'tx_scheduler[task_executeschedulablecommand][options][' . $name . ']';
392  $checkboxId = 'tx_scheduler_task_executeschedulablecommand_options_' . $name;
393  $checkboxTag = new TagBuilder();
394  $checkboxTag->setTagName('input');
395  $checkboxTag->addAttribute('id', $checkboxId);
396  $checkboxTag->addAttribute('name', $checkboxFieldName);
397  $checkboxTag->addAttribute('type', 'checkbox');
398  $checkboxTag->addAttribute('class', 'form-check-input');
399  $checkboxTagId = 'options_' . $name;
400  $checkboxTag->addAttribute('id', $checkboxTagId);
401  if ($enabled) {
402  $checkboxTag->addAttribute('checked', 'checked');
403  }
404  $html = $checkboxTag->render()
405  . '<label class="form-check-label" for="' . $checkboxTagId . '">'
406  . ' ' . $this->‪getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.addOptionToCommand')
407  . '</label>';
408 
409  $optionValueField = '';
410  if ($option->isValueRequired() || $option->isValueOptional() || $option->isArray()) {
411  $valueFieldName = 'tx_scheduler[task_executeschedulablecommand][option_values][' . $name . ']';
412  $inputTag = new TagBuilder();
413  $inputTagId = 'options_' . $name . '_values';
414  $inputTag->setTagName('input');
415  $inputTag->addAttribute('name', $valueFieldName);
416  $inputTag->addAttribute('type', 'text');
417  $inputTag->addAttribute('value', $currentValue);
418  $inputTag->addAttribute('class', 'form-control form-control-clearable t3js-clearable');
419  $inputTag->addAttribute('id', $inputTagId);
420  $optionValueField = $inputTag->render();
421  }
422 
423  return [
424  'html' => $html,
425  'optionValueField' => $optionValueField,
426  ];
427  }
428 
429  protected function ‪getLanguageService(): ‪LanguageService
430  {
431  return ‪$GLOBALS['LANG'];
432  }
433 }
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getAdditionalFields
‪array getAdditionalFields(array &$txSchedulerPostData, $task, SchedulerModuleController $schedulerModule)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:67
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getCommandOptionFields
‪getCommandOptionFields(InputDefinition $inputDefinition)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:274
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getLanguageService
‪getLanguageService()
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:427
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\saveAdditionalFields
‪saveAdditionalFields(array $submittedData, AbstractTask $task)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:167
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:40
‪TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository
Definition: SchedulerTaskRepository.php:36
‪TYPO3\CMS\Scheduler\Task
Definition: AbstractTask.php:16
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getOptionLabel
‪getOptionLabel(InputOption $option)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:321
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask\setArguments
‪setArguments(array $arguments)
Definition: ExecuteSchedulableCommandTask.php:145
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask
Definition: ExecuteSchedulableCommandTask.php:32
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getArgumentDescription
‪getArgumentDescription(InputArgument $argument)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:313
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\validateAdditionalFields
‪validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:94
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Core\Console\CommandRegistry
Definition: CommandRegistry.php:31
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\renderArgumentField
‪renderArgumentField(InputArgument $argument, string $currentValue)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:366
‪TYPO3\CMS\Scheduler\Task\AbstractTask\setScheduler
‪setScheduler()
Definition: AbstractTask.php:278
‪TYPO3\CMS\Scheduler\Task\AbstractTask
Definition: AbstractTask.php:33
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\$schedulableCommands
‪Command[] $schedulableCommands
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:43
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\__construct
‪__construct()
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:49
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\renderOptionField
‪renderOptionField(InputOption $option, bool $enabled, string $currentValue)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:385
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController
Definition: SchedulerModuleController.php:60
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getOptionDescription
‪getOptionDescription(InputOption $option)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:329
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask\setCommandIdentifier
‪setCommandIdentifier(string $commandIdentifier)
Definition: ExecuteSchedulableCommandTask.php:53
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getArgumentLabel
‪getArgumentLabel(InputArgument $argument)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:305
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\$task
‪ExecuteSchedulableCommandTask null $task
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:47
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask\setOptions
‪setOptions(array $options)
Definition: ExecuteSchedulableCommandTask.php:155
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getSchedulableCommandsField
‪getSchedulableCommandsField(array $txSchedulerPostData)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:219
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\renderSelectField
‪renderSelectField(array $options, string $selectedOptionValue)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:334
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask\setOptionValues
‪setOptionValues(array $optionValues)
Definition: ExecuteSchedulableCommandTask.php:165
‪TYPO3\CMS\Core\Messaging\FlashMessageService
Definition: FlashMessageService.php:27
‪TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface
Definition: AdditionalFieldProviderInterface.php:25
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider\getCommandArgumentFields
‪getCommandArgumentFields(InputDefinition $inputDefinition)
Definition: ExecuteSchedulableCommandAdditionalFieldProvider.php:244