Creating a custom scheduler task 

Implementation of a custom scheduler task 

All scheduler task implementations must extend \TYPO3\CMS\Scheduler\Task\AbstractTask .

packages/my_extension/Classes/MyTask.php
<?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');
    }
}
Copied!

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.

Method getAdditionalInformation() should be implemented to provide additional information in the schedulers backend module.

Scheduler task implementations that provide additional fields should implement additional methods, expecially getTaskParameters().

Scheduler task registration and configuration 

Deprecated since version 14.0

Registering tasks and additional field providers via $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] has been deprecated.

Custom scheduler tasks can be registered via TCA overrides, for example in EXT:my_extension/Configuration/TCA/Overrides/tx_scheduler_my_task.php

EXT:my_extension/Configuration/TCA/Overrides/tx_scheduler_my_task.php
<?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'
    );
}
Copied!

Providing additional fields for scheduler task 

Deprecated since version 14.0 Deprecation: #98453 - Scheduler task registration via SC_OPTIONS

Registering tasks via $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] has been deprecated. It will stop working in TYPO3 v16.

Changed in version 15.0 Breaking: #109783 - Deprecated functionality removed

Additional fields for scheduler tasks are handled via FormEngine and can be configured via TCA.

The task needs to be registered via TCA override:

EXT:my_extension/Configuration/TCA/Overrides/scheduler_my_task_type.php
<?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,
                --palette--;;execution,
            --div--;core.form.tabs:access,
                disable,
            --div--;core.form.tabs:extended,',
        [],
        '',
        'tx_scheduler_task'
    );
}
Copied!

And implemented the following methods in your scheduler task if needed:

packages/my_extension/Classes/MyTask.php
<?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
        );
    }
}
Copied!