111 lines
4.6 KiB
PHP
111 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Scheduler\Task;
|
|
|
|
use Psr\Container\ContainerInterface;
|
|
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
|
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Scheduler\Exception\InvalidTaskException;
|
|
use TYPO3\CMS\Scheduler\Execution;
|
|
use TYPO3\CMS\Scheduler\Service\TaskService;
|
|
|
|
/**
|
|
* Handles serialization of `AbstractTask` objects.
|
|
*
|
|
* @internal This is an internal API, avoid using it in custom implementations.
|
|
*/
|
|
#[Autoconfigure(public: true)]
|
|
readonly class TaskSerializer
|
|
{
|
|
public function __construct(
|
|
protected ContainerInterface $container,
|
|
protected TaskService $taskService,
|
|
) {}
|
|
|
|
/**
|
|
* This method takes care of safely deserializing tasks from the database
|
|
* and either returns a valid Task or throws an InvalidTaskException, which
|
|
* holds information about the broken task.
|
|
*
|
|
* First, find the task object, from the registry
|
|
* Second, recreate the execution object,
|
|
* Then fill all the data of the new task object from the rest of the row.
|
|
*
|
|
* @throws InvalidTaskException
|
|
*/
|
|
public function deserialize(array $row): AbstractTask
|
|
{
|
|
$taskType = $row['tasktype'] ?? '';
|
|
if (!empty($taskType)) {
|
|
if ($this->taskService->isTaskTypeRegistered($taskType)) {
|
|
$taskInformation = $this->taskService->getTaskDetailsFromTaskType($taskType);
|
|
$className = $taskInformation['className'];
|
|
try {
|
|
$taskObject = $this->container->get($className);
|
|
} catch (ServiceNotFoundException) {
|
|
$taskObject = GeneralUtility::makeInstance($className);
|
|
}
|
|
} else {
|
|
throw new InvalidTaskException('Task type ' . $taskType . ' not found. Probably not registered?', 1742584362);
|
|
}
|
|
|
|
if (!$taskObject instanceof AbstractTask) {
|
|
throw new InvalidTaskException('The deserialized task in not an instance of AbstractTask', 1642954501);
|
|
}
|
|
if ($taskObject instanceof ExecuteSchedulableCommandTask) {
|
|
$taskObject->setTaskType($taskType);
|
|
}
|
|
$taskObject->setTaskUid((int)$row['uid']);
|
|
$taskObject->setTaskGroup((int)$row['task_group']);
|
|
$taskParameters = json_decode($row['parameters'] ?? '', true) ?: [];
|
|
// Set additional fields from the row with the parameters stored
|
|
// in the parameters field for native types.
|
|
if ($taskInformation['isNativeTask'] ?? false) {
|
|
// If there are native registered fields, they take precedence over the values.
|
|
foreach ($taskInformation['additionalFields'] ?? [] as $additionalFieldName) {
|
|
$taskParameters[$additionalFieldName] = $taskParameters[$additionalFieldName] ?? $row[$additionalFieldName] ?? null;
|
|
}
|
|
}
|
|
$taskObject->setTaskParameters($taskParameters);
|
|
$taskObject->setDescription((string)$row['description']);
|
|
$taskObject->setExecutionTime((int)$row['nextexecution']);
|
|
$taskObject->setTaskGroup((int)$row['task_group']);
|
|
$taskObject->setDisabled((bool)$row['disable']);
|
|
$executionDetails = json_decode($row['execution_details'] ?? '', true);
|
|
if ($executionDetails !== null) {
|
|
$taskObject->setExecution(Execution::createFromDetails($executionDetails));
|
|
}
|
|
return $taskObject;
|
|
}
|
|
throw new InvalidTaskException('No task type given for task ID : ' . $row['uid'], 1740514192);
|
|
}
|
|
|
|
/**
|
|
* If the task class couldn't be figured out from the unserialization (because of uninstalled extensions or exceptions),
|
|
* try to find it in the serialized string with a simple preg match.
|
|
*/
|
|
public function extractClassName(string $serializedTask): ?string
|
|
{
|
|
if (preg_match('/^O:[0-9]+:"(?P<classname>[^"]+)"/', $serializedTask, $matches) === 1) {
|
|
return $matches['classname'];
|
|
}
|
|
return null;
|
|
}
|
|
}
|