Implementing an upgrade wizard 

Deprecated since version 14.0

The attribute \TYPO3\CMS\Install\Attribute\UpgradeWizard has been deprecated in favour of \TYPO3\CMS\Core\Attribute\UpgradeWizard .

The interfaces and classes used for upgrade wizards have been moved from namespace \TYPO3\CMS\Install\Updates to \TYPO3\CMS\Core\Upgrades.

Using the old locations is deprecated in v14 but can be used to provide compatibility with both TYPO3 v13 and v14.

To create an upgrade wizard you have to add a class which implements the UpgradeWizardInterface.

The class may implement other interfaces (optional):

UpgradeWizardInterface 

Deprecated since version 14.0

\TYPO3\CMS\Install\Updates\UpgradeWizardInterface has been deprecated, implement \TYPO3\CMS\Core\Upgrades\UpgradeWizardInterface once dropping TYPO3 v13 support.

The attribute \TYPO3\CMS\Install\Attribute\UpgradeWizard has been deprecated in favour of \TYPO3\CMS\Core\Attribute\UpgradeWizard .

Each upgrade wizard consists of a single PHP file containing a single PHP class. This class has to implement \TYPO3\CMS\Core\Upgrades\UpgradeWizardInterface and its methods.

The registration of an upgrade wizard is done directly in the class by adding the class attribute \TYPO3\CMS\Core\Attribute\UpgradeWizard . The unique identifier is passed as an argument.

EXT:my_extension/Classes/Upgrades/ExampleUpgradeWizard.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Upgrades;

use TYPO3\CMS\Core\Attribute\UpgradeWizard;
use TYPO3\CMS\Core\Upgrades\UpgradeWizardInterface;

#[UpgradeWizard('myExtension_exampleUpgradeWizard')]
final class ExampleUpgradeWizard implements UpgradeWizardInterface
{
    /**
     * Return the speaking name of this wizard
     */
    public function getTitle(): string
    {
        return 'Title of this updater';
    }

    /**
     * Return the description for this wizard
     */
    public function getDescription(): string
    {
        return 'Description of this updater';
    }

    /**
     * Execute the update
     *
     * Called when a wizard reports that an update is necessary
     *
     * The boolean indicates whether the update was successful
     */
    public function executeUpdate(): bool
    {
        // Add your logic here
    }

    /**
     * Is an update necessary?
     *
     * Is used to determine whether a wizard needs to be run.
     * Check if data for migration exists.
     *
     * @return bool Whether an update is required (TRUE) or not (FALSE)
     */
    public function updateNecessary(): bool
    {
        // Add your logic here
    }

    /**
     * Returns an array of class names of prerequisite classes
     *
     * This way a wizard can define dependencies like "database up-to-date" or
     * "reference index updated"
     *
     * @return string[]
     */
    public function getPrerequisites(): array
    {
        // Add your logic here
    }
}
Copied!
Method getTitle()
Return the speaking name of this wizard.
Method getDescription()
Return the description for this wizard.
Method executeUpdate()
Is called, if the user triggers the wizard. This method should contain, or call, the code that is needed to execute the upgrade. Return a boolean indicating whether the update was successful.
Method updateNecessary()
Is called to check whether the upgrade wizard has to run. Return true, if an upgrade is necessary, false if not. If false is returned, the upgrade wizard will not be displayed in the list of available wizards.
Method getPrerequisites()

Returns an array of class names of prerequisite classes. This way, a wizard can define dependencies before it can be performed. Currently, the following prerequisites exist:

  • DatabaseUpdatedPrerequisite : Ensures that the database table fields are up-to-date.
  • ReferenceIndexUpdatedPrerequisite : The reference index needs to be up-to-date.
EXT:my_extension/Classes/Upgrades/ExampleUpgradeWizard.php
use TYPO3\CMS\Core\Upgrades\DatabaseUpdatedPrerequisite;
use TYPO3\CMS\Core\Upgrades\ReferenceIndexUpdatedPrerequisite;

