getSchedulableCommands() as $commandIdentifier => $command) { $this->schedulableCommands[$commandIdentifier] = $command; } ksort($this->schedulableCommands); } /** * Render additional information fields within the scheduler backend. * * @param array &$taskInfo Array information of task to return * @param AbstractTask|null $task When editing, reference to the current task. NULL when adding. * @param SchedulerModuleController $schedulerModule Reference to the calling object (BE module of the Scheduler) * @return array Additional fields * @see \TYPO3\CMS\Scheduler\AdditionalFieldProvider#getAdditionalFields($taskInfo, $task, $schedulerModule) */ public function getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $schedulerModule): array { $this->task = $task; if ($this->task !== null) { $this->task->setScheduler(); } $fields = []; $fields['action'] = $this->getActionField(); if ($this->task !== null && isset($this->schedulableCommands[$this->task->getCommandIdentifier()])) { $command = $this->schedulableCommands[$this->task->getCommandIdentifier()]; $fields['description'] = $this->getCommandDescriptionField($command->getDescription()); $argumentFields = $this->getCommandArgumentFields($command->getDefinition()); $fields = array_merge($fields, $argumentFields); $optionFields = $this->getCommandOptionFields($command->getDefinition()); $fields = array_merge($fields, $optionFields); $this->task->save(); // todo: this seems to be superfluous } return $fields; } /** * Validates additional selected fields * * @param array &$submittedData * @param SchedulerModuleController $schedulerModule * @return bool */ public function validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule): bool { if (!isset($this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']])) { return false; } $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']]; /** @var FlashMessageService $flashMessageService */ $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); $hasErrors = false; foreach ($command->getDefinition()->getArguments() as $argument) { foreach ((array)$submittedData['task_executeschedulablecommand']['arguments'] as $argumentName => $argumentValue) { /** @var string $argumentName */ /** @var string $argumentValue */ if ($argument->getName() !== $argumentName) { continue; } if ($argument->isRequired() && trim($argumentValue) === '') { // Argument is required and argument value is empty0 $flashMessageService->getMessageQueueByIdentifier()->addMessage( new FlashMessage( sprintf( $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.mandatoryArgumentMissing'), $argumentName ), $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateError'), FlashMessage::ERROR ) ); $hasErrors = true; } } } foreach ($command->getDefinition()->getOptions() as $optionDefinition) { $optionEnabled = $submittedData['task_executeschedulablecommand']['options'][$optionDefinition->getName()] ?? false; $optionValue = $submittedData['task_executeschedulablecommand']['option_values'][$optionDefinition->getName()] ?? $optionDefinition->getDefault(); if ($optionEnabled && $optionDefinition->isValueRequired()) { if ($optionDefinition->isArray()) { $testValues = is_array($optionValue) ? $optionValue : GeneralUtility::trimExplode(',', $optionValue, false); } else { $testValues = [$optionValue]; } foreach ($testValues as $testValue) { if ($testValue === null || trim($testValue) === '') { // An option that requires a value is used with an empty value $flashMessageService->getMessageQueueByIdentifier()->addMessage( new FlashMessage( sprintf( $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.mandatoryArgumentMissing'), $optionDefinition->getName() ), $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateError'), FlashMessage::ERROR ) ); $hasErrors = true; } } } } return $hasErrors === false; } /** * Saves additional field values * * @param array $submittedData * @param AbstractTask $task * @return bool */ public function saveAdditionalFields(array $submittedData, AbstractTask $task): bool { $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']]; /** @var ExecuteSchedulableCommandTask $task */ $task->setCommandIdentifier($submittedData['task_executeschedulablecommand']['command']); $arguments = []; foreach ((array)$submittedData['task_executeschedulablecommand']['arguments'] as $argumentName => $argumentValue) { try { $argumentDefinition = $command->getDefinition()->getArgument($argumentName); } catch (InvalidArgumentException $e) { continue; } if ($argumentDefinition->isArray()) { $argumentValue = GeneralUtility::trimExplode(',', $argumentValue, true); } $arguments[$argumentName] = $argumentValue; } $options = []; $optionValues = []; foreach ($command->getDefinition()->getOptions() as $optionDefinition) { $optionEnabled = $submittedData['task_executeschedulablecommand']['options'][$optionDefinition->getName()] ?? false; $options[$optionDefinition->getName()] = (bool)$optionEnabled; if ($optionDefinition->isValueRequired() || $optionDefinition->isValueOptional() || $optionDefinition->isArray()) { $optionValue = $submittedData['task_executeschedulablecommand']['option_values'][$optionDefinition->getName()] ?? $optionDefinition->getDefault(); if ($optionDefinition->isArray() && !is_array($optionValue)) { // Do not remove empty array values. // One empty array element indicates the existence of one occurence of an array option (InputOption::VALUE_IS_ARRAY) without a value. // Empty array elements are also required for command options like "-vvv" (can be entered as ",,"). $optionValue = GeneralUtility::trimExplode(',', $optionValue, false); } } else { // boolean flag: option value must be true if option is added or false otherwise $optionValue = (bool)$optionEnabled; } $optionValues[$optionDefinition->getName()] = $optionValue; } $task->setArguments($arguments); $task->setOptions($options); $task->setOptionValues($optionValues); return true; } /** * Get description of selected command * * @param string $description * @return array */ protected function getCommandDescriptionField(string $description): array { return [ 'code' => '', 'label' => '' . $description . '' ]; } /** * Gets a select field containing all possible schedulable commands * * @return array */ protected function getActionField(): array { $currentlySelectedCommand = $this->task !== null ? $this->task->getCommandIdentifier() : ''; $options = []; foreach ($this->schedulableCommands as $commandIdentifier => $command) { $options[$commandIdentifier] = $commandIdentifier . ': ' . $command->getDescription(); } return [ 'code' => $this->renderSelectField($options, $currentlySelectedCommand), 'label' => $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.schedulableCommandName') ]; } /** * Gets a set of fields covering arguments which can or must be used. * Also registers the default values of those fields with the Task, allowing * them to be read upon execution. * * @param InputDefinition $inputDefinition * @return array */ protected function getCommandArgumentFields(InputDefinition $inputDefinition): array { $fields = []; $argumentValues = $this->task->getArguments(); foreach ($inputDefinition->getArguments() as $argument) { $name = $argument->getName(); $defaultValue = $argument->getDefault(); $this->task->addDefaultValue($name, $defaultValue); $value = $argumentValues[$name] ?? $defaultValue; if (is_array($value) && $argument->isArray()) { $value = implode(',', $value); } $fields[$name] = [ 'code' => $this->renderArgumentField($argument, (string)$value), 'label' => $this->getArgumentLabel($argument) ]; } return $fields; } /** * Gets a set of fields covering options which can or must be used. * Also registers the default values of those fields with the Task, allowing * them to be read upon execution. * * @param InputDefinition $inputDefinition * @return array */ protected function getCommandOptionFields(InputDefinition $inputDefinition): array { $fields = []; $enabledOptions = $this->task->getOptions(); $optionValues = $this->task->getOptionValues(); foreach ($inputDefinition->getOptions() as $option) { $name = $option->getName(); $defaultValue = $option->getDefault(); $this->task->addDefaultValue($name, $defaultValue); $enabled = $enabledOptions[$name] ?? false; $value = $optionValues[$name] ?? $defaultValue; if (is_array($value) && $option->isArray()) { $value = implode(',', $value); } $fields[$name] = [ 'code' => $this->renderOptionField($option, (bool)$enabled, (string)$value), 'label' => $this->getOptionLabel($option) ]; } return $fields; } /** * Get a human-readable label for a command argument * * @param InputArgument $argument * @return string */ protected function getArgumentLabel(InputArgument $argument): string { return 'Argument: ' . $argument->getName() . '. ' . htmlspecialchars($argument->getDescription()) . ''; } /** * Get a human-readable label for a command option * * @param InputOption $option * @return string */ protected function getOptionLabel(InputOption $option): string { return 'Option: ' . htmlspecialchars($option->getName()) . '. ' . htmlspecialchars($option->getDescription()) . ''; } /** * @param array $options * @param string $selectedOptionValue * @return string */ protected function renderSelectField(array $options, string $selectedOptionValue): string { $selectTag = new TagBuilder(); $selectTag->setTagName('select'); $selectTag->forceClosingTag(true); $selectTag->addAttribute('class', 'form-control'); $selectTag->addAttribute('name', 'tx_scheduler[task_executeschedulablecommand][command]'); $optionsHtml = ''; foreach ($options as $value => $label) { $optionTag = new TagBuilder(); $optionTag->setTagName('option'); $optionTag->forceClosingTag(true); $optionTag->addAttribute('title', (string)$label); $optionTag->addAttribute('value', (string)$value); $optionTag->setContent($label); if ($value === $selectedOptionValue) { $optionTag->addAttribute('selected', 'selected'); } $optionsHtml .= $optionTag->render(); } $selectTag->setContent($optionsHtml); return $selectTag->render(); } /** * Renders a field for defining an argument's value * * @param InputArgument $argument * @param mixed $currentValue * @return string */ protected function renderArgumentField(InputArgument $argument, string $currentValue): string { $name = $argument->getName(); $fieldName = 'tx_scheduler[task_executeschedulablecommand][arguments][' . $name . ']'; $inputTag = new TagBuilder(); $inputTag->setTagName('input'); $inputTag->addAttribute('type', 'text'); $inputTag->addAttribute('name', $fieldName); $inputTag->addAttribute('value', $currentValue); $inputTag->addAttribute('class', 'form-control'); return $inputTag->render(); } /** * Renders a field for defining an option's value * * @param InputOption $option * @param mixed $currentValue * @return string */ protected function renderOptionField(InputOption $option, bool $enabled, string $currentValue): string { $name = $option->getName(); $checkboxFieldName = 'tx_scheduler[task_executeschedulablecommand][options][' . $name . ']'; $checkboxId = 'tx_scheduler_task_executeschedulablecommand_options_' . $name; $checkboxTag = new TagBuilder(); $checkboxTag->setTagName('input'); $checkboxTag->addAttribute('id', $checkboxId); $checkboxTag->addAttribute('name', $checkboxFieldName); $checkboxTag->addAttribute('type', 'checkbox'); if ($enabled) { $checkboxTag->addAttribute('checked', 'checked'); } $html = ''; if ($option->isValueRequired() || $option->isValueOptional() || $option->isArray()) { $valueFieldName = 'tx_scheduler[task_executeschedulablecommand][option_values][' . $name . ']'; $inputTag = new TagBuilder(); $inputTag->setTagName('input'); $inputTag->addAttribute('name', $valueFieldName); $inputTag->addAttribute('type', 'text'); $inputTag->addAttribute('value', $currentValue); $inputTag->addAttribute('class', 'form-control'); $html .= $inputTag->render(); } return $html; } /** * @return LanguageService */ public function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }