TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:38 +02:00
commit 4392dbe2ce
142 changed files with 11824 additions and 0 deletions
@@ -0,0 +1,129 @@
:navigation-title: Task development
.. include:: /Includes.rst.txt
.. _creating-tasks:
================================
Creating a custom scheduler task
================================
.. important::
.. versionchanged:: 14.0
Custom scheduler tasks can be registered as TCA types in table
`tx_scheduler_task`.
See also: `Changelog Feature: #107526 - Custom TCA types for scheduler tasks <https://docs.typo3.org/permalink/changelog:feature-107526-1747816234>`_.
.. contents:: Table of contents
.. toctree::
:glob:
:titlesonly:
*
.. seealso::
Symfony console commands can also be executed as scheduler task:
See :ref:`Create and use Symfony commands in TYPO3 <t3coreapi:symfony-console-commands>`.
.. _creating-tasks-implementation:
Implementation of a custom scheduler task
=========================================
All scheduler task implementations **must** extend
:php:`\TYPO3\CMS\Scheduler\Task\AbstractTask`.
.. literalinclude:: _codesnippets/_MyTask.php.inc
:language: php
:caption: packages/my_extension/Classes/MyTask.php
A custom task implementation **must** override the method `execute(): bool`.
It is the main method that is called when a task is executed.
This method Should return `true` on successful execution, `false` on error.
.. note::
There is no error handling by default, errors and failures are expected
to be handled and logged by the client implementation.
Method `getAdditionalInformation()` **should** be implemented to provide
additional information in the schedulers backend module.
Scheduler task implementations that provide `additional fields <https://docs.typo3.org/permalink/typo3/cms-scheduler:additional-fields>`_
**should** implement additional methods, expecially `getTaskParameters()`.
.. _creating-tasks-registration:
Scheduler task registration and configuration
=============================================
.. deprecated:: 14.0
Registering tasks and additional field providers via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']` has
been deprecated.
Custom scheduler tasks can be registered via TCA overrides, for example in
:file:`EXT:my_extension/Configuration/TCA/Overrides/tx_scheduler_my_task.php`
.. literalinclude:: _codesnippets/_tx_scheduler_my_task.php.inc
:language: php
:caption: EXT:my_extension/Configuration/TCA/Overrides/tx_scheduler_my_task.php
.. tip::
Using the :php:`iconOverlay` option on task type registration, an icon
overlay can be added, which is then displayed in the wizard. This can
be useful for similar task types that use the same "base" `icon`, but
still have to be differentiated.
.. include:: /_Includes/_ExtendingSchedulerTca.rst.txt
.. _additional-fields:
Providing additional fields for scheduler task
==============================================
.. deprecated:: 14.0
Registering tasks and additional field providers via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']` has
been deprecated.
The :php-short:`\TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface` and
:php-short:`\TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider` have also
been deprecated.
Tasks in general and additional fields for tasks are registered via TCA
instead.
See also: `Migrating tasks with AdditionalFieldProviders to TCA registration <https://docs.typo3.org/permalink/typo3/cms-scheduler:additional-fields-migration>`_
Additional fields for scheduler tasks are handled via FormEngine and can be
configured via TCA.
If the task should provide additional fields for configuration options in
the backend module, you need to implement a second class, extending
:php-short:`\TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider`.
The task needs to be registered via TCA override:
.. literalinclude:: _codesnippets/_scheduler_my_task_type-additional.php.inc
:language: php
:caption: EXT:my_extension/Configuration/TCA/Overrides/scheduler_my_task_type.php
And implemented the following methods in your scheduler task if needed:
.. literalinclude:: _codesnippets/_MyTaskWithAdditionalFields.php.inc
:language: php
:caption: packages/my_extension/Classes/MyTask.php
.. note::
Method `getTaskParameters()` should be implemented when
`migrating tasks <https://docs.typo3.org/permalink/typo3/cms-scheduler:additional-fields-migration>`_
For native TCA tasks, this method is typically no longer needed in custom
tasks after the migration has been done, since field values are then stored
directly in database columns.
.. seealso::
There are additional examples in described in the
`Changelog Feature: #107526 - Custom TCA types for scheduler tasks <https://docs.typo3.org/permalink/changelog:feature-107526-1747816234>`_.
@@ -0,0 +1,110 @@
:navigation-title: Migration
.. include:: /Includes.rst.txt
.. _task-migration:
=====================================================
Migration to the TCA registration for scheduler tasks
=====================================================
.. deprecated:: 14.0
Registering tasks and additional field providers via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']` has
been deprecated.
The :php-short:`\TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface` and
:php-short:`\TYPO3\CMS\Scheduler\AbstractAdditionalFieldProvider` have also
been deprecated.
.. contents:: Table of contents
Tasks in general and additional fields for tasks are registered via TCA
instead.
.. _additional-fields-migration:
Migrating tasks with AdditionalFieldProviders to TCA registration
=================================================================
Scheduler tasks should now be registered as native task types using TCA.
This provides a more integrated and maintainable approach to task configuration.
.. _additional-fields-migration-steps:
Migration steps:
----------------
1. Remove the registration from :file:`ext_localconf.php`
2. Create a TCA override file in :file:`Configuration/TCA/Overrides/scheduler_my_task_type.php`
3. Update your task class to implement the new parameter methods
4. Remove the :php:`AdditionalFieldProvider` class if it exists
.. note::
The new TCA-based approach automatically migrates existing task data.
When upgrading, existing task configurations are preserved through the
:php:`getTaskParameters()` and :php:`setTaskParameters()` methods.
.. _additional-fields-migration-example:
Example migration: Scheduler task with additional fields suppporting TYPO3 13 and 14
------------------------------------------------------------------------------------
Remove the registration from :file:`ext_localconf.php` once TYPO3 13 support is
dropped:
.. literalinclude:: _codesnippets/_ext_localconf_deprecated.php.inc
:language: php
:caption: packages/my_extension/ext_localconf.php
And also remove the :php:`MyTaskAdditionalFieldProvider` class once
TYPO3 13 support is dropped.
Create a TCA override file in :file:`Configuration/TCA/Overrides/scheduler_my_task_type.php`:
.. literalinclude:: _codesnippets/_scheduler_my_task_type-additional.php.inc
:language: php
:caption: EXT:my_extension/Configuration/TCA/Overrides/scheduler_my_task_type.php
Update your (existing) task class to implement the new methods:
.. literalinclude:: _codesnippets/_MyTaskWithAdditionalFieldsMigration.php.inc
:language: php
:caption: packages/my_extension/Classes/MyTask.php
The new TCA-based approach uses three key methods for parameter handling:
**getTaskParameters(): array**
This method is already implemented in ``AbstractTask`` to handle task class
properties automatically, but can be overridden in task classes for custom
behavior.
The method is primarily used:
* For migration from old serialized task format to new TCA structure
* For non-native (deprecated) task types to store their values in the legacy ``parameters`` field
For native TCA tasks, this method is typically no longer needed in custom
tasks after the migration has been done, since field values are then stored
directly in database columns.
**setTaskParameters(array $parameters): void**
Sets field values from an associative array. This method handles:
* Migration from old AdditionalFieldProvider field names to new TCA field names
* Loading saved task configurations when editing or executing tasks
* Parameter mapping during task creation and updates
* The method should always be implemented, especially for native tasks
The migration pattern is: :php:`$this->myField = $parameters['oldName'] ?? $parameters['new_tca_field_name'] ?? '';`
**validateTaskParameters(array $parameters): bool**
*Optional method.* Only implement this for validation that cannot be handled by FormEngine.
* Basic validation (required, trim, etc.) should be done via TCA configuration (``required`` property and ``eval`` options)
* Use this method for complex business logic validation (e.g., email format validation, external API checks)
* Return ``false`` and add FlashMessage for validation errors
* FormEngine automatically handles standard TCA validation rules
For a complete working example, see :php:`\TYPO3\CMS\Reports\Task\SystemStatusUpdateTask`
and its corresponding TCA configuration in
:file:`EXT:reports/Configuration/TCA/Overrides/scheduler_system_status_update_task.php`.
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Task;
use MyVendor\MyExtension\BusinessLogic;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
final class MyTask extends AbstractTask
{
/**
* MUST be implemented by all tasks
*/
public function execute(): bool
{
# Dependency injection cannot be used in scheduler tasks
$businessLogic = GeneralUtility::makeInstance(BusinessLogic::class);
return $businessLogic->run('arg1', 'arg2', '…');
}
public function getAdditionalInformation()
{
$this->getLanguageService()->sL('LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTaskInformation');
}
}
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Task;
use MyVendor\MyExtension\BusinessLogic;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
final class MyTask extends AbstractTask
{
protected string $myField = '';
protected string $emailList = '';
public function execute(): bool
{
# Dependency injection cannot be used in scheduler tasks
$businessLogic = GeneralUtility::makeInstance(BusinessLogic::class);
return $businessLogic->run($this->myField, $this->emailList, '…');
}
/**
* Set field values from associative array.
*
* @param array $parameters Values from TCA fields
*/
public function setTaskParameters(array $parameters): void
{
$this->myField = $parameters['my_extension_field'] ?? '';
$this->emailList = $parameters['my_extension_email_list'] ?? '';
}
/**
* Validate task parameters.
* Only implement this method for validation that cannot be handled by FormEngine.
* Basic validation like 'required' should be done via TCA 'eval' configuration.
*/
public function validateTaskParameters(array $parameters): bool
{
$isValid = true;
// Example: Custom email validation (beyond basic 'required' check)
$emailList = $parameters['my_extension_email_list'] ?? '';
if (!empty($emailList)) {
$emails = GeneralUtility::trimExplode(',', $emailList, true);
foreach ($emails as $email) {
if (!GeneralUtility::validEmail($email)) {
GeneralUtility::makeInstance(FlashMessageService::class)
->getMessageQueueByIdentifier()
->addMessage(
GeneralUtility::makeInstance(
FlashMessage::class,
'Invalid email address: ' . $email,
'',
ContextualFeedbackSeverity::ERROR
)
);
$isValid = false;
}
}
}
return $isValid;
}
public function getAdditionalInformation(): string
{
return sprintf(
'Field: %s, Emails: %s',
$this->myField,
$this->emailList
);
}
}
@@ -0,0 +1,96 @@
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Task;
use MyVendor\MyExtension\BusinessLogic;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask;
final class MyTask extends AbstractTask
{
protected string $myField = '';
protected string $emailList = '';
public function execute(): bool
{
# Dependency injection cannot be used in scheduler tasks
$businessLogic = GeneralUtility::makeInstance(BusinessLogic::class);
return $businessLogic->run($this->myField, $this->emailList, '…');
}
/**
* Return current field values as associative array.
* This method is called during migration from old serialized tasks
* and when displaying task information.
*/
public function getTaskParameters(): array
{
return [
'my_extension_field' => $this->myField,
'my_extension_email_list' => $this->emailList,
];
}
/**
* Set field values from associative array.
* This method handles both old and new parameter formats for migration.
*
* @param array $parameters Values from either old AdditionalFieldProvider or new TCA fields
*/
public function setTaskParameters(array $parameters): void
{
// Handle migration: check old parameter names first, then new TCA field names
$this->myField = $parameters['myField'] ?? $parameters['my_extension_field'] ?? '';
$this->emailList = $parameters['emailList'] ?? $parameters['my_extension_email_list'] ?? '';
}
/**
* Validate task parameters.
* Only implement this method for validation that cannot be handled by FormEngine.
* Basic validation like 'required' should be done via TCA 'eval' configuration.
*/
public function validateTaskParameters(array $parameters): bool
{
$isValid = true;
// Example: Custom email validation (beyond basic 'required' check)
$emailList = $parameters['my_extension_email_list'] ?? '';
if (!empty($emailList)) {
$emails = GeneralUtility::trimExplode(',', $emailList, true);
foreach ($emails as $email) {
if (!GeneralUtility::validEmail($email)) {
GeneralUtility::makeInstance(FlashMessageService::class)
->getMessageQueueByIdentifier()
->addMessage(
GeneralUtility::makeInstance(
FlashMessage::class,
'Invalid email address: ' . $email,
'',
ContextualFeedbackSeverity::ERROR
)
);
$isValid = false;
}
}
}
return $isValid;
}
public function getAdditionalInformation(): string
{
$info = [];
if ($this->myField !== '') {
$info[] = 'Field: ' . $this->myField;
}
if ($this->emailList !== '') {
$info[] = 'Emails: ' . $this->emailList;
}
return implode(', ', $info);
}
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use MyVendor\MyExtension\Task\MyTask;
if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() < 14) {
// Todo: Remove when TYPO3 13 support is dropped
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][MyTask::class] = [
'extension' => 'my_extension',
'title' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTask.title',
'description' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:myTask.description',
'additionalFields' => \MyVendor\MyExtension\Task\MyTaskAdditionalFieldProvider::class,
];
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use MyVendor\MyExtension\Task\MyTask;
defined('TYPO3') or die();
if (isset($GLOBALS['TCA']['tx_scheduler_task'])) {
// Add custom fields to the tx_scheduler_task table
ExtensionManagementUtility::addTCAcolumns(
'tx_scheduler_task',
[
'my_extension_field' => [
'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:field.label',
'config' => [
'type' => 'input',
'size' => 30,
'required' => true,
'eval' => 'trim',
'placeholder' => 'Enter value here...',
],
],
'my_extension_email_list' => [
'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:emailList.label',
'config' => [
'type' => 'text',
'rows' => 3,
'required' => true,
'placeholder' => 'admin@example.com',
],
],
]
);
// Register the task type
ExtensionManagementUtility::addRecordType(
[
'label' => 'Some title or LLL:EXT reference',
'description' => 'Some description or LLL:EXT reference',
'value' => MyTask::class,
'icon' => 'mimetypes-x-tx_scheduler_task_group',
'iconOverlay' => 'content-clock',
'group' => 'my_extension',
],
'
--div--;core.form.tabs:general,
tasktype,
task_group,
description,
my_extension_field,
my_extension_email_list,
--div--;core.form.tabs:timing,
execution_details,
nextexecution,
--palette--;;lastexecution,
--div--;core.form.tabs:access,
disable,
--div--;core.form.tabs:extended,',
[],
'',
'tx_scheduler_task'
);
}
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
use MyVendor\MyExtension\Task\MyTask;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
if (isset($GLOBALS['TCA']['tx_scheduler_task'])) {
ExtensionManagementUtility::addRecordType(
[
'label' => 'My Custom Task',
'description' => 'Description of what this task does',
'value' => MyTask::class,
'icon' => 'my-custom-icon',
'iconOverlay' => 'content-clock',
'group' => 'my_extension',
],
$GLOBALS['TCA']['tx_scheduler_task']['types']['0']['showitem'],
[],
'',
'tx_scheduler_task'
);
}
@@ -0,0 +1,54 @@
:navigation-title: Events
.. include:: /Includes.rst.txt
.. _scheduler-events:
==========================================
Events provided by the scheduler extension
==========================================
The system extension :composer:`typo3/cms-scheduler` provides the following
events:
.. contents:: Table of contents
.. _ModifyNewSchedulerTaskWizardItemsEvent:
ModifyNewSchedulerTaskWizardItemsEvent
======================================
The PSR-14 event :php:`\TYPO3\CMS\Scheduler\Event\ModifyNewSchedulerTaskWizardItemsEvent`
allows extensions to modify the items in the
`scheduler task wizard <https://docs.typo3.org/permalink/typo3/cms-scheduler:adding-editing-task-wizard>`_.
.. seealso::
`ModifyNewSchedulerTaskWizardItemsEvent (TYPO3 explained) <https://docs.typo3.org/permalink/t3coreapi:ModifyNewSchedulerTaskWizardItemsEvent>`_
for examples and the api information.
.. _AfterTaskExecutionEvent:
AfterTaskExecutionEvent
=======================
The PSR-14 event :php:`\TYPO3\CMS\Scheduler\Event\AfterTaskExecutionEvent`
is dispatched after a scheduled task (including command tasks) has been executed.
It provides the following information:
* :php:`getTask(): AbstractTask` — the executed task object
* :php:`isSuccess(): bool` — whether the task completed without exception
* :php:`getException(): ?\Throwable` — the thrown exception on failure, or :php:`null` on success
Example listener::
use TYPO3\CMS\Scheduler\Event\AfterTaskExecutionEvent;
final class SchedulerTaskResultListener
{
public function __invoke(AfterTaskExecutionEvent $event): void
{
$task = $event->getTask();
$status = $event->isSuccess() ? 'success' : 'failure';
// e.g. send a notification, write to a custom log, etc.
}
}
+19
View File
@@ -0,0 +1,19 @@
:navigation-title: Development
.. include:: /Includes.rst.txt
.. _developer-guide:
==========================
Scheduler task development
==========================
The Scheduler makes it very easy to create a new task class.
Furthermore the tasks packaged with this extension provide
a good basis to learn by example.
.. toctree::
:maxdepth: 5
:titlesonly:
:glob:
*/Index
@@ -0,0 +1,30 @@
.. include:: /Includes.rst.txt
.. _scheduler-api:
=============
Scheduler API
=============
It is possible to refer to the Scheduler from other extensions. Once a
:php:`\TYPO3\CMS\Scheduler\Scheduler` object has been instantiated all of its
public methods can be used. The PHPdoc of the methods should be enough to
understand what each is to be used for.
The extension ships with a
:php:`\TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository` class,
which provides some helpful methods, for example:
* :php:`findByUid(int $uid)`: this method is used to fetch a registered task
from the database given an ID.
* :php:`findNextExecutableTask()`: this method returns the next due task. The
return value is the unserialized task object.
* :php:`findRecordByUid(int $uid)`: is also used to retrieve a registered task
from the database, but it returns the record corresponding to the task
registration and not the task object itself.
These are the main methods that will be used from outside the
Scheduler as they can retrieve registered tasks from the database.
When a task has been fetched, all public methods from the
:php:`\TYPO3\CMS\Scheduler\Task\AbstractTask` class can be used.
@@ -0,0 +1,58 @@
.. include:: /Includes.rst.txt
.. _technical-background:
.. _scheduler-task-storage:
======================
Scheduler task storage
======================
.. versionchanged:: 14.0
With TYPO3 v14.0 the storage of scheduler tasks switched from the
PHP-serialized storage format in the database to a JSON-based format.
The scheduler tasks displayed in backend module :guilabel:`Administration > Scheduler`
are stored in the **database** table :sql:`tx_scheduler_task`. Task groups are
stored in table :sql:`tx_scheduler_task_group`.
.. contents:: Table of contents
.. _scheduler-task-storage-fields:
tx_scheduler_task fields
========================
The database table :sql:`tx_scheduler_task` contains the following fields:
`tasktype`
Typically contains the fully qualified class name of the task, for example
:php:`\TYPO3\CMS\Scheduler\Task\CachingFrameworkGarbageCollectionTask` or
the command name, for example `language:update` if the task is implemented as
`Symfony console command <https://docs.typo3.org/permalink/t3coreapi:symfony-console-commands>`_.
`parameters`
The options configuring the task as JSON-encoded value.
`execution_details`
Contains all details on execution like the type (Recurring / Single),
start and end dates and the frequency in which recurring tasks should be
executed.
Additionally it stores some information on the last and next execution of the
task, and fields for a description and the group.
.. _serialized-objects:
.. _save-task-state:
.. _serialized-objects_migration:
Migration from serialized task objects
======================================
.. attention::
.. versionchanged:: 14.0
The storage format was changed with TYPO3 v14. If the database field
:sql:`tx_scheduler_task:tasktype` is empty this hints at a missing or failed
migration by the upgrade wizard. See also:
`Important: #106532 - Changed database storage format for Scheduler Tasks <https://docs.typo3.org/permalink/changelog:important-106532-1744207039>`_
A manual migration is necessary. You can also delete the task and
create it newly.