/**
 * @return string[]
 */
public function getPrerequisites(): array
{
    return [
        DatabaseUpdatedPrerequisite::class,
        ReferenceIndexUpdatedPrerequisite::class,
    ];
}
Copied!

After creating the new upgrade wizard, delete all caches in System > Maintenance > Flush TYPO3 and PHP Cache or via console command:

vendor/bin/typo3 cache:flush
Copied!
typo3/sysext/core/bin/typo3 cache:flush
Copied!

Wizard identifier 

The wizard identifier is used:

  • when calling the wizard from the command line.
  • when marking the wizard as done in the table sys_registry

Since all upgrade wizards of TYPO3 Core and extensions are registered using the identifier, it is recommended to prepend the wizard identifier with a prefix based on the extension key.

You should use the following naming convention for the identifier:

myExtension_wizardName, for example bootstrapPackage_addNewDefaultTypes

  • The extension key and wizard name in lowerCamelCase, separated by underscore
  • The existing underscores in extension keys are replaced by capitalizing the following letter

Some examples:

Extension key Wizard identifier
container container_upgradeColumnPositions
news_events newsEvents_migrateEvents
bootstrap_package bootstrapPackage_addNewDefaultTypes

Marking wizard as done 

Deprecated since version 14.0

\TYPO3\CMS\Install\Updates\RepeatableInterface has been deprecated, implement \TYPO3\CMS\Core\Upgrades\RepeatableInterface once dropping TYPO3 v13 support.

As soon as the wizard has completely finished, for example, it detected that no upgrade is necessary anymore, the wizard is marked as done and will not be checked anymore.

To force TYPO3 to check the wizard every time, the interface \TYPO3\CMS\Core\Upgrades\RepeatableInterface has to be implemented. This interface works as a marker and does not force any methods to be implemented.

Generating output 

The \TYPO3\CMS\Install\Updates\ChattyInterface can be implemented for wizards which should generate output. It uses the Symfony interface \Symfony\Component\Console\Output\OutputInterface.

Classes using this interface must implement the following method:

vendor/symfony/console/Output/OutputInterface.php
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Setter injection for output into upgrade wizards
 */
 public function setOutput(OutputInterface $output): void;
Copied!

The class \TYPO3\CMS\Core\Upgrades\DatabaseUpdatedPrerequisite implements this interface. We are showing a simplified example here, based on this class:

EXT:install/Classes/Updates/DatabaseUpdatedPrerequisite.php
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Upgrades\DatabaseUpdatedPrerequisite;
use TYPO3\CMS\Core\Upgrades\ChattyInterface;

class DatabaseUpdatedPrerequisite implements PrerequisiteInterface, ChattyInterface
{
    /**
     * @var OutputInterface
     */
    protected $output;

    public function setOutput(OutputInterface $output): void
    {
        $this->output = $output;
    }

    public function ensure(): bool
    {
        $adds = $this->upgradeWizardsService->getBlockingDatabaseAdds();
        $result = null;
        if (count($adds) > 0) {
            $this->output->writeln('Performing ' . count($adds) . ' database operations.');
            $result = $this->upgradeWizardsService->addMissingTablesAndFields();
        }
        return $result === null;
    }

    // ... more logic
}
Copied!

Executing the wizard 

Changed in version 14.0

The upgrade wizards can always be run via the console command typo3 upgrade:run.

The backend module System > Upgrade can only be used if typo3/cms-install is installed.

Wizards are listed in the backend module System > Upgrade and the card Upgrade Wizard. The registered wizard should be shown there, as long as it is not done.

It is also possible to execute the wizard from the command line:

vendor/bin/typo3 upgrade:run myExtension_exampleUpgradeWizard
Copied!
typo3/sysext/core/bin/typo3 upgrade:run myExtension_exampleUpgradeWizard
Copied!