[TASK] Migrate extension install upgrade wizards to new API 33/58233/4
authorSusanne Moog <susanne.moog@typo3.org>
Wed, 5 Sep 2018 21:22:34 +0000 (23:22 +0200)
committerFrank Naegler <frank.naegler@typo3.org>
Fri, 14 Sep 2018 11:36:03 +0000 (13:36 +0200)
Migrates all upgrade wizards based on the
`AbstractDownloadExtensionUpdate` class to the new API.

Related: #86172
Resolves: #86199
Releases: master
Change-Id: I79ffa702a1448bb66324074ef2debf41922d95e8
Reviewed-on: https://review.typo3.org/58233
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
12 files changed:
typo3/sysext/install/Classes/Command/UpgradeWizardRunCommand.php
typo3/sysext/install/Classes/Updates/AbstractDownloadExtensionUpdate.php
typo3/sysext/install/Classes/Updates/AdminPanelInstall.php
typo3/sysext/install/Classes/Updates/Compatibility7ExtractionUpdate.php
typo3/sysext/install/Classes/Updates/ExtensionModel.php [new file with mode: 0644]
typo3/sysext/install/Classes/Updates/FormLegacyExtractionUpdate.php
typo3/sysext/install/Classes/Updates/FuncExtractionUpdate.php
typo3/sysext/install/Classes/Updates/RedirectExtractionUpdate.php
typo3/sysext/install/Classes/Updates/RedirectsExtensionUpdate.php
typo3/sysext/install/Classes/Updates/RteHtmlAreaExtractionUpdate.php
typo3/sysext/install/Classes/Updates/Typo3DbExtractionUpdate.php
typo3/sysext/install/Tests/Unit/Updates/Compatibility7ExtractionUpdateTest.php

index d48bc8e..a84ec1f 100644 (file)
@@ -108,8 +108,6 @@ class UpgradeWizardRunCommand extends Command
                 if ($upgradeWizard !== null) {
                     $this->handlePrerequisites([$upgradeWizard]);
                     $result = $this->runSingleWizard($upgradeWizard);
-                } else {
-                    $this->output->warning('Wizard ' . $wizardToExecute . ' is already done.');
                 }
             } else {
                 $this->output->error('No such wizard: ' . $wizardToExecute);
@@ -151,7 +149,12 @@ class UpgradeWizardRunCommand extends Command
             return null;
         }
 
-        return $wizardInstance->updateNecessary() ? $wizardInstance : null;
+        if ($wizardInstance->updateNecessary()) {
+            return $wizardInstance;
+        }
+        $this->output->note('Wizard ' . $identifier . ' does not need to make changes. Marking wizard as done.');
+        $this->upgradeWizardsService->markWizardAsDone($identifier);
+        return null;
     }
 
     /**
@@ -218,6 +221,7 @@ class UpgradeWizardRunCommand extends Command
             $helper = $this->getHelper('question');
             if (!$helper->ask($this->input, $this->output, $question)) {
                 $this->upgradeWizardsService->markWizardAsDone($instance->getIdentifier());
+                $this->output->note('No changes applied, marking wizard as done.');
                 return 0;
             }
         }
index 0e2cb2d..3e7fbad 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+
 namespace TYPO3\CMS\Install\Updates;
 
 /*
@@ -14,6 +15,7 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Symfony\Component\Console\Output\OutputInterface;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
@@ -25,33 +27,48 @@ use TYPO3\CMS\Extensionmanager\Utility\ListUtility;
 /**
  * Download extension from TER
  */
-abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
+abstract class AbstractDownloadExtensionUpdate implements UpgradeWizardInterface, ConfirmableInterface, ChattyInterface
 {
     /**
      * @var string
      */
-    protected $title = 'Install an Extension from the Extension Repository';
+    protected $repositoryUrl = 'https://typo3.org/fileadmin/ter/@filename';
 
     /**
-     * See subclasses for more information
-     * @var array
+     * @var OutputInterface
      */
-    protected $extensionDetails = [];
+    protected $output;
 
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\ExtensionModel
      */
-    protected $repositoryUrl = 'https://typo3.org/fileadmin/ter/@filename';
+    protected $extension;
+
+    public function setOutput(OutputInterface $output): void
+    {
+        $this->output = $output;
+    }
+
+    /**
+     * Execute the update
+     * Called when a wizard reports that an update is necessary
+     *
+     * @return bool
+     */
+    public function executeUpdate(): bool
+    {
+        return $this->installExtension($this->extension);
+    }
 
     /**
      * This method can be called to install an extension following all proper processes
      * (e.g. installing in extList, respecting priority, etc.)
      *
-     * @param string $extensionKey
-     * @param string $customMessage
+     * @param \TYPO3\CMS\Install\Updates\ExtensionModel $extension
      * @return bool whether the installation worked or not
+     * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
      */
-    protected function installExtension($extensionKey, &$customMessage)
+    protected function installExtension(ExtensionModel $extension): bool
     {
         $updateSuccessful = true;
         /** @var ObjectManager $objectManager */
@@ -60,27 +77,23 @@ abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
         /** @var ListUtility $extensionListUtility */
         $extensionListUtility = $objectManager->get(ListUtility::class);
         $availableExtensions = $extensionListUtility->getAvailableExtensions();
-        $extensionDetails = $this->getExtensionDetails($extensionKey);
 
+        $extensionKey = $extension->getKey();
         $isExtensionAvailable = !empty($availableExtensions[$extensionKey]);
         $isComposerMode = Environment::isComposerMode();
 
         if (!$isComposerMode && !$isExtensionAvailable) {
             /** @var TerUtility $extensionTerUtility */
             $extensionTerUtility = $objectManager->get(TerUtility::class);
-            if (empty($extensionDetails)) {
-                $updateSuccessful = false;
-                $customMessage .= 'No version information for extension ' . $extensionKey . ' found. Can not install the extension.';
-            }
-            $t3xContent = $this->fetchExtension($extensionKey, $extensionDetails['versionString']);
+            $t3xContent = $this->fetchExtension($extensionKey, $extension->getVersionString());
             if (empty($t3xContent)) {
                 $updateSuccessful = false;
-                $customMessage .= 'The extension ' . $extensionKey . ' could not be downloaded.';
+                $this->output->writeln('<error>The extension ' . $extensionKey . ' could not be downloaded.</error>');
             }
             $t3xExtracted = $extensionTerUtility->decodeExchangeData($t3xContent);
             if (empty($t3xExtracted) || !is_array($t3xExtracted) || empty($t3xExtracted['extKey'])) {
                 $updateSuccessful = false;
-                $customMessage .= 'The extension ' . $extensionKey . ' could not be extracted.';
+                $this->output->writeln('<error>The extension ' . $extensionKey . ' could not be extracted.</error>');
             }
 
             /** @var FileHandlingUtility $extensionFileHandlingUtility */
@@ -93,10 +106,16 @@ abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
 
         if ($isComposerMode && !$isExtensionAvailable) {
             $updateSuccessful = false;
-            $customMessage .= 'The extension ' . $extensionKey . ' can not be downloaded since ' .
-              'Composer is used for package management. Please require this ' .
-              'extension as package via Composer: ' .
-              '"composer require ' . $extensionDetails['composerName'] . ':^' . $extensionDetails['versionString'] . '"';
+            $this->output->writeln('<warning>The extension ' .
+                              $extensionKey .
+                              ' can not be downloaded since ' .
+                              'Composer is used for package management. Please require this ' .
+                              'extension as package via Composer: ' .
+                              '"composer require ' .
+                              $extension->getComposerName() .
+                              ':^' .
+                              $extension->getVersionString() .
+                              '"</warning>');
         }
 
         if ($updateSuccessful) {
@@ -109,31 +128,14 @@ abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
     }
 
     /**
-     * Returns the details of a local or external extension
-     *
-     * @param string $extensionKey Key of the extension to check
-     *
-     * @return array Extension details
-     */
-    protected function getExtensionDetails($extensionKey)
-    {
-        if (array_key_exists($extensionKey, $this->extensionDetails)) {
-            return $this->extensionDetails[$extensionKey];
-        }
-
-        return [];
-    }
-
-    /**
      * Fetch extension from repository
      *
      * @param string $extensionKey The extension key to fetch
      * @param string $version The version to fetch
-     *
      * @throws \InvalidArgumentException
      * @return string T3X file content
      */
-    protected function fetchExtension($extensionKey, $version)
+    protected function fetchExtension($extensionKey, $version): string
     {
         if (empty($extensionKey) || empty($version)) {
             throw new \InvalidArgumentException(
@@ -150,17 +152,15 @@ abstract class AbstractDownloadExtensionUpdate extends AbstractUpdate
 
     /**
      * Open an URL and return the response
-     *
      * This wrapper method is required to try several download methods if
      * the configuration is not valid or initially written by the installer.
      *
      * @param string $url The URL to file
-     *
      * @throws \Exception
      * @throws \InvalidArgumentException
      * @return string File content
      */
-    protected function fetchUrl($url)
+    protected function fetchUrl($url): string
     {
         if (empty($url)) {
             throw new \InvalidArgumentException(
index 6c7fc89..f738e99 100644 (file)
@@ -17,111 +17,96 @@ namespace TYPO3\CMS\Install\Updates;
  */
 
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Installs EXT:adminpanel
  */
 class AdminPanelInstall extends AbstractDownloadExtensionUpdate
 {
+
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install extension "adminpanel"';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'adminpanel',
+            'TYPO3 Admin Panel',
+            '9.2',
+            'typo3/cms-adminpanel',
+            'The TYPO3 admin panel provides a panel with additional functionality in the frontend (Debugging, Caching, Preview...)'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install the "adminpanel" only if needed. ' . $this->extension->getDescription(),
+            true
+        );
+    }
 
     /**
-     * @var string
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'adminpanel';
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * @var array
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
      */
-    protected $extensionDetails = [
-        'adminpanel' => [
-            'title' => 'TYPO3 Admin Panel',
-            'description' => 'The TYPO3 admin panel provides a panel with additional functionality in the frontend (Debugging, Caching, Preview...)',
-            'versionString' => '9.2',
-            'composerName' => 'typo3/cms-adminpanel',
-        ],
-    ];
+    public function getIdentifier(): string
+    {
+        return 'adminpanelExtension';
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the speaking name of this wizard
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description): bool
+    public function getTitle(): string
     {
-        $description = 'The TYPO3 admin panel was extracted to an own extension. This update installs the extension.';
-
-        if (ExtensionManagementUtility::isLoaded('adminpanel')) {
-            $this->markWizardAsDone();
-        }
-
-        $updateNeeded = false;
-        if (!$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
-        return $updateNeeded;
+        return 'Install extension "adminpanel"';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:adminpanel only if you really need it.</p>
-                    <p>This update wizard cannot check if the extension was installed before the update.</p>
-                    <p>Are you really sure, you want to install EXT:adminpanel?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The TYPO3 admin panel was extracted to an own extension. This update installs the extension.';
     }
 
     /**
-     * Performs the update
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage): bool
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['adminpanelExtension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['adminpanelExtension']['install'];
+        return !ExtensionManagementUtility::isLoaded('adminpanel');
+    }
 
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+    /**
+     * 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
+    {
+        return [];
     }
 }
index b6aa71b..5d40248 100644 (file)
@@ -14,7 +14,7 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 
 /**
  * Installs and downloads EXT:compatibility7 if needed
@@ -44,80 +44,94 @@ class Compatibility7ExtractionUpdate extends AbstractDownloadExtensionUpdate
     ];
 
     /**
-     * Checks if an update is needed
-     *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @var \TYPO3\CMS\Install\Updates\ExtensionModel
+     */
+    protected $extension;
+
+    /**
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    public function checkForUpdate(&$description)
+    protected $confirmation;
+
+    public function __construct()
     {
-        $description = 'The extension "compatibility7" (Compatibility Mode for TYPO3 v7) was extracted into '
-            . 'the TYPO3 Extension Repository. This update downloads the TYPO3 Extension from the TER.';
+        $this->extension = new ExtensionModel(
+            'compatibility7',
+            'Compatibility Mode for TYPO3 v7',
+            '8.7.1',
+            'friendsoftypo3/compatibility7',
+            'Provides an additional backwards-compatibility layer with legacy functionality for sites that haven\'t fully migrated to TYPO3 v8 yet.'
+        );
 
-        $updateNeeded = false;
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'The compatibility extensions come with a performance penalty, use only if needed. ' . $this->extension->getDescription(),
+            false
+        );
+    }
 
-        if (!$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
+    /**
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
+     */
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
+
+    /**
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
+     */
+    public function getIdentifier(): string
+    {
+        return 'compatibility7Extension';
+    }
 
-        return $updateNeeded;
+    /**
+     * Return the speaking name of this wizard
+     *
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return 'Install compatibility extension for TYPO3 7 compatibility';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:compatibility7 only if you really need it.</p>
-                    <p>This update wizard cannot check if the extension was installed before the update.</p>
-                    <p>Are you really sure, you want to install EXT:compatibility7?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The extension "compatibility7" (Compatibility Mode for TYPO3 v7) was extracted into '
+               . 'the TYPO3 Extension Repository. This update downloads the TYPO3 Extension from the TER.';
     }
 
     /**
-     * Performs the update if EXT:compatibility7 should be installed.
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['compatibility7Extension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['compatibility7Extension']['install'];
+        return !ExtensionManagementUtility::isLoaded('compatibility7');
+    }
 
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+    /**
+     * 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
+    {
+        return [];
     }
 }
diff --git a/typo3/sysext/install/Classes/Updates/ExtensionModel.php b/typo3/sysext/install/Classes/Updates/ExtensionModel.php
new file mode 100644 (file)
index 0000000..ca8fdd9
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Install\Updates;
+
+/*
+ * 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!
+ */
+
+/**
+ * Model for extensions installed by upgrade wizards
+ *
+ * @internal
+ */
+class ExtensionModel
+{
+    protected $key = '';
+    protected $title = '';
+    protected $versionString = '';
+    protected $composerName = '';
+    protected $description = '';
+
+    public function __construct(
+        string $key,
+        string $title,
+        string $versionString,
+        string $composerName,
+        string $description
+    ) {
+        $this->key = $key;
+        $this->title = $title;
+        $this->versionString = $versionString;
+        $this->composerName = $composerName;
+        $this->description = $description;
+    }
+
+    public function getDescription(): string
+    {
+        return $this->description;
+    }
+
+    /**
+     * @return string
+     */
+    public function getKey(): string
+    {
+        return $this->key;
+    }
+
+    /**
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return $this->title;
+    }
+
+    /**
+     * @return string
+     */
+    public function getVersionString(): string
+    {
+        return $this->versionString;
+    }
+
+    /**
+     * @return string
+     */
+    public function getComposerName(): string
+    {
+        return $this->composerName;
+    }
+}
index 11c9f35..e8949b7 100644 (file)
@@ -25,41 +25,83 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class FormLegacyExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install extension "form_legacy" from TER';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'form_legacy',
+            'Legacy form extension for TYPO3 v7 compatibility',
+            '8.7.0',
+            'friendsoftypo3/form-legacy',
+            'Provides an additional backwards-compatibility layer with legacy functionality for sites that used the form extension in TYPO3 v7.'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you really sure, you want to install EXT:form_legacy?',
+            'You should install EXT:form_legacy only if you really need it.'
+                    . 'This update wizard checked all content elements and found at least one not deleted element based'
+                    . 'on the old form module. It is advised to manually convert those elements from the old form implementation'
+                    . 'to the new implementation of EXT:form. EXT:form_legacy should be unloaded and removed afterwards.',
+            true
+        );
+    }
 
     /**
-     * @var string
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'form_legacy';
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * @var array
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
      */
-    protected $extensionDetails = [
-        'form_legacy' => [
-            'title' => 'Legacy form extension for TYPO3 v7 compatibility',
-            'description' => 'Provides an additional backwards-compatibility layer with legacy functionality for sites that used the form extension in TYPO3 v7.',
-            'versionString' => '8.7.0',
-            'composerName' => 'friendsoftypo3/form-legacy',
-        ],
-    ];
+    public function getIdentifier(): string
+    {
+        return 'formLegacyExtractionUpdate';
+    }
+
+    /**
+     * Return the speaking name of this wizard
+     *
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return 'Install extension "form_legacy"';
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the description for this wizard
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description)
+    public function getDescription(): string
     {
-        $description = 'The extension "form" was rewritten in TYPO3 v8 and follows a new approach.'
-            . 'This update downloads the old implementation of the form extension as known from TYPO3 v7 from the TER.';
+        return 'The extension "form" was rewritten in TYPO3 v8 and follows a new approach.'
+        . 'This update downloads the old implementation of the form extension as known from TYPO3 v7 from the TER.';
+    }
 
+    /**
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
+     *
+     * @return bool
+     */
+    public function updateNecessary(): bool
+    {
         $updateNeeded = false;
 
-        if (!$this->isWizardDone() && !ExtensionManagementUtility::isLoaded('form_legacy')) {
+        if (!ExtensionManagementUtility::isLoaded('form_legacy')) {
             $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content');
             $queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
             $count = $queryBuilder
@@ -72,67 +114,20 @@ class FormLegacyExtractionUpdate extends AbstractDownloadExtensionUpdate
                 $updateNeeded = true;
             }
         }
-
         return $updateNeeded;
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * 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"
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string[]
      */
-    public function getUserInput($inputPrefix)
+    public function getPrerequisites(): array
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:form_legacy only if you really need it.</p>
-                    <p>This update wizard checked all content elements and found at least one not deleted element based
-                    on the old form module. It is advised to manually convert those elements from the old form implementation
-                    to the new implementation of EXT:form. EXT:form_legacy should be unloaded and removed afterwards.</p>
-                    <p>Are you really sure, you want to install EXT:form_legacy?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
-    }
-
-    /**
-     * Performs the update if EXT:form_legacy should be installed.
-     *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
-     * @return bool
-     */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
-    {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['formLegacyExtractionUpdate']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['formLegacyExtractionUpdate']['install'];
-
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+        return [
+            DatabaseUpdatedPrerequisite::class
+        ];
     }
 }
index 19001ca..bc1d9ba 100644 (file)
@@ -14,112 +14,100 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 
 /**
  * Installs and downloads EXT:func
  */
 class FuncExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
+
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install extension "func" from TER';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'func',
+            'Web->Functions module',
+            '9.0.1',
+            'friendsoftypo3/cms-func',
+            'Provides Web->Functions BE module used in previous TYPO3 versions for extensions that still rely on it.'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install EXT:func only if you really need it. ' . $this->extension->getDescription(),
+            false
+        );
+    }
 
     /**
-     * @var string
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'func';
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * @var array
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
      */
-    protected $extensionDetails = [
-        'func' => [
-            'title' => 'Web->Functions module',
-            'description' => 'Provides Web->Functions BE module used in previous TYPO3 versions for extensions that still rely on it.',
-            'versionString' => '9.0.1',
-            'composerName' => 'friendsoftypo3/cms-func',
-        ],
-    ];
+    public function getIdentifier(): string
+    {
+        return 'funcExtension';
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the speaking name of this wizard
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description)
+    public function getTitle(): string
     {
-        $description = 'The extension "func" that brings the "Web->Functions" backend module has been extracted to'
-            . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension func from the TER.'
-            . ' Use this if you\'re dealing with extensions in the instance that rely on "Web->Functions" and bring own'
-            . ' modules.';
-
-        $updateNeeded = false;
-
-        if (!$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
-
-        return $updateNeeded;
+        return 'Install extension "func" from TER';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:func only if you really need it.</p>
-                    <p>This update wizard cannot check if the extension was installed before the update.</p>
-                    <p>Are you really sure, you want to install EXT:func?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The extension "func" that brings the "Web->Functions" backend module has been extracted to'
+               . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension func from the TER.'
+               . ' Use this if you\'re dealing with extensions in the instance that rely on "Web->Functions" and bring own'
+               . ' modules.';
     }
 
     /**
-     * Performs the update if EXT:func should be installed.
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['funcExtension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['funcExtension']['install'];
+        return !ExtensionManagementUtility::isLoaded($this->extension->getKey());
+    }
 
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+    /**
+     * 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
+    {
+        return [];
     }
 }
index e31db5d..633f239 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Install\Updates;
  */
 
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -23,101 +24,84 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class RedirectExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\ExtensionModel
      */
-    protected $title = 'Install extension "rdct" from TER if DB table cache_md5params is filled';
+    protected $extension;
 
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'rdct';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+          'rdct',
+            'Redirects based on &RDCT parameter',
+            '1.0.0',
+            'friendsoftypo3/rdct',
+            'The extension provides redirects based on "cache_md5params" and the GET parameter &RDCT for extensions that still rely on it.'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install the Redirects extension only if needed. ' . $this->extension->getDescription(),
+            false
+        );
+    }
 
     /**
-     * @var array
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionDetails = [
-        'rdct' => [
-            'title' => 'Redirects based on &RDCT parameter',
-            'description' => 'Provides redirects based on "cache_md5params" and the GET parameter &RDCT for extensions that still rely on it.',
-            'versionString' => '1.0.0',
-            'composerName' => 'friendsoftypo3/rdct',
-        ],
-    ];
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description)
+    public function getIdentifier(): string
     {
-        $description = 'The extension "rdct" includes redirects based on the GET parameter &RDCT. The functionality has been extracted to'
-            . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension from the TER.'
-            . ' Use this if you are dealing with extensions in the instance that rely on this kind of redirects.';
-
-        $updateNeeded = false;
-
-        // Check if table exists and table is not empty, and the wizard has not been run already
-        if ($this->checkIfWizardIsRequired() && !$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
+        return 'rdctExtension';
+    }
 
-        return $updateNeeded;
+    /**
+     * Return the speaking name of this wizard
+     *
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return 'Install extension "rdct" from TER if DB table cache_md5params is filled';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:rdct only if you really need it.</p>
-                    <p>If you have never heard of index.php?RDCT then we are 99% confident that you don\'t need to install this extension.</p>
-                    <p>Are you really sure, you want to install EXT:rdct?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The extension "rdct" includes redirects based on the GET parameter &RDCT. The functionality has been extracted to'
+               . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension from the TER.'
+               . ' Use this if you are dealing with extensions in the instance that rely on this kind of redirects.';
     }
 
     /**
-     * Performs the update if EXT:rdct should be installed.
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['rdctExtension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['rdctExtension']['install'];
-
-        $updateSuccessful = true;
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-        }
-        if ($updateSuccessful) {
-            $this->markWizardAsDone();
-        }
-        return $updateSuccessful;
+        return !ExtensionManagementUtility::isLoaded('rdct') && $this->checkIfWizardIsRequired();
     }
 
     /**
@@ -144,4 +128,18 @@ class RedirectExtractionUpdate extends AbstractDownloadExtensionUpdate
 
         return false;
     }
+
+    /**
+     * 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
+    {
+        return [
+            DatabaseUpdatedPrerequisite::class
+        ];
+    }
 }
index 97c08b0..01adfae 100644 (file)
@@ -15,8 +15,6 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -24,47 +22,82 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Installs EXT:redirect if sys_domain.redirectTo is filled, and migrates the values from redirectTo
  * to a proper sys_redirect entry.
  */
-class RedirectsExtensionUpdate extends AbstractDownloadExtensionUpdate implements LoggerAwareInterface
+class RedirectsExtensionUpdate extends AbstractDownloadExtensionUpdate
 {
-    use LoggerAwareTrait;
-
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install system extension "redirects" if a sys_domain entry with redirectTo is necessary';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'redirects',
+            'Redirects',
+            '9.2',
+            'typo3/cms-redirects',
+            'Manage redirects for your TYPO3-based website'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install the "adminpanel" only if needed. ' . $this->extension->getDescription(),
+            true
+        );
+    }
 
     /**
-     * @var array
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionDetails = [
-        'redirects' => [
-            'title' => 'Redirects',
-            'description' => 'Manage redirects for your TYPO3-based website',
-            'versionString' => '9.2',
-            'composerName' => 'typo3/cms-redirects',
-        ],
-    ];
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description): bool
+    public function getIdentifier(): string
     {
-        $description = 'The extension "redirects" includes functionality to handle any kind of redirects. '
-            . 'The functionality superseds sys_domain entries with the only purpose of redirecting to a different domain or entry. '
-            . 'This upgrade wizard installs the redirect extension if necessary and migrates the sys_domain entries to standard redirects.';
+        return 'redirects';
+    }
 
-        $updateNeeded = false;
+    /**
+     * Return the speaking name of this wizard
+     *
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return 'Install system extension "redirects" if a sys_domain entry with redirectTo is necessary';
+    }
 
-        // Check if table exists and table is not empty, and the wizard has not been run already
-        if ($this->checkIfWizardIsRequired() && !$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
+    /**
+     * Return the description for this wizard
+     *
+     * @return string
+     */
+    public function getDescription(): string
+    {
+        return 'The extension "redirects" includes functionality to handle any kind of redirects. '
+               . 'The functionality superseds sys_domain entries with the only purpose of redirecting to a different domain or entry. '
+               . 'This upgrade wizard installs the redirect extension if necessary and migrates the sys_domain entries to standard redirects.';
+    }
 
-        return $updateNeeded;
+    /**
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
+     *
+     * @return bool
+     */
+    public function updateNecessary(): bool
+    {
+        return $this->checkIfWizardIsRequired();
     }
 
     /**
@@ -72,18 +105,15 @@ class RedirectsExtensionUpdate extends AbstractDownloadExtensionUpdate implement
      * - Install EXT:redirect
      * - Migrate DB records
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage): bool
+    public function executeUpdate(): bool
     {
         // Install the EXT:redirects extension if not happened yet
-        $installationSuccessful = $this->installExtension('redirects', $customMessage);
+        $installationSuccessful = $this->installExtension($this->extension->getKey());
         if ($installationSuccessful) {
             // Migrate the database entries
             $this->migrateRedirectDomainsToSysRedirect();
-            $this->markWizardAsDone();
         }
         return $installationSuccessful;
     }
@@ -172,4 +202,18 @@ class RedirectsExtensionUpdate extends AbstractDownloadExtensionUpdate implement
             $connDomains->delete('sys_domain', ['uid' => (int)$domainEntry['uid']]);
         }
     }
+
+    /**
+     * 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
+    {
+        return [
+            DatabaseUpdatedPrerequisite::class
+        ];
+    }
 }
index e1604d2..54d4746 100644 (file)
@@ -14,7 +14,7 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 
 /**
  * Installs and downloads EXT:rtehtmlarea if needed
@@ -22,103 +22,90 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class RteHtmlAreaExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install extension "rtehtmlarea" from TER';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'rtehtmlarea',
+            'RTE HTMLArea for TYPO3',
+            '8.7.0',
+            'friendsoftypo3/rtehtmlarea',
+            'The extension provides the well-known RTE used in previous TYPO3 versions, if handling of images or custom legacy configurations are necessary.'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install EXT:rtehtmlarea only if you really need it. ' . $this->extension->getDescription(),
+            false
+        );
+    }
 
     /**
-     * @var string
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'rtehtmlarea';
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * @var array
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
      */
-    protected $extensionDetails = [
-        'rtehtmlarea' => [
-            'title' => 'RTE HTMLArea for TYPO3',
-            'description' => 'Provides the well-known RTE used in previous TYPO3 versions, if handling of images or custom configurations are necessary.',
-            'versionString' => '8.7.0',
-            'composerName' => 'friendsoftypo3/rtehtmlarea',
-        ],
-    ];
+    public function getIdentifier(): string
+    {
+        return 'rtehtmlareaExtension';
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the speaking name of this wizard
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description)
+    public function getTitle(): string
     {
-        $description = 'The extension "rtehtmlarea" (RTE based on HtmlArea) was extracted into'
-            . ' the TYPO3 Extension Repository. This update downloads the TYPO3 Extension from the TER.'
-            . ' Use this if you have special configurations or image handling within Rich Text fields and uninstall the shipped EXT:rte_ckeditor.';
-
-        $updateNeeded = false;
-
-        if (!$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
-
-        return $updateNeeded;
+        return 'Install extension "rtehtmlarea" from TER';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:rtehtmlarea only if you really need it.</p>
-                    <p>This update wizard cannot check if the extension was installed before the update.</p>
-                    <p>Are you really sure, you want to install EXT:rtehtmlarea?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The extension "rtehtmlarea" (RTE based on HtmlArea) was extracted into'
+               . ' the TYPO3 Extension Repository. This update downloads the TYPO3 Extension from the TER.'
+               . ' Use this if you have special configurations or image handling within Rich Text fields and uninstall the shipped EXT:rte_ckeditor.';
     }
 
     /**
-     * Performs the update if EXT:compatibility7 should be installed.
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['rtehtmlareaExtension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['rtehtmlareaExtension']['install'];
+        return !ExtensionManagementUtility::isLoaded('rtehtmlarea');
+    }
 
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+    /**
+     * 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
+    {
+        return [];
     }
 }
index a96ac13..9602a60 100644 (file)
@@ -14,7 +14,7 @@ namespace TYPO3\CMS\Install\Updates;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 
 /**
  * Installs and downloads EXT:typo3db_legacy
@@ -22,103 +22,90 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 class Typo3DbExtractionUpdate extends AbstractDownloadExtensionUpdate
 {
     /**
-     * @var string
+     * @var \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $title = 'Install extension "typo3db_legacy" from TER';
+    protected $confirmation;
+
+    public function __construct()
+    {
+        $this->extension = new ExtensionModel(
+            'typo3db_legacy',
+            '$GLOBALS[\'TYPO3_DB\'] compatibility layer',
+            '1.0.1',
+            'friendsoftypo3/typo3db-legacy',
+            'This extension provides the well-known database API $GLOBALS[\'TYPO3_DB\'] used in previous TYPO3 versions for extensions that still rely on it.'
+        );
+
+        $this->confirmation = new Confirmation(
+            'Are you sure?',
+            'You should install EXT:typo3db_legacy only if you really need it. ' . $this->extension->getDescription(),
+            false
+        );
+    }
 
     /**
-     * @var string
+     * Return a confirmation message instance
+     *
+     * @return \TYPO3\CMS\Install\Updates\Confirmation
      */
-    protected $extensionKey = 'typo3db_legacy';
+    public function getConfirmation(): Confirmation
+    {
+        return $this->confirmation;
+    }
 
     /**
-     * @var array
+     * Return the identifier for this wizard
+     * This should be the same string as used in the ext_localconf class registration
+     *
+     * @return string
      */
-    protected $extensionDetails = [
-        'typo3db_legacy' => [
-            'title' => '$GLOBALS[\'TYPO3_DB\'] compatibility layer',
-            'description' => 'Provides the well-known database API $GLOBALS[\'TYPO3_DB\'] used in previous TYPO3 versions for extensions that still rely on it.',
-            'versionString' => '1.0.1',
-            'composerName' => 'friendsoftypo3/typo3db-legacy',
-        ],
-    ];
+    public function getIdentifier(): string
+    {
+        return 'typo3DbLegacyExtension';
+    }
 
     /**
-     * Checks if an update is needed
+     * Return the speaking name of this wizard
      *
-     * @param string $description The description for the update
-     * @return bool Whether an update is needed (true) or not (false)
+     * @return string
      */
-    public function checkForUpdate(&$description)
+    public function getTitle(): string
     {
-        $description = 'The old database API populated as $GLOBALS[\'TYPO3_DB\'] has been extracted into'
-            . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension typo3db_legacy from the TER.'
-            . ' Use this if you\'re dealing with extensions in the instance that still rely on the old database API.';
-
-        $updateNeeded = false;
-
-        if (!$this->isWizardDone()) {
-            $updateNeeded = true;
-        }
-
-        return $updateNeeded;
+        return 'Install extension "typo3db_legacy" from TER';
     }
 
     /**
-     * Second step: Ask user to install the extension
+     * Return the description for this wizard
      *
-     * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
-     * @return string HTML output
+     * @return string
      */
-    public function getUserInput($inputPrefix)
+    public function getDescription(): string
     {
-        return '
-            <div class="panel panel-danger">
-                <div class="panel-heading">Are you really sure?</div>
-                <div class="panel-body">
-                    <p>You should install EXT:typo3db_legacy only if you really need it.</p>
-                    <p>This update wizard cannot check if the extension was installed before the update.</p>
-                    <p>Are you really sure, you want to install EXT:typo3db_legacy?</p>
-                    <div class="btn-group clearfix" data-toggle="buttons">
-                        <label class="btn btn-default active">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="0" checked="checked" /> no, don\'t install
-                        </label>
-                        <label class="btn btn-default">
-                            <input type="radio" name="' . $inputPrefix . '[install]" value="1" /> yes, please install
-                        </label>
-                    </div>
-                </div>
-            </div>
-        ';
+        return 'The old database API populated as $GLOBALS[\'TYPO3_DB\'] has been extracted into'
+               . ' the TYPO3 Extension Repository. This update downloads the TYPO3 extension typo3db_legacy from the TER.'
+               . ' Use this if you\'re dealing with extensions in the instance that still rely on the old database API.';
     }
 
     /**
-     * Performs the update if EXT:typo3db_legacy should be installed.
+     * Is an update necessary?
+     * Is used to determine whether a wizard needs to be run.
      *
-     * @param array $databaseQueries Queries done in this update
-     * @param string $customMessage Custom message
      * @return bool
      */
-    public function performUpdate(array &$databaseQueries, &$customMessage)
+    public function updateNecessary(): bool
     {
-        $requestParams = GeneralUtility::_GP('install');
-        if (!isset($requestParams['values']['typo3DbLegacyExtension']['install'])) {
-            return false;
-        }
-        $install = (int)$requestParams['values']['typo3DbLegacyExtension']['install'];
+        return !ExtensionManagementUtility::isLoaded($this->extension->getKey());
+    }
 
-        if ($install === 1) {
-            // user decided to install extension, install and mark wizard as done
-            $updateSuccessful = $this->installExtension($this->extensionKey, $customMessage);
-            if ($updateSuccessful) {
-                $this->markWizardAsDone();
-                return true;
-            }
-        } else {
-            // user decided to not install extension, mark wizard as done
-            $this->markWizardAsDone();
-            return true;
-        }
-        return $updateSuccessful;
+    /**
+     * 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
+    {
+        return [];
     }
 }
index 67e0bb3..e1934f2 100644 (file)
@@ -58,53 +58,14 @@ class Compatibility7ExtractionUpdateTest extends UnitTestCase
     {
         $this->registry->get('installUpdate', Compatibility7ExtractionUpdate::class, false)->willReturn(false);
         $subject = new Compatibility7ExtractionUpdate();
-        $description = '';
-        $this->assertTrue($subject->checkForUpdate($description));
+        $this->assertTrue($subject->updateNecessary());
     }
 
     /**
      * @test
      */
-    public function checkForUpdateReturnsFalseIfWizardIsMarkedAsDone()
+    public function performUpdateInstallsExtensionUponRequest()
     {
-        $this->registry->get('installUpdate', Compatibility7ExtractionUpdate::class, false)->willReturn(true);
-        $subject = new Compatibility7ExtractionUpdate();
-        $description = '';
-        $this->assertFalse($subject->checkForUpdate($description));
-    }
-
-    /**
-     * @test
-     */
-    public function performUpdateReturnsFalseIfNoUserInputWasFound()
-    {
-        $_GET['install'] = [];
-        $subject = new Compatibility7ExtractionUpdate();
-        $databaseQueries = [];
-        $customMessage = '';
-        $this->assertFalse($subject->performUpdate($databaseQueries, $customMessage));
-    }
-
-    /**
-     * @test
-     */
-    public function performUpdateReturnsTrueIfUserDeclinesInstallAndMarksWizardDone()
-    {
-        $_GET['install']['values']['compatibility7Extension']['install'] = 0;
-        $subject = new Compatibility7ExtractionUpdate();
-        $databaseQueries = [];
-        $customMessage = '';
-        $this->assertTrue($subject->performUpdate($databaseQueries, $customMessage));
-        $this->registry->set('installUpdate', Compatibility7ExtractionUpdate::class, 1)->shouldHaveBeenCalled();
-    }
-
-    /**
-     * @test
-     */
-    public function performUpdateInstallsExtensionUponRequestAndMarksWizardDone()
-    {
-        $_GET['install']['values']['compatibility7Extension']['install'] = 1;
-
         $objectManager = $this->prophesize(ObjectManager::class);
         GeneralUtility::setSingletonInstance(ObjectManager::class, $objectManager->reveal());
 
@@ -115,12 +76,10 @@ class Compatibility7ExtractionUpdateTest extends UnitTestCase
         $extensionList = ['compatibility7' => ['foo' => 'bar']];
         $listUtility->getAvailableExtensions()->willReturn($extensionList);
         $listUtility->getAvailableAndInstalledExtensions($extensionList)->willReturn($extensionList);
-        $installUtility->install('compatibility7')->shouldBeCalled();
 
         $subject = new Compatibility7ExtractionUpdate();
-        $databaseQueries = [];
-        $customMessage = '';
-        $this->assertTrue($subject->performUpdate($databaseQueries, $customMessage));
-        $this->registry->set('installUpdate', Compatibility7ExtractionUpdate::class, 1)->shouldHaveBeenCalled();
+        $this->assertTrue($subject->executeUpdate());
+
+        $installUtility->install('compatibility7')->shouldHaveBeenCalled();
     }
 }