From d8c77f7eb9a47bff1a497eefe902a63c00bcf7ba Mon Sep 17 00:00:00 2001
From: Nicole Cordes <typo3@cordes.co>
Date: Mon, 12 Oct 2015 16:04:50 +0200
Subject: [PATCH] [TASK] Decouple extension setup from installation

This patch introduces an API which does all necessary setup steps for an
extension without activating it or clearing the caches. This is useful
in deployment scenarios as well as enhancing the composer
usage experience.

The patch
* adds an own cache for available extension information in ListUtility
* decouples the function to retrieve basic extension information
* adds an api method to setup an extension

Resolves: #70606
Releases: master
Change-Id: I7b535cf0a17cfa7c6c68ed67486ce04a5cabbfc0
Reviewed-on: http://review.typo3.org/44011
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
Tested-by: Helmut Hummel <helmut.hummel@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
---
 .../Classes/Utility/InstallUtility.php        | 39 ++++++++++++++-----
 .../Classes/Utility/ListUtility.php           | 29 ++++++++------
 .../Tests/Unit/Utility/InstallUtilityTest.php |  5 +++
 3 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
index c77316950142..ee2c5b0d5e82 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
@@ -14,8 +14,9 @@ namespace TYPO3\CMS\Extensionmanager\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Service\OpcodeCacheService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
 use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
 use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
@@ -187,13 +188,21 @@ class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface
             $this->cacheManager->flushCachesInGroup('system');
         }
         $this->reloadCaches();
+        $this->processExtensionSetup($extensionKey);
+
+        $this->emitAfterExtensionInstallSignal($extensionKey);
+    }
 
+    /**
+     * @param string $extensionKey
+     */
+    public function processExtensionSetup($extensionKey)
+    {
+        $extension = $this->getExtensionArray($extensionKey);
         $this->importInitialFiles($extension['siteRelPath'], $extensionKey);
         $this->processDatabaseUpdates($extension);
         $this->processRuntimeDatabaseUpdates($extensionKey);
-        $this->saveDefaultConfiguration($extension['key']);
-
-        $this->emitAfterExtensionInstallSignal($extensionKey);
+        $this->saveDefaultConfiguration($extensionKey);
     }
 
     /**
@@ -313,12 +322,7 @@ class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface
      */
     public function enrichExtensionWithDetails($extensionKey)
     {
-        $availableExtensions = $this->listUtility->getAvailableExtensions();
-        if (isset($availableExtensions[$extensionKey])) {
-            $extension = $availableExtensions[$extensionKey];
-        } else {
-            throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
-        }
+        $extension = $this->getExtensionArray($extensionKey);
         $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(array($extensionKey => $extension));
 
         if (!isset($availableAndInstalledExtensions[$extensionKey])) {
@@ -331,6 +335,21 @@ class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface
         return $availableAndInstalledExtensions[$extensionKey];
     }
 
+    /**
+     * @param string $extensionKey
+     * @return array
+     * @throws ExtensionManagerException
+     */
+    protected function getExtensionArray($extensionKey)
+    {
+        $availableExtensions = $this->listUtility->getAvailableExtensions();
+        if (isset($availableExtensions[$extensionKey])) {
+            return $availableExtensions[$extensionKey];
+        } else {
+            throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
+        }
+    }
+
     /**
      * Creates directories as requested in ext_emconf.php
      *
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
index 8978b125f1b5..59c57898c4be 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
@@ -55,6 +55,11 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface
      */
     protected $signalSlotDispatcher;
 
+    /**
+     * @var array
+     */
+    protected $availableExtensions = NULL;
+
     /**
      * @param \TYPO3\CMS\Extensionmanager\Utility\EmConfUtility $emConfUtility
      */
@@ -102,18 +107,20 @@ class ListUtility implements \TYPO3\CMS\Core\SingletonInterface
      */
     public function getAvailableExtensions()
     {
-        $this->emitPackagesMayHaveChangedSignal();
-        $extensions = array();
-        foreach ($this->packageManager->getAvailablePackages() as $package) {
-            $installationType = $this->getInstallTypeForPackage($package);
-            $extensions[$package->getPackageKey()] = array(
-                'siteRelPath' => str_replace(PATH_site, '', $package->getPackagePath()),
-                'type' => $installationType,
-                'key' => $package->getPackageKey(),
-                'ext_icon' => ExtensionManagementUtility::getExtensionIcon($package->getPackagePath()),
-            );
+        if ($this->availableExtensions === NULL) {
+            $this->emitPackagesMayHaveChangedSignal();
+            foreach ($this->packageManager->getAvailablePackages() as $package) {
+                $installationType = $this->getInstallTypeForPackage($package);
+                $this->availableExtensions[$package->getPackageKey()] = array(
+                    'siteRelPath' => str_replace(PATH_site, '', $package->getPackagePath()),
+                    'type' => $installationType,
+                    'key' => $package->getPackageKey(),
+                    'ext_icon' => ExtensionManagementUtility::getExtensionIcon($package->getPackagePath()),
+                );
+            }
         }
-        return $extensions;
+
+        return $this->availableExtensions;
     }
 
     /**
diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php
index caab13c97353..ede4169ed25e 100644
--- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php
+++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/InstallUtilityTest.php
@@ -59,6 +59,7 @@ class InstallUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                 'reloadCaches',
                 'processCachingFrameworkUpdates',
                 'saveDefaultConfiguration',
+                'getExtensionArray',
                 'enrichExtensionWithDetails',
                 'ensureConfiguredDirectoriesExist',
                 'importInitialFiles',
@@ -70,6 +71,10 @@ class InstallUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         );
         $dependencyUtility = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class);
         $this->installMock->_set('dependencyUtility', $dependencyUtility);
+        $this->installMock->expects($this->any())
+            ->method('getExtensionArray')
+            ->with($this->extensionKey)
+            ->will($this->returnCallback(array($this, 'getExtensionData')));
         $this->installMock->expects($this->any())
             ->method('enrichExtensionWithDetails')
             ->with($this->extensionKey)
-- 
GitLab