[FEATURE] Add new extension manager to the core
authorSusanne Moog <typo3@susanne-moog.de>
Sun, 12 Aug 2012 12:29:09 +0000 (14:29 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Fri, 17 Aug 2012 16:38:16 +0000 (18:38 +0200)
For 6.0 a new extension manager based on
extbase was developed. Goal of this extension
manager is not to be the most feature rich
but easy to use extension managers.

Therefore the whole extension manager was
restructured and some features where removed:
* language handling -> will be an own extension
* file editing -> can be done via other extensions
* upload extension -> will be integrated into extdeveval

This patch adds the base extension manager.
Styling and JS fine tuning will be done afterwards.

Please test the given functionality carefully and
report as many bugs as you can find to the project
at forge (TYPO3 6.0 > Extension Manager).

Change-Id: I28ef14401f40e239e5ea235af2be3e431fb8789d
Resolves: #39726
Releases: 6.0
Reviewed-on: http://review.typo3.org/13612
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
114 files changed:
t3lib/core_autoload.php
t3lib/utility/class.t3lib_utility_string.php [new file with mode: 0644]
t3lib/utility/class.t3lib_utility_versionnumber.php
tests/Unit/t3lib/utility/class.t3lib_utility_stringTest.php [new file with mode: 0644]
tests/Unit/t3lib/utility/class.t3lib_utility_versionNumberTest.php
typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/ActionController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/DownloadController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/ListController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/UpdateFromTerController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationCategory.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationItem.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationSubcategory.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/Dependency.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/DownloadQueue.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/Extension.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/Mirrors.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Model/Repository.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Repository/ConfigurationItemRepository.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Repository/ExtensionRepository.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Domain/Repository/RepositoryRepository.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Exception/ExtensionManager.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Service/Management.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Configuration.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Connection/Ter.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Database.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Dependency.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Download.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/EmConf.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/FileHandling.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Importer/ExtensionList.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Importer/MirrorList.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Install.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/List.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlAbstractParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPullParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlAbstractParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPullParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/XmlAbstractParser.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Parser/XmlParserFactory.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/Utility/Repository/Helper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/Be/ContainerViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/ConfigureExtensionViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/DownloadExtensionDataViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/DownloadExtensionViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/Form/TypoScriptConstantsViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/Format/ImplodeViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/Format/JsonEncodeViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/ImageViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/InstallationStateCssClassViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/RemoveExtensionViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/ShowExtensionVersionsViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/ToggleExtensionInstallationStateViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Classes/ViewHelpers/UpdateFromTerViewHelper.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Configuration/TCA/Extension.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Language/locallang.xlf [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Language/locallang_db.xml [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Language/locallang_mod.xlf [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Layouts/Main.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Partials/List/TerPaginator.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Partials/List/TerShowVersionsSingleLine.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Partials/List/TerShowVersionsTable.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Partials/List/TerSingleLine.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Partials/List/TerTable.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Action/RemoveExtension.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Configuration/ShowConfigurationForm.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Download/CheckDependencies.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Download/InstallFromTer.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Download/UpdateCommentForUpdatableVersions.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/Download/UpdateExtension.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/List/Index.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/List/ShowAllVersions.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/List/Ter.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/List/Ter.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/UpdateFromTer/UpdateExtensionListFromTer.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/UploadExtensionFile/Extract.json [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Private/Templates/UploadExtensionFile/Form.html [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/Farbtastic/LICENSE.txt [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/Farbtastic/farbtastic.css [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/Farbtastic/farbtastic.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/LoadMask/jquery.loadmask.css [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/LoadMask/jquery.loadmask.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Contrib/LoadMask/jquery.loadmask.min.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Css/jquery-ui-1.8.17.custom.css [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/Css/main.css [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/configuration.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery-ui-1.8.17.custom.min.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/jquery.tools.min.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/main.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/ter.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/update.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Resources/Public/JavaScript/upload.js [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Controller/UpdateFromTerControllerTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Domain/Model/DownloadQueueTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Repository/ConfigurationItemRepositoryTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Service/ManagementTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Utility/DependencyTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Utility/EmConfTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Utility/FilehandlingTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Utility/InstallTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/Tests/Utility/ListTest.php [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_emconf.php [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_icon.gif [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_localconf.php [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_tables.php [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_tables.sql [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_tables_static+adt.sql [new file with mode: 0644]
typo3/sysext/extensionmanager/ext_typoscript_setup.txt [new file with mode: 0644]
typo3/sysext/extensionmanager/info.txt [new file with mode: 0644]

index 1fd1a05..4eb0015 100644 (file)
@@ -308,6 +308,7 @@ $t3libClasses = array(
        't3lib_userauth' => PATH_t3lib . 'class.t3lib_userauth.php',
        't3lib_userauthgroup' => PATH_t3lib . 'class.t3lib_userauthgroup.php',
        't3lib_utility_array' => PATH_t3lib . 'utility/class.t3lib_utility_array.php',
+       't3lib_utility_string' => PATH_t3lib . 'utility/class.t3lib_utility_string.php',
        't3lib_utility_client' => PATH_t3lib . 'utility/class.t3lib_utility_client.php',
        't3lib_utility_command' => PATH_t3lib . 'utility/class.t3lib_utility_command.php',
        't3lib_utility_debug' => PATH_t3lib . 'utility/class.t3lib_utility_debug.php',
diff --git a/t3lib/utility/class.t3lib_utility_string.php b/t3lib/utility/class.t3lib_utility_string.php
new file mode 100644 (file)
index 0000000..b033679
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2011 Susanne Moog <typo3@susanne-moog.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ * A copy is found in the textfile GPL.txt and important notices to the license
+ * from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Class with helper functions for string handling
+ *
+ * @author Susanne Moog <typo3@susanne-moog.de>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+final class t3lib_utility_String {
+
+       /**
+        * Returns TRUE if $haystack ends with $needle.
+        * The input string is not trimmed before and search
+        * is done case sensitive.
+        *
+        * @param string $haystack Full string to check
+        * @param string $needle Reference string which must be found as the "last part" of the full string
+        * @return boolean TRUE if $needle was found to be equal to the last part of $str
+        */
+       public static function isLastPartOfString($haystack, $needle) {
+               $stringLength = strlen($haystack);
+               $needleLength = strlen($needle);
+               return strrpos((string)$haystack, (string)$needle, 0) === ($stringLength - $needleLength);
+       }
+
+}
+?>
\ No newline at end of file
index d145473..7ab92f4 100644 (file)
@@ -32,7 +32,7 @@
  * @package TYPO3
  * @subpackage t3lib
  */
-final class t3lib_utility_VersionNumber {
+class t3lib_utility_VersionNumber {
 
        /**
         * Returns an integer from a three part version number, eg '4.12.3' -> 4012003
@@ -68,6 +68,147 @@ final class t3lib_utility_VersionNumber {
                );
                return intval($parts[0]) . '.' . intval($parts[1]) . '.' . intval($parts[2]);
        }
+
+       /**
+        * Splits a version range into an array.
+        *
+        * If a single version number is given, it is considered a minimum value.
+        * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
+        * If no version can be parsed "0.0.0" — "0.0.0" is the result
+        *
+        * @param string $version A string with a version range.
+        * @return array
+        */
+       public static function splitVersionRange($version) {
+               $versionRange = array();
+               if (strstr($version, '-')) {
+                       $versionRange = explode('-', $version, 2);
+               } else {
+                       $versionRange[0] = $version;
+                       $versionRange[1] = '';
+               }
+
+               if (!$versionRange[0]) {
+                       $versionRange[0] = '0.0.0';
+               }
+               if (!$versionRange[1]) {
+                       $versionRange[1] = '0.0.0';
+               }
+
+               return $versionRange;
+       }
+
+       /**
+        * Removes -dev -alpha -beta -RC states from a version number
+        * and replaces them by .0
+        *
+        * @static
+        * @return string
+        */
+       public static function getNumericTypo3Version() {
+               $t3version = static::getTypo3Version();
+               if (stripos($t3version, '-dev')
+                       || stripos($t3version, '-alpha')
+                       || stripos($t3version, '-beta')
+                       || stripos($t3version, '-RC')) {
+                               // find the last occurence of "-" and replace that part with a ".0"
+                       $t3version = substr($t3version, 0, strrpos($t3version, '-')) . '.0';
+               }
+               return $t3version;
+       }
+
+       /**
+        * Wrapper function for TYPO3_version constant to make functions using
+        * the constant unit testable
+        *
+        * @static
+        * @return string
+        */
+       protected static function getTypo3Version() {
+               return TYPO3_version;
+       }
+
+       /**
+        * This function converts version range strings (like '4.2.0-4.4.99') to an array
+        * (like array('4.2.0', '4.4.99'). It also forces each version part to be between
+        * 0 and 999
+        *
+        * @param string $versionsString
+        * @return array
+        */
+       public static function convertVersionsStringToVersionNumbers($versionsString) {
+               $versions = t3lib_div::trimExplode('-', $versionsString);
+               for ($i = 0; $i < count($versions); $i++) {
+                       $cleanedVersion = t3lib_div::trimExplode('.', $versions[$i]);
+                       for ($j = 0; $j < count($cleanedVersion); $j++) {
+                               $cleanedVersion[$j] = t3lib_utility_Math::forceIntegerInRange($cleanedVersion[$j], 0, 999);
+                       }
+                       $cleanedVersionString = implode('.', $cleanedVersion);
+                       if (static::convertVersionNumberToInteger($cleanedVersionString) === 0) {
+                               $cleanedVersionString = '';
+                       }
+                       $versions[$i] = $cleanedVersionString;
+               }
+               return $versions;
+       }
+
+       /**
+        * Parses the version number x.x.x and returns an array with the various parts.
+        * It also forces each … 0 to 999
+        *
+        * @param string $version Version code, x.x.x
+        * @return array
+        */
+       public static function convertVersionStringToArray($version) {
+               $parts = t3lib_div::intExplode('.', $version . '..');
+               $parts[0] = t3lib_utility_Math::forceIntegerInRange($parts[0], 0, 999);
+               $parts[1] = t3lib_utility_Math::forceIntegerInRange($parts[1], 0, 999);
+               $parts[2] = t3lib_utility_Math::forceIntegerInRange($parts[2], 0, 999);
+
+               $result = array();
+               $result['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2];
+               $result['version_int'] = intval($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]);
+               $result['version_main'] = $parts[0];
+               $result['version_sub'] = $parts[1];
+               $result['version_dev'] = $parts[2];
+
+               return $result;
+       }
+
+       /**
+        * Method to raise a version number
+        *
+        * @param string $raise one of "main", "sub", "dev" - the version part to raise by one
+        * @param string $version (like 4.1.20)
+        * @return string
+        * @throws t3lib_exception
+        */
+       public static function raiseVersionNumber($raise, $version) {
+               if (!in_array($raise, array('main', 'sub', 'dev'))) {
+                       throw new t3lib_exception('RaiseVersionNumber expects one of "main", "sub" or "dev".', 1342639555);
+               }
+               $parts = t3lib_div::intExplode('.', $version . '..');
+               $parts[0] = t3lib_utility_Math::forceIntegerInRange($parts[0], 0, 999);
+               $parts[1] = t3lib_utility_Math::forceIntegerInRange($parts[1], 0, 999);
+               $parts[2] = t3lib_utility_Math::forceIntegerInRange($parts[2], 0, 999);
+
+               switch ((string)$raise) {
+                       case 'main':
+                               $parts[0]++;
+                               $parts[1] = 0;
+                               $parts[2] = 0;
+                               break;
+                       case 'sub':
+                               $parts[1]++;
+                               $parts[2] = 0;
+                               break;
+                       case 'dev':
+                               $parts[2]++;
+                               break;
+               }
+               return $parts[0] . '.' . $parts[1] . '.' . $parts[2];
+       }
+
 }
 
 ?>
\ No newline at end of file
diff --git a/tests/Unit/t3lib/utility/class.t3lib_utility_stringTest.php b/tests/Unit/t3lib/utility/class.t3lib_utility_stringTest.php
new file mode 100644 (file)
index 0000000..08ca71e
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2011 Susanne Moog <typo3@susanne-moog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Testcase for class t3lib_utility_string
+ *
+ * @author Susanne Moog <typo3@susanne-moog.de>
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_utility_StringTest extends tx_phpunit_testcase {
+
+       /**
+        * Data provider for isLastPartOfStrReturnsTrueForMatchingLastParts
+        *
+        * @return array
+        */
+       public function isLastPartOfStringReturnsTrueForMatchingFirstPartDataProvider() {
+               return array(
+                       'match last part of string' => array('hello world', 'world'),
+                       'match last char of string' => array('hellod world', 'd'),
+                       'match whole string' => array('hello', 'hello'),
+                       'integer is part of string with same number' => array('24', 24),
+                       'string is part of integer with same number' => array(24, '24'),
+                       'integer is part of string starting with same number' => array('please gimme beer, 24', 24),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider isLastPartOfStringReturnsTrueForMatchingFirstPartDataProvider
+        */
+       public function isLastPartOfStringReturnsTrueForMatchingFirstPart($string, $part) {
+               $this->assertTrue(t3lib_utility_String::isLastPartOfString($string, $part));
+       }
+
+       /**
+        * Data provider for checkisLastPartOfStringReturnsFalseForNotMatchingFirstParts
+        *
+        * @return array
+        */
+       public function isLastPartOfStringReturnsFalseForNotMatchingFirstPartDataProvider() {
+               return array(
+                       'no string match' => array('hello', 'bye'),
+                       'no case sensitive string match' => array('hello world', 'World'),
+                       'array is not part of string' => array('string', array()),
+                       'string is not part of array' => array(array(), 'string'),
+                       'NULL is not part of string' => array('string', NULL),
+                       'string is not part of array' => array(NULL, 'string'),
+                       'NULL is not part of array' => array(array(), NULL),
+                       'array is not part of string' => array(NULL, array()),
+                       'NULL is not part of empty string' => array('', NULL),
+                       'false is not part of empty string' => array('', FALSE),
+                       'empty string is not part of NULL' => array(NULL, ''),
+                       'empty string is not part of false' => array(FALSE, ''),
+                       'empty string is not part of zero integer' => array(0, ''),
+                       'zero integer is not part of NULL' => array(NULL, 0),
+                       'zero integer is not part of empty string' => array('', 0),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider isLastPartOfStringReturnsFalseForNotMatchingFirstPartDataProvider
+        */
+       public function isLastPartOfStringReturnsFalseForNotMatchingFirstPart($string, $part) {
+               $this->assertFalse(t3lib_utility_String::isLastPartOfString($string, $part));
+       }
+
+}
+
+?>
\ No newline at end of file
index 11f2963..b94f4e4 100644 (file)
@@ -34,7 +34,7 @@ class t3lib_utility_VersionNumberTest extends tx_phpunit_testcase {
        /**
         * Data Provider for convertVersionNumberToIntegerConvertsVersionNumbersToIntegers
         *
-        * return array
+        * @return array
         */
        public function validVersionNumberDataProvider() {
                return array(
@@ -50,7 +50,7 @@ class t3lib_utility_VersionNumberTest extends tx_phpunit_testcase {
         * Data Provider for convertIntegerToVersionNumberConvertsOtherTypesAsIntegerToVersionNumber
         *
         * @see http://php.net/manual/en/language.types.php
-        * return array
+        * @return array
         */
        public function invalidVersionNumberDataProvider() {
                return array(
@@ -90,6 +90,95 @@ class t3lib_utility_VersionNumberTest extends tx_phpunit_testcase {
                $this->setExpectedException('\InvalidArgumentException', '', 1334072223);
                t3lib_utility_VersionNumber::convertIntegerToVersionNumber($version);
        }
+
+       /**
+        * @return array
+        */
+       public function getNumericTypo3VersionNumberDataProvider() {
+               return array(
+                       array(
+                               '6.0-dev',
+                               '6.0.0'
+                       ),
+                       array(
+                               '4.5-alpha',
+                               '4.5.0'
+                       ),
+                       array(
+                               '4.5-beta',
+                               '4.5.0'
+                       ),
+                       array(
+                               '4.5-RC',
+                               '4.5.0'
+                       ),
+                       array(
+                               '6.0.1',
+                               '6.0.1'
+                       ),
+               );
+       }
+
+       /**
+        * Check whether getNumericTypo3Version handles all kinds of valid
+        * version strings
+        *
+        * @dataProvider getNumericTypo3VersionNumberDataProvider
+        * @test
+        * @param string $currentVersion
+        * @param string $expectedVersion
+        */
+       public function getNumericTypo3VersionNumber($currentVersion, $expectedVersion) {
+               $className = uniqid('t3lib_utility_VersionNumber');
+               eval(
+                       'class ' . $className . ' extends t3lib_utility_VersionNumber {' .
+                       '  protected static function getTypo3Version() {' .
+                       '    return \'' . $currentVersion . '\';' .
+                       '  }' .
+                       '}'
+               );
+               $version = $className::getNumericTypo3Version();
+               $this->assertEquals($expectedVersion, $version);
+       }
+
+       /**
+        * Data provider for convertVersionsStringToVersionNumbersForcesVersionNumberInRange
+        * @return array
+        */
+       public function convertVersionsStringToVersionNumbersForcesVersionNumberInRangeDataProvider() {
+               return array(
+                       'everything ok' => array(
+                               '4.2.0-4.4.99',
+                               array(
+                                       '4.2.0',
+                                       '4.4.99'
+                               ),
+                       ),
+                       'too high value' => array(
+                               '4.2.0-4.4.2990',
+                               array(
+                                       '4.2.0',
+                                       '4.4.999'
+                               ),
+                       ),
+                       'empty high value' => array(
+                               '4.2.0-0.0.0',
+                               array(
+                                       '4.2.0',
+                                       ''
+                               ),
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider convertVersionsStringToVersionNumbersForcesVersionNumberInRangeDataProvider
+        */
+       public function convertVersionsStringToVersionNumbersForcesVersionNumberInRange($versionString, $expectedResult) {
+               $versions = t3lib_utility_VersionNumber::convertVersionsStringToVersionNumbers($versionString);
+               $this->assertEquals($expectedResult, $versions);
+       }
 }
 
 ?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php b/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php
new file mode 100644 (file)
index 0000000..152c039
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Abstract action controller.
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage controller
+ */
+class Tx_Extensionmanager_Controller_AbstractController extends Tx_Extbase_MVC_Controller_ActionController {
+
+       /**
+        * Resolve view and initialize the general view-variables extensionName,
+        * controllerName and actionName based on the request object
+        *
+        * @return Tx_Fluid_View_TemplateView
+        */
+       protected function resolveView() {
+               $view = parent::resolveView();
+               $view->assignMultiple(array(
+                       'extensionName' => $this->request->getControllerExtensionName(),
+                       'controllerName' => $this->request->getControllerName(),
+                       'actionName' => $this->request->getControllerActionName(),
+               ));
+               return $view;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php b/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php
new file mode 100644 (file)
index 0000000..86e1f30
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Controller for handling extension related actions like
+ * installing, removing, downloading of data or files
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_ActionController extends Tx_Extensionmanager_Controller_AbstractController {
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_FileHandling
+        */
+       protected $fileHandlingUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility
+        * @return void
+        */
+       public function injectFileHandlingUtility(Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility) {
+               $this->fileHandlingUtility = $fileHandlingUtility;
+       }
+
+       /**
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function initializeAction() {
+               if (!$this->request->hasArgument('extension')) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Required argument extension not set!',
+                               1342874433
+                       );
+               }
+       }
+
+       /**
+        * Toggle extension installation state action
+        *
+        * @return void
+        */
+       protected function toggleExtensionInstallationStateAction() {
+               $installedExtensions = t3lib_extMgm::getLoadedExtensionListArray();
+               $extension = $this->request->getArgument('extension');
+               if (in_array($extension, $installedExtensions)) {
+                               // uninstall
+                       $this->installUtility->uninstall($extension);
+               } else {
+                               // install
+                       $this->installUtility->install($extension);
+               }
+               $this->redirect('index', 'List');
+       }
+
+       /**
+        * Remove an extension (if it is still installed, uninstall it first)
+        *
+        * @return void
+        */
+       protected function removeExtensionAction() {
+               $success = TRUE;
+               $message = '';
+               $extension = $this->request->getArgument('extension');
+               try {
+                       if (t3lib_extMgm::isLoaded($extension)) {
+                               $this->installUtility->uninstall($extension);
+                       }
+                       $this->installUtility->removeExtension($extension);
+               } catch (Tx_Extensionmanager_Exception_ExtensionManager $e) {
+                       $message = $e->getMessage();
+                       $success = FALSE;
+               }
+               $this->view->assign('success', $success)
+                       ->assign('message', $message)
+                       ->assign('extension', $extension);
+
+       }
+
+       /**
+        * Download an extension as a zip file
+        *
+        * @return void
+        */
+       protected function downloadExtensionZipAction() {
+               $extension = $this->request->getArgument('extension');
+               $fileName = $this->fileHandlingUtility->createZipFileFromExtension($extension);
+               $this->fileHandlingUtility->sendZipFileToBrowserAndDelete($fileName);
+       }
+
+       /**
+        * Download data of an extension as sql statements
+        *
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       protected function downloadExtensionDataAction() {
+               $error = NULL;
+               $extension = $this->request->getArgument('extension');
+               $sqlData = $this->installUtility->getExtensionSqlDataDump($extension);
+               $dump = $sqlData['extTables'] . $sqlData['staticSql'];
+               $fileName = $extension . '_sqlDump.sql';
+               $filePath = PATH_site . 'typo3temp/' . $fileName;
+               $error = t3lib_div::writeFileToTypo3tempDir($filePath, $dump);
+               if (is_string($error)) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager($error, 1343048718);
+               }
+
+               $this->fileHandlingUtility->sendSqlDumpFileToBrowserAndDelete($filePath, $fileName);
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php b/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php
new file mode 100644 (file)
index 0000000..5804f12
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * Controller for configuration related actions.
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_ConfigurationController extends Tx_Extensionmanager_Controller_AbstractController {
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository
+        */
+       protected $configurationItemRepository;
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository $configurationItemRepository
+        * @return void
+        */
+       public function injectConfigurationItemRepository(
+               Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository $configurationItemRepository
+       ) {
+               $this->configurationItemRepository = $configurationItemRepository;
+       }
+
+       /**
+        * Show the extension configuration form. The whole form field handling is done
+        * in the corresponding view helper
+        *
+        * @return void
+        */
+       public function showConfigurationFormAction() {
+               $extension = $this->request->getArgument('extension');
+               $extension = array_merge($extension, $GLOBALS['TYPO3_LOADED_EXT'][$extension['key']]);
+               $configuration = $this->configurationItemRepository->findByExtension($extension);
+               $this->view
+                       ->assign('configuration', $configuration)
+                       ->assign('extension', $extension);
+       }
+
+       /**
+        * Save configuration to file
+        * Merges existing with new configuration.
+        *
+        * @param array $config The new extension configuration
+        * @param string $extensionKey The extension key
+        * @return void
+        */
+       public function saveAction(array $config, $extensionKey) {
+               /** @var $configurationUtility Tx_Extensionmanager_Utility_Configuration */
+               $configurationUtility = $this->objectManager->get('Tx_Extensionmanager_Utility_Configuration');
+               $currentFullConfiguration = $configurationUtility->getCurrentConfiguration($extensionKey);
+               $newConfiguration = t3lib_div::array_merge_recursive_overrule($currentFullConfiguration, $config);
+
+               $strippedConfiguration = array();
+               foreach ($newConfiguration as $configurationKey => $configurationValue) {
+                       $strippedConfiguration[$configurationKey]['value'] = $configurationValue['value'];
+               }
+
+               $configurationUtility->writeConfiguration($strippedConfiguration, $extensionKey);
+               $this->redirect('showConfigurationForm', NULL, NULL, array('extension' => array('key' => $extensionKey)));
+       }
+
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/DownloadController.php b/typo3/sysext/extensionmanager/Classes/Controller/DownloadController.php
new file mode 100644 (file)
index 0000000..7aa57cb
--- /dev/null
@@ -0,0 +1,224 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * Controller for actions related to the TER download of an extension
+ *
+ * @author Susanne Moog, <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_DownloadController extends Tx_Extensionmanager_Controller_AbstractController {
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       protected $extensionRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_FileHandling
+        */
+       protected $fileHandlingUtility;
+
+
+       /**
+        * @var Tx_Extensionmanager_Service_Management
+        */
+       protected $managementService;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * Dependency injection of the Extension Repository
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility
+        * @return void
+        */
+       public function injectFileHandlingUtility(Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility) {
+               $this->fileHandlingUtility = $fileHandlingUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Service_Management $managementService
+        * @return void
+        */
+       public function injectManagementService(Tx_Extensionmanager_Service_Management $managementService) {
+               $this->managementService = $managementService;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Download
+        */
+       protected $downloadUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Download $downloadUtility
+        * @return void
+        */
+       public function injectDownloadUtility(Tx_Extensionmanager_Utility_Download $downloadUtility) {
+               $this->downloadUtility = $downloadUtility;
+       }
+
+       /**
+        * Check extension dependencies
+        *
+        * @throws Exception
+        * @return void
+        */
+       public function checkDependenciesAction() {
+               if (!$this->request->hasArgument('extension')) {
+                       throw new Exception('Required argument extension not set.', 1334433342);
+               }
+               $extensionUid = $this->request->getArgument('extension');
+               /** @var $extension Tx_Extensionmanager_Domain_Model_Extension */
+               $extension = $this->extensionRepository->findByUid(intval($extensionUid));
+
+               $dependencyTypes = $this->managementService->getAndResolveDependencies($extension);
+               $message = '';
+               if (count($dependencyTypes) > 0) {
+                               // @todo translate and beautify
+                       $message = 'The following dependencies have to be resolved before installation:<br /><br />';
+                       foreach ($dependencyTypes as $dependencyType => $dependencies) {
+                               $message .= '<h3>Extensions marked for ' . $dependencyType . ':</h3>';
+                               foreach ($dependencies as $extensionKey => $dependency) {
+                                       $message .= $extensionKey . '<br />';
+                               }
+                               $message .= 'Shall these dependencies be resolved automatically?';
+                       }
+               }
+               $this->view->assign('dependencies', $dependencyTypes)
+                       ->assign('extension', $extension)
+                       ->assign('message', $message);
+       }
+
+       /**
+        * Install an extension from TER
+        *
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function installFromTerAction() {
+               $result = FALSE;
+               $errorMessage = '';
+               try {
+                       if (!$this->request->hasArgument('extension')) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager('Required argument extension not set.', 1334433342);
+                       }
+                       $extensionUid = $this->request->getArgument('extension');
+
+                       if ($this->request->hasArgument('downloadPath')) {
+                               $this->downloadUtility->setDownloadPath($this->request->getArgument('downloadPath'));
+                       }
+
+                       /** @var $extension Tx_Extensionmanager_Domain_Model_Extension */
+                       $extension = $this->extensionRepository->findByUid(intval($extensionUid));
+                       $this->prepareExtensionForImport($extension);
+                       $result = $this->managementService->resolveDependenciesAndInstall($extension);
+               } catch (Tx_Extensionmanager_Exception_ExtensionManager $e) {
+                       $errorMessage = $e->getMessage();
+               }
+               $this->view->assign('result', $result)
+                       ->assign('extension', $extension)
+                       ->assign('errorMessage', $errorMessage);
+       }
+
+       /**
+        * Prepares an extension for import from TER
+        * Uninstalls the extension if it is already loaded (case: update)
+        * and reloads the caches.
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       protected function prepareExtensionForImport(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               if (t3lib_extMgm::isLoaded($extension->getExtensionKey())) {
+                       t3lib_extMgm::unloadExtension($extension->getExtensionKey());
+                       $this->installUtility->reloadCaches();
+               }
+       }
+
+       /**
+        * Update an extension. Makes no sanity check but directly searches highest
+        * available version from TER and updates. Update check is done by the list
+        * already. This method should only be called if we are sure that there is
+        * an update.
+        *
+        * @return void
+        */
+       protected function updateExtensionAction() {
+               $extensionKey = $this->request->getArgument('extension');
+               /** @var $highestTerVersionExtension Tx_Extensionmanager_Domain_Model_Extension */
+               $highestTerVersionExtension = $this->extensionRepository->findHighestAvailableVersion($extensionKey);
+               $this->prepareExtensionForImport($highestTerVersionExtension);
+               $result = $this->managementService->resolveDependenciesAndInstall($highestTerVersionExtension);
+               $this->view->assign('result', $result)
+                       ->assign('extension', $highestTerVersionExtension);
+       }
+
+       /**
+        * Show update comments for extensions that can be updated.
+        * Fetches update comments for all versions between the current
+        * installed and the highest version.
+        *
+        * @return void
+        */
+       protected function updateCommentForUpdatableVersionsAction() {
+               $extensionKey = $this->request->getArgument('extension');
+               $version = $this->request->getArgument('integerVersion');
+               $updateComments = array();
+               /** @var $updatableVersion Tx_Extensionmanager_Domain_Model_Extension */
+               $updatableVersions = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $version);
+               foreach ($updatableVersions as $updatableVersion) {
+                       $updateComments[$updatableVersion->getVersion()] = $updatableVersion->getUpdateComment();
+               }
+               $this->view
+                       ->assign('updateComments', $updateComments)
+                       ->assign('extensionKey', $extensionKey);
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ListController.php b/typo3/sysext/extensionmanager/Classes/Controller/ListController.php
new file mode 100644 (file)
index 0000000..ea8a25a
--- /dev/null
@@ -0,0 +1,171 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * Controller for extension listings (TER or local extensions)
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_ListController extends Tx_Extensionmanager_Controller_AbstractController {
+
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       protected $extensionRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * Dependency injection of the Extension Repository
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * @var t3lib_PageRenderer
+        */
+       protected $pageRenderer;
+
+       /**
+        * @param t3lib_PageRenderer $pageRenderer
+        * @return void
+        */
+       public function injectPageRenderer(t3lib_PageRenderer $pageRenderer) {
+               $this->pageRenderer = $pageRenderer;
+       }
+
+       /**
+        * Shows list of extensions present in the system
+        *
+        * @return void
+        */
+       public function indexAction() {
+               $this->pageRenderer->addJsFile('../t3lib/js/extjs/notifications.js');
+               $availableExtensions = $this->listUtility->getAvailableExtensions();
+               $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensions($availableExtensions);
+               $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
+                       $availableAndInstalledExtensions
+               );
+               $this->view->assign('extensions', $availableAndInstalledExtensions);
+       }
+
+       /**
+        * Shows extensions from TER
+        * Either all extensions or depending on a search param
+        *
+        * @return void
+        */
+       public function terAction() {
+               $this->pageRenderer->addJsFile('../t3lib/js/extjs/notifications.js');
+               $search = $this->getSearchParam();
+
+               $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensionsWithAdditionalInformation();
+
+               if (is_string($search) && !empty($search)) {
+                       $extensions = $this->extensionRepository->findByTitleOrAuthorNameOrExtensionKey($search);
+               } else {
+                       $extensions = $this->extensionRepository->findAll();
+               }
+               $this->view
+                       ->assign('extensions', $extensions)
+                       ->assign('search', $search)
+                       ->assign('availableAndInstalled', $availableAndInstalledExtensions);
+       }
+
+       /**
+        * Shows all versions of a specific extension
+        *
+        * @return void
+        */
+       public function showAllVersionsAction() {
+               $this->pageRenderer->addJsFile($this->backPath . '../t3lib/js/extjs/notifications.js');
+               $extensions = array();
+               $extensionKey = '';
+               if (
+                       $this->request->hasArgument('allVersions') &&
+                       $this->request->getArgument('allVersions') == 1 &&
+                       $this->request->hasArgument('extensionKey') &&
+                       is_string($this->request->getArgument('extensionKey'))
+               ) {
+                       $extensionKey = $this->request->getArgument('extensionKey');
+                       $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey);
+               } else {
+                       $this->redirect('ter');
+               }
+               $this->view
+                       ->assign('extensions', $extensions)
+                       ->assign('extensionKey', $extensionKey);
+       }
+
+       /**
+        * Gets the search parameter either from the url or out
+        * of the session if present
+        *
+        * @return string
+        */
+       public function getSearchParam() {
+               $search = '';
+               if ($this->request->hasArgument('search') && is_string($this->request->getArgument('search'))) {
+                       $search = $this->request->getArgument('search');
+               }
+               return $search;
+       }
+
+       /**
+       * Gets instance of template if exists or create a new one.
+       * Saves instance in viewHelperVariableContainer
+       *
+       * @return template $doc
+       */
+       public function getDocInstance() {
+               if (!isset($GLOBALS['SOBE']->doc)) {
+                       $GLOBALS['SOBE']->doc = t3lib_div::makeInstance('template');
+                       $GLOBALS['SOBE']->doc->backPath = $GLOBALS['BACK_PATH'];
+               }
+               return $GLOBALS['SOBE']->doc;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/UpdateFromTerController.php b/typo3/sysext/extensionmanager/Classes/Controller/UpdateFromTerController.php
new file mode 100644 (file)
index 0000000..3f62a79
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Controller for actions relating to update of full extension list from TER
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_UpdateFromTerController extends Tx_Extensionmanager_Controller_AbstractController {
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Repository_Helper
+        */
+       protected $repositoryHelper;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_RepositoryRepository
+        */
+       protected $repositoryRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       protected $extensionRepository;
+
+       /**
+        * Dependency injection of the Extension Repository
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+
+       /**
+        * Dependency injection of the Repository Helper Utility
+        *
+        * @param Tx_Extensionmanager_Utility_Repository_Helper $repositoryHelper
+        * @return void
+        */
+       public function injectRepositoryHelper(Tx_Extensionmanager_Utility_Repository_Helper $repositoryHelper) {
+               $this->repositoryHelper = $repositoryHelper;
+       }
+
+       /**
+        * Dependency injection of repository repository
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_RepositoryRepository $repositoryRepository
+        * @return void
+        */
+       public function injectRepositoryRepository(Tx_Extensionmanager_Domain_Repository_RepositoryRepository $repositoryRepository) {
+               $this->repositoryRepository = $repositoryRepository;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * Update extension list from TER
+        *
+        * @return void
+        */
+       public function updateExtensionListFromTerAction() {
+               $updated = FALSE;
+               $forceUpdateCheck = FALSE;
+               $errorMessage = '';
+               if ($this->request->hasArgument('forceUpdateCheck') && (int)$this->request->getArgument('forceUpdateCheck') == 1) {
+                       $forceUpdateCheck = TRUE;
+               }
+               /** @var $repository Tx_Extensionmanager_Domain_Model_Repository */
+               $repository = $this->repositoryRepository->findOneByUid((int)$this->settings['repositoryUid']);
+               if ($repository->getLastUpdate() < ($GLOBALS['EXEC_TIME'] - 24 * 60 * 60) || $forceUpdateCheck) {
+                       try {
+                               $updated = $this->repositoryHelper->updateExtList();
+                       } catch (Tx_Extensionmanager_Exception_ExtensionManager $e) {
+                               $errorMessage = $e->getMessage();
+                       }
+               }
+               $this->view->assign('updated', $updated)
+                       ->assign('repository', $repository)
+                       ->assign('errorMessage', $errorMessage);
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php b/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php
new file mode 100644 (file)
index 0000000..6095ff8
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Controller for handling upload of a local extension file
+ * Handles .t3x or .zip files
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Controller
+ */
+class Tx_Extensionmanager_Controller_UploadExtensionFileController extends Tx_Extensionmanager_Controller_AbstractController {
+
+       /**
+        * @var Tx_Extensionmanager_Utility_FileHandling
+        */
+       protected $fileHandlingUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Connection_Ter
+        */
+       protected $terUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility
+        * @return void
+        */
+       public function injectFileHandlingUtility(Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility) {
+               $this->fileHandlingUtility = $fileHandlingUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Connection_Ter $terUtility
+        * @return void
+        */
+       public function injectTerUtility(Tx_Extensionmanager_Utility_Connection_Ter $terUtility) {
+               $this->terUtility = $terUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * Render upload extension form
+        *
+        * @return void
+        */
+       public function formAction() {
+
+       }
+
+       /**
+        * Extract an uploaded file and install the matching extension
+        *
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function extractAction() {
+               $file = $_FILES['tx_extensionmanager_tools_extensionmanagerextensionmanager'];
+               $fileExtension = pathinfo($file['name']['extensionFile'], PATHINFO_EXTENSION);
+               $fileName = pathinfo($file['name']['extensionFile'], PATHINFO_BASENAME);
+               if (isset($file['name']['extensionFile']) && (
+                               $fileExtension !== 't3x' &&
+                               $fileExtension !== 'zip'
+                       )
+               ) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Wrong file format given.', 1342858853);
+               }
+               if (isset($file['tmp_name']['extensionFile'])) {
+                       $tempFile = t3lib_div::upload_to_tempfile($file['tmp_name']['extensionFile']);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Creating temporary file failed.', 1342864339);
+               }
+               if ($fileExtension === 't3x') {
+                       $extensionData = $this->getExtensionFromT3xFile($tempFile);
+               } else {
+                       $extensionData = $this->getExtensionFromZipFile($tempFile, $fileName);
+               }
+
+               $this->view->assign('extensionKey', $extensionData['extKey']);
+       }
+
+       /**
+        * Extracts a given t3x file and installs the extension
+        *
+        * @param string $file
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return array
+        */
+       protected function getExtensionFromT3xFile($file) {
+               $fileContent = t3lib_div::getUrl($file);
+               if (!$fileContent) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('File had no or wrong content.', 1342859339);
+               }
+               $extensionData = $this->terUtility->decodeExchangeData($fileContent);
+               if ($extensionData['extKey']) {
+                       $this->fileHandlingUtility->unpackExtensionFromExtensionDataArray($extensionData);
+                       $this->installUtility->install($extensionData['extKey']);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Decoding the file went wrong. No extension key found', 1342864309);
+               }
+               return $extensionData;
+       }
+
+       /**
+        * Extracts a given zip file and installs the extension
+        * As there is no information about the extension key in the zip
+        * we have to use the file name to get that information
+        * filename format is expected to be extensionkey_version.zip
+        *
+        * @param string $file path to uploaded file
+        * @param string $fileName filename (basename) of uploaded file
+        * @return array
+        */
+       protected function getExtensionFromZipFile($file, $fileName) {
+               $fileNameParts = t3lib_div::revExplode('_', $fileName, 2);
+               $this->fileHandlingUtility->unzipExtensionFromFile($file, $fileNameParts[0]);
+               $this->installUtility->install($fileNameParts[0]);
+               return array('extKey' => $fileNameParts[0]);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationCategory.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationCategory.php
new file mode 100644 (file)
index 0000000..7523c1c
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Main model for extension configuration categories
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_ConfigurationCategory extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * @var string
+        */
+       protected $name = '';
+
+       /**
+        * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory>
+        */
+       protected $subcategories;
+
+       /**
+        * @var string
+        */
+       protected $highlightText = '';
+
+       /**
+        * Constructs this Category
+        */
+       public function __construct() {
+               $this->subcategories = new Tx_Extbase_Persistence_ObjectStorage();
+
+       }
+
+       /**
+        * @param \Tx_Extbase_Persistence_ObjectStorage $subcategories
+        * @return void
+        */
+       public function setSubcategories($subcategories) {
+               $this->subcategories = $subcategories;
+       }
+
+       /**
+        * @return \Tx_Extbase_Persistence_ObjectStorage
+        */
+       public function getSubcategories() {
+               return $this->subcategories;
+       }
+
+       /**
+        * Adds a subcategories
+        *
+        * @param Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory $subcategory
+        * @return void
+        */
+       public function addSubcategory(Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory $subcategory) {
+               $this->subcategories->attach($subcategory);
+       }
+
+       /**
+        * @param string $name
+        * @return void
+        */
+       public function setName($name) {
+               $this->name = $name;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * @param string $highlightText
+        * @return void
+        */
+       public function setHighlightText($highlightText) {
+               $this->highlightText = $highlightText;
+       }
+
+       /**
+        * @return string
+        */
+       public function getHighlightText() {
+               return $this->highlightText;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationItem.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationItem.php
new file mode 100644 (file)
index 0000000..82221cc
--- /dev/null
@@ -0,0 +1,218 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * Model for extension configuration items
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_ConfigurationItem extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * @var string
+        */
+       protected $category = '';
+
+       /**
+        * @var string
+        */
+       protected $subCategory = '';
+
+       /**
+        * @var string
+        */
+       protected $type = '';
+
+       /**
+        * @var string
+        */
+       protected $labelHeadline = '';
+
+       /**
+        * @var string
+        */
+       protected $labelText = '';
+
+       /**
+        * @var mixed
+        */
+       protected $generic = '';
+
+       /**
+        * @var string
+        */
+       protected $name = '';
+
+       /**
+        * @var string
+        */
+       protected $value = '';
+
+       /**
+        * @var int
+        */
+       protected $highlight = 0;
+
+       /**
+        * @param string $category
+        * @return void
+        */
+       public function setCategory($category) {
+               $this->category = $category;
+       }
+
+       /**
+        * @return string
+        */
+       public function getCategory() {
+               return $this->category;
+       }
+
+       /**
+        * @param string $labelHeadline
+        * @return void
+        */
+       public function setLabelHeadline($labelHeadline) {
+               $this->labelHeadline = $labelHeadline;
+       }
+
+       /**
+        * @return string
+        */
+       public function getLabelHeadline() {
+               return $this->labelHeadline;
+       }
+
+       /**
+        * @param string $labelText
+        * @return void
+        */
+       public function setLabelText($labelText) {
+               $this->labelText = $labelText;
+       }
+
+       /**
+        * @return string
+        */
+       public function getLabelText() {
+               return $this->labelText;
+       }
+
+       /**
+        * @param string $subCategory
+        * @return void
+        */
+       public function setSubCategory($subCategory) {
+               $this->subCategory = $subCategory;
+       }
+
+       /**
+        * @return string
+        */
+       public function getSubCategory() {
+               return $this->subCategory;
+       }
+
+       /**
+        * @param string $type
+        * @return void
+        */
+       public function setType($type) {
+               $this->type = $type;
+       }
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return $this->type;
+       }
+
+       /**
+        * @param mixed $userFunc
+        * @return void
+        */
+       public function setGeneric($userFunc) {
+               $this->generic = $userFunc;
+       }
+
+       /**
+        * @return mixed
+        */
+       public function getGeneric() {
+               return $this->generic;
+       }
+
+       /**
+        * @param string $name
+        * @return void
+        */
+       public function setName($name) {
+               $this->name = $name;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * @param string $value
+        * @return void
+        */
+       public function setValue($value) {
+               $this->value = $value;
+       }
+
+       /**
+        * @return string
+        */
+       public function getValue() {
+               return $this->value;
+       }
+
+       /**
+        * @param integer $highlight
+        * @return void
+        */
+       public function setHighlight($highlight) {
+               $this->highlight = $highlight;
+       }
+
+       /**
+        * @return integer
+        */
+       public function getHighlight() {
+               return $this->highlight;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationSubcategory.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/ConfigurationSubcategory.php
new file mode 100644 (file)
index 0000000..62ca80f
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Model for configuration subcategories
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * @var string
+        */
+       protected $name = '';
+
+       /**
+        * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Extensionmanager_Domain_Model_ConfigurationItem>
+        */
+       protected $items;
+
+       /**
+        * Constructs this Category
+        */
+       public function __construct() {
+               $this->items = new Tx_Extbase_Persistence_ObjectStorage();
+
+       }
+
+       /**
+        * @param Tx_Extbase_Persistence_ObjectStorage $items
+        * @return void
+        */
+       public function setItems($items) {
+               $this->items = $items;
+       }
+
+       /**
+        * @return Tx_Extbase_Persistence_ObjectStorage
+        */
+       public function getItems() {
+               return $this->items;
+       }
+
+       /**
+        * Adds a subcategory
+        *
+        * @param Tx_Extensionmanager_Domain_Model_ConfigurationItem $item
+        * @return void
+        */
+       public function addItem(Tx_Extensionmanager_Domain_Model_ConfigurationItem $item) {
+               $this->items->attach($item);
+       }
+
+       /**
+        * @param string $name
+        * @return void
+        */
+       public function setName($name) {
+               $this->name = $name;
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/Dependency.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/Dependency.php
new file mode 100644 (file)
index 0000000..a224d15
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * Main extension model
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_Dependency extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * @var string
+        */
+       protected $identifier = '';
+
+       /**
+        * @var string
+        */
+       protected $lowestVersion = '';
+
+       /**
+        * @var string
+        */
+       protected $highestVersion = '';
+
+       /**
+        * @var string
+        */
+       protected $type = '';
+
+       /**
+        * @var array
+        */
+       protected static $dependencyTypes = array(
+               'depends',
+               'conflicts'
+       );
+
+       /**
+        * @var array
+        */
+       public static $specialDependencies = array(
+               'typo3',
+               'php'
+       );
+
+       /**
+        * @param string $highestVersion
+        * @return void
+        */
+       public function setHighestVersion($highestVersion) {
+               $this->highestVersion = $highestVersion;
+       }
+
+       /**
+        * @return string
+        */
+       public function getHighestVersion() {
+               return $this->highestVersion;
+       }
+
+       /**
+        * @param string $identifier
+        * @return void
+        */
+       public function setIdentifier($identifier) {
+               $this->identifier = $identifier;
+       }
+
+       /**
+        * @return string
+        */
+       public function getIdentifier() {
+               return $this->identifier;
+       }
+
+       /**
+        * @param string $lowestVersion
+        * @return void
+        */
+       public function setLowestVersion($lowestVersion) {
+               $this->lowestVersion = $lowestVersion;
+       }
+
+       /**
+        * @return string
+        */
+       public function getLowestVersion() {
+               return $this->lowestVersion;
+       }
+
+       /**
+        * @param string $type
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager if no valid dependency type was given
+        * @return void
+        */
+       public function setType($type) {
+               if (in_array($type, self::$dependencyTypes)) {
+                       $this->type = $type;
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager($type . 'was not a valid dependency type.');
+               }
+       }
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return $this->type;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/DownloadQueue.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/DownloadQueue.php
new file mode 100644 (file)
index 0000000..16e2015
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Download Queue - storage for extensions to be downloaded
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_DownloadQueue implements t3lib_Singleton {
+
+       /**
+        * Storage for extensions to be downloaded
+        *
+        * @var array<Tx_Extensionmanager_Domain_Model_Extension>
+        */
+       protected $extensionStorage = array();
+
+       /**
+        * Storage for extensions to be installed
+        *
+        * @var array
+        */
+       protected $extensionInstallStorage = array();
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * Adds an extension to the download queue.
+        * If the extension was already requested in a different version
+        * an exception is thrown.
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @param string $stack
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function addExtensionToQueue(Tx_Extensionmanager_Domain_Model_Extension $extension, $stack = 'download') {
+               if (!is_string($stack) || !in_array($stack, array('download', 'update'))) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Stack has to be either "download" or "update"',
+                               1342432103
+                       );
+               }
+               if (array_key_exists($extension->getExtensionKey(), $this->extensionStorage)) {
+                       if (!($this->extensionStorage[$extension->getExtensionKey()] === $extension)) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       $extension->getExtensionKey() . ' was requested to be downloaded in different versions.',
+                                       1342432101
+                               );
+                       }
+               }
+               $this->extensionStorage[$stack][$extension->getExtensionKey()] = $extension;
+       }
+
+       /**
+        * @return array
+        */
+       public function getExtensionQueue() {
+               return $this->extensionStorage;
+       }
+
+       /**
+        * Remove an extension from download queue
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @param string $stack Stack to remove extension from (download, update or install)
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function removeExtensionFromQueue(Tx_Extensionmanager_Domain_Model_Extension $extension, $stack = 'download') {
+               if (!is_string($stack) || !in_array($stack, array('download', 'update'))) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Stack has to be either "download" or "update"',
+                               1342432103
+                       );
+               }
+               if (array_key_exists($stack, $this->extensionStorage) && is_array($this->extensionStorage[$stack])) {
+                       if (array_key_exists($extension->getExtensionKey(), $this->extensionStorage[$stack])) {
+                               unset($this->extensionStorage[$stack][$extension->getExtensionKey()]);
+                       }
+               }
+       }
+
+       /**
+        * Adds an extension to the install queue for later installation
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       public function addExtensionToInstallQueue($extensionKey) {
+               $this->extensionInstallStorage[$extensionKey] = $extensionKey;
+       }
+
+       /**
+        * Removes an extension from the install queue
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       public function removeExtensionFromInstallQueue($extensionKey) {
+               if (array_key_exists($extensionKey, $this->extensionInstallStorage)) {
+                       unset($this->extensionInstallStorage[$extensionKey]);
+               }
+       }
+
+       /**
+        * Gets the extension installation queue
+        *
+        * @return array
+        */
+       public function getExtensionInstallStorage() {
+               return $this->extensionInstallStorage;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/Extension.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/Extension.php
new file mode 100644 (file)
index 0000000..0dfdfad
--- /dev/null
@@ -0,0 +1,571 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Main extension model
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_Extension extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * Contains default categories.
+        *
+        * @var array
+        */
+       protected static $defaultCategories = array(
+               0 => 'be',
+               1 => 'module',
+               2 => 'fe',
+               3 => 'plugin',
+               4 => 'misc',
+               5 => 'services',
+               6 => 'templates',
+               8 => 'doc',
+               9 => 'example'
+       );
+
+       /**
+        * Contains default states.
+        *
+        * @var array
+        */
+       protected static $defaultStates = array(
+               0 => 'alpha',
+               1 => 'beta',
+               2 => 'stable',
+               3 => 'experimental',
+               4 => 'test',
+               5 => 'obsolete',
+               6 => 'excludeFromUpdates',
+               999 => 'n/a'
+       );
+
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManager
+        */
+       protected $objectManager;
+
+       /**
+        * @var string
+        */
+       protected $extensionKey = '';
+
+       /**
+        * @var string
+        */
+       protected $version = '';
+
+       /**
+        * @var integer
+        */
+       protected $integerVersion = 0;
+
+       /**
+        * @var string
+        */
+       protected $title = '';
+
+       /**
+        * @var string
+        */
+       protected $description = '';
+
+       /**
+        * @var integer
+        */
+       protected $state = 0;
+
+       /**
+        * @var integer
+        */
+       protected $category = 0;
+
+       /**
+        * @var DateTime
+        */
+       protected $lastUpdated;
+
+       /**
+        * @var string
+        */
+       protected $updateComment = '';
+
+       /**
+        * @var string
+        */
+       protected $authorName = '';
+
+       /**
+        * @var string
+        */
+       protected $authorEmail = '';
+
+       /**
+        * @var boolean
+        */
+       protected $currentVersion = FALSE;
+
+       /**
+        * @var string
+        */
+       protected $md5hash = '';
+
+       /**
+        * @var integer
+        */
+       protected $reviewState;
+
+       /**
+        * @var string
+        */
+       protected $serializedDependencies = '';
+
+       /**
+        * @var SplObjectStorage<Tx_Extensionmanager_Utility_Dependency>
+        */
+       protected $dependencies = NULL;
+
+       /**
+        * @internal
+        * @var integer
+        */
+       protected $position = 0;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManager $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManager $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @param string $authorEmail
+        * @return void
+        */
+       public function setAuthorEmail($authorEmail) {
+               $this->authorEmail = $authorEmail;
+       }
+
+       /**
+        * @return string
+        */
+       public function getAuthorEmail() {
+               return $this->authorEmail;
+       }
+
+       /**
+        * @param string $authorName
+        * @return void
+        */
+       public function setAuthorName($authorName) {
+               $this->authorName = $authorName;
+       }
+
+       /**
+        * @return string
+        */
+       public function getAuthorName() {
+               return $this->authorName;
+       }
+
+       /**
+        * @param int $category
+        * @return void
+        */
+       public function setCategory($category) {
+               $this->category = $category;
+       }
+
+       /**
+        * @return integer
+        */
+       public function getCategory() {
+               return $this->category;
+       }
+
+       /**
+        * Get Category String
+        *
+        * @return string
+        */
+       public function getCategoryString() {
+               $categoryString = '';
+               if (isset(self::$defaultCategories[$this->getCategory()])) {
+                       $categoryString = self::$defaultCategories[$this->getCategory()];
+               }
+               return $categoryString;
+       }
+
+       /**
+        * Returns either array with all default categories or index/title
+        * of a category entry.
+        *
+        * @param mixed $cat category title or category index
+        * @return mixed
+        */
+       public function getDefaultCategory($cat = NULL) {
+               $return = '';
+               if (is_null($cat)) {
+                       $return = self::$defaultCategories;
+               } else {
+                       if (is_string($cat)) {
+                                       // default category
+                               $catIndex = 4;
+                               if (array_key_exists(strtolower($cat), self::$defaultCategories)) {
+                                       $catIndex = self::$defaultCategories[strtolower($cat)];
+                               }
+                               $return = $catIndex;
+                       } else {
+                               if (is_int($cat) && $cat >= 0) {
+                                       $catTitle = array_search($cat, self::$defaultCategories);
+                                               // default category
+                                       if (!$catTitle) {
+                                               $catTitle = 'misc';
+                                       }
+                                       $return = $catTitle;
+                               }
+                       }
+               }
+               return $return;
+       }
+
+       /**
+        * @param string $description
+        * @return void
+        */
+       public function setDescription($description) {
+               $this->description = $description;
+       }
+
+       /**
+        * @return string
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+
+       /**
+        * @param string $extensionKey
+        * @return void
+        */
+       public function setExtensionKey($extensionKey) {
+               $this->extensionKey = $extensionKey;
+       }
+
+       /**
+        * @return string
+        */
+       public function getExtensionKey() {
+               return $this->extensionKey;
+       }
+
+       /**
+        * @param DateTime $lastUpdated
+        * @return void
+        */
+       public function setLastUpdated(DateTime $lastUpdated) {
+               $this->lastUpdated = $lastUpdated;
+       }
+
+       /**
+        * @return DateTime
+        */
+       public function getLastUpdated() {
+               return $this->lastUpdated;
+       }
+
+       /**
+        * @param integer $state
+        * @return void
+        */
+       public function setState($state) {
+               $this->state = $state;
+       }
+
+       /**
+        * @return integer
+        */
+       public function getState() {
+               return $this->state;
+       }
+
+       /**
+        * Get State string
+        *
+        * @return string
+        */
+       public function getStateString() {
+               $stateString = '';
+               if (isset(self::$defaultStates[$this->getState()])) {
+                       $stateString = self::$defaultStates[$this->getState()];
+               }
+               return $stateString;
+       }
+
+       /**
+        * Returns either array with all default states or index/title
+        * of a state entry.
+        *
+        * @param mixed $state state title or state index
+        * @return mixed
+        */
+       public function getDefaultState($state = NULL) {
+               if (is_null($state)) {
+                       $defaultState = self::$defaultStates;
+               } else {
+                       if (is_string($state)) {
+                                       // default state
+                               $stateIndex = 999;
+                               if (array_key_exists(strtolower($state), self::$defaultStates)) {
+                                       $stateIndex = self::$defaultStates[strtolower($state)];
+                               }
+                               $defaultState = $stateIndex;
+                       } else {
+                               if (is_int($state) && $state >= 0) {
+                                       $stateTitle = array_search($state, self::$defaultStates);
+                                               // default state
+                                       if (!$stateTitle) {
+                                               $stateTitle = 'n/a';
+                                       }
+                                       $defaultState = $stateTitle;
+                               }
+                       }
+               }
+               return $defaultState;
+       }
+
+       /**
+        * @param string $title
+        * @return void
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+       }
+
+       /**
+        * @return string
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * @param string $updateComment
+        * @return void
+        */
+       public function setUpdateComment($updateComment) {
+               $this->updateComment = $updateComment;
+       }
+
+       /**
+        * @return string
+        */
+       public function getUpdateComment() {
+               return $this->updateComment;
+       }
+
+       /**
+        * @param string $version
+        * @return void
+        */
+       public function setVersion($version) {
+               $this->version = $version;
+       }
+
+       /**
+        * @return string
+        */
+       public function getVersion() {
+               return $this->version;
+       }
+
+       /**
+        * @param boolean $currentVersion
+        * @return void
+        */
+       public function setCurrentVersion($currentVersion) {
+               $this->currentVersion = $currentVersion;
+       }
+
+       /**
+        * @return boolean
+        */
+       public function getCurrentVersion() {
+               return $this->currentVersion;
+       }
+
+       /**
+        * @param string $md5hash
+        * @return void
+        */
+       public function setMd5hash($md5hash) {
+               $this->md5hash = $md5hash;
+       }
+
+       /**
+        * @return string
+        */
+       public function getMd5hash() {
+               return $this->md5hash;
+       }
+
+       /**
+        * Possible install pathes
+        *
+        * @static
+        * @return array
+        */
+       public static function returnInstallPaths() {
+               $installPaths = array(
+                       'System' => PATH_typo3 . 'sysext/',
+                       'Global' => PATH_typo3 . 'ext/',
+                       'Local' => PATH_typo3conf . 'ext/'
+               );
+               return $installPaths;
+       }
+
+       /**
+        * Allowed install pathes
+        *
+        * @static
+        * @return array
+        */
+       public static function returnAllowedInstallPaths() {
+               $installPaths = self::returnInstallPaths();
+               if (!(isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall']) &&
+                       $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall'])) {
+                       unset($installPaths['System']);
+               }
+               return $installPaths;
+       }
+
+       /**
+        * Allowed install names: System, Global, Local
+        *
+        * @static
+        * @return array
+        */
+       public static function returnAllowedInstallTypes() {
+               $installPaths = self::returnAllowedInstallPaths();
+               return array_keys($installPaths);
+       }
+
+       /**
+        * @param string $dependencies
+        * @return void
+        */
+       public function setSerializedDependencies($dependencies) {
+               $this->serializedDependencies = $dependencies;
+       }
+
+       /**
+        * @return string
+        */
+       public function getSerializedDependencies() {
+               return $this->serializedDependencies;
+       }
+
+       /**
+        * @param SplObjectStorage $dependencies
+        * @return void
+        */
+       public function setDependencies($dependencies) {
+               $this->dependencies = $dependencies;
+       }
+
+       /**
+        * @return SplObjectStorage
+        */
+       public function getDependencies() {
+               if (!is_object($this->dependencies)) {
+                       /** @var $dependencyUtility Tx_Extensionmanager_Utility_Dependency */
+                       $dependencyUtility = $this->objectManager->get('Tx_Extensionmanager_Utility_Dependency');
+                       $this->setDependencies($dependencyUtility->convertDependenciesToObjects($this->getSerializedDependencies()));
+               }
+               return $this->dependencies;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return void
+        */
+       public function addDependency(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $this->dependencies->attach($dependency);
+       }
+
+       /**
+        * @param int $integerVersion
+        * @return void
+        */
+       public function setIntegerVersion($integerVersion) {
+               $this->integerVersion = $integerVersion;
+       }
+
+       /**
+        * @return int
+        */
+       public function getIntegerVersion() {
+               return $this->integerVersion;
+       }
+
+       /**
+        * @param int $reviewState
+        * @return void
+        */
+       public function setReviewState($reviewState) {
+               $this->reviewState = $reviewState;
+       }
+
+       /**
+        * @return int
+        */
+       public function getReviewState() {
+               return $this->reviewState;
+       }
+
+       /**
+        * @param int $position
+        * @return void
+        */
+       public function setPosition($position) {
+               $this->position = $position;
+       }
+
+       /**
+        * @return int
+        */
+       public function getPosition() {
+               return $this->position;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/Mirrors.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/Mirrors.php
new file mode 100644 (file)
index 0000000..5a7ed67
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ *          Steffen Kamper <info@sk-typo3.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ * Repository mirrors object for extension manager.
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since 2010-02-11
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_Mirrors extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * Keeps mirrors.
+        *
+        * @var array
+        */
+       protected $mirrors = array();
+
+       /**
+        * Keeps currently select mirror.
+        *
+        * Is array index.
+        *
+        * @var integer
+        */
+       protected $currentMirror;
+
+       /**
+        * Keeps information if a mirror should
+        * be randomly selected.
+        *
+        * @var boolean
+        */
+       protected $isRandomSelection = TRUE;
+
+       /**
+        * Method selects one specific mirror to be used.
+        *
+        * @param integer $mirrorId number (>=1) of mirror or NULL for random selection
+        * @return void
+        * @see $currentMirror
+        */
+       public function setSelect($mirrorId = NULL) {
+               if (is_null($mirrorId)) {
+                       $this->isRandomSelection = TRUE;
+               } else {
+                       if (is_int($mirrorId) && $mirrorId >= 1 && $mirrorId <= count($this->mirrors)) {
+                               $this->currentMirror = $mirrorId - 1;
+                       }
+               }
+       }
+
+       /**
+        * Method returns one mirror for use.
+        *
+        * Mirror has previously been selected or is chosen
+        * randomly.
+        *
+        * @access public
+        * @return array array of a mirror's properties or NULL in case of errors
+        */
+       public function getMirror() {
+               $sumMirrors = count($this->mirrors);
+               if ($sumMirrors > 0) {
+                       if (!is_int($this->currentMirror)) {
+                               $this->currentMirror = rand(0, $sumMirrors - 1);
+                       }
+                       return $this->mirrors[$this->currentMirror];
+               }
+               return NULL;
+       }
+
+       /**
+        * Gets the mirror url from selected mirror
+        *
+        * @return string
+        */
+       public function getMirrorUrl() {
+               $mirror = $this->getMirror();
+               $mirrorUrl = $mirror['host'] . $mirror['path'];
+
+               return 'http://' . $mirrorUrl;
+       }
+
+       /**
+        * Method returns all available mirrors.
+        *
+        * @access public
+        * @return array multidimensional array with mirrors and their properties
+        * @see  $mirrors, setMirrors()
+        */
+       public function getMirrors() {
+               return $this->mirrors;
+       }
+
+       /**
+        * Method sets available mirrors.
+        *
+        * @param array $mirrors multidimensional array with mirrors and their properties
+        * @return void
+        * @see $mirrors, getMirrors()
+        */
+       public function setMirrors(array $mirrors) {
+               if (count($mirrors) >= 1) {
+                       $this->mirrors = $mirrors;
+               }
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Model/Repository.php b/typo3/sysext/extensionmanager/Classes/Domain/Model/Repository.php
new file mode 100644 (file)
index 0000000..8eeff39
--- /dev/null
@@ -0,0 +1,282 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ *          Steffen Kamper <info@sk-typo3.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Repository object for extension manager.
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since 2010-02-11
+ * @package Extension Manager
+ * @subpackage Model
+ */
+class Tx_Extensionmanager_Domain_Model_Repository extends Tx_Extbase_DomainObject_AbstractEntity {
+
+       /**
+        * Keeps repository title.
+        *
+        * @var string
+        */
+       protected $title;
+
+       /**
+        * Keeps repository description.
+        *
+        * @var string
+        */
+       protected $description;
+
+       /**
+        * Keeps mirror list URL.
+        *
+        * @var string
+        */
+       protected $mirrorListUrl;
+
+       /**
+        * Keeps repository mirrors object.
+        *
+        * @var Tx_Extensionmanager_Domain_Model_Mirrors
+        */
+       protected $mirrors;
+
+       /**
+        * Keeps wsdl URL.
+        *
+        * @var string
+        */
+       protected $wsdlUrl;
+
+       /**
+        * Keeps last update.
+        *
+        * @var DateTime
+        */
+       protected $lastUpdate;
+
+       /**
+        * Keeps extension count.
+        *
+        * @var string
+        */
+       protected $extensionCount;
+
+       /**
+        * Method returns title of a repository.
+        *
+        * @access public
+        * @return string title of repository
+        * @see $title, setTitle()
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Method sets title of a repository.
+        *
+        * @access public
+        * @param string $title title of repository to set
+        * @return void
+        * @see $title, getTitle()
+        */
+       public function setTitle($title) {
+               if (!empty($title) && is_string($title)) {
+                       $this->title = $title;
+               }
+       }
+
+       /**
+        * Method returns description of a repository.
+        *
+        * @access public
+        * @return string title of repository
+        * @see $title, setTitle()
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+
+       /**
+        * Method sets description of a repository.
+        *
+        * @access public
+        * @param string $description title of repository to set
+        * @return void
+        */
+       public function setDescription($description) {
+               if (!empty($description) && is_string($description)) {
+                       $this->description = $description;
+               }
+       }
+
+       /**
+        * Method returns URL of a resource that contains repository mirrors.
+        *
+        * @access public
+        * @return string URL of file that contains repository mirros
+        * @see $mirrorListUrl, getMirrorListUrl()
+        */
+       public function getMirrorListUrl() {
+               return $this->mirrorListUrl;
+       }
+
+       /**
+        * Method sets URL of a resource that contains repository mirrors.
+        *
+        * Parameter is typically a remote gzipped xml file.
+        *
+        * @access public
+        * @param string $url URL of file that contains repository mirrors
+        * @return void
+        * @see $mirrorListUrl, getMirrorListUrl()
+        */
+       public function setMirrorListUrl($url) {
+               if (empty($url) || (!empty($url) && t3lib_div::isValidUrl($url))) {
+                       $this->mirrorListUrl = $url;
+               }
+       }
+
+       /**
+        * Method returns URL of repository WSDL.
+        *
+        * @access public
+        * @return string URL of repository WSDL
+        * @see $wsdlUrl, setWsdlUrl()
+        */
+       public function getWsdlUrl() {
+               return $this->wsdlUrl;
+       }
+
+       /**
+        * Method sets URL of repository WSDL.
+        *
+        * @param string $url URL of repository WSDL
+        * @return void
+        * @see $wsdlUrl, getWsdlUrl()
+        */
+       public function setWsdlUrl($url) {
+               if (!empty($url) && t3lib_div::isValidUrl($url)) {
+                       $this->wsdlUrl = $url;
+               }
+       }
+
+       /**
+        * Method returns LastUpdate.
+        *
+        * @access public
+        * @return int timestamp of last update
+        */
+       public function getLastUpdate() {
+               return $this->lastUpdate;
+       }
+
+       /**
+        * Method sets LastUpdate.
+        *
+        * @access public
+        * @param int $time URL of repository WSDL
+        * @return void
+        */
+       public function setLastUpdate($time) {
+               $this->lastUpdate = $time;
+       }
+
+       /**
+        * Method returns extension count
+        *
+        * @access public
+        * @return int count of read extensions
+        */
+       public function getExtensionCount() {
+               return $this->extensionCount;
+       }
+
+       /**
+        * Method sets extension count
+        *
+        * @access public
+        * @param string $count count of read extensions
+        * @return void
+        */
+       public function setExtensionCount($count) {
+               $this->extensionCount = $count;
+       }
+
+       /**
+        * Method registers repository mirrors object.
+        *
+        * Repository mirrors object is passed by reference.
+        *
+        * @access public
+        * @param Tx_Extensionmanager_Domain_Model_Mirrors $mirrors mirror list
+        * @return void
+        * @see $mirrors, getMirrors(), hasMirrors(), removeMirrors()
+        */
+       public function addMirrors(Tx_Extensionmanager_Domain_Model_Mirrors $mirrors) {
+               $this->mirrors = $mirrors;
+       }
+
+       /**
+        * Method returns information if a repository mirrors
+        * object has been registered to this repository.
+        *
+        * @access public
+        * @return boolean TRUE, if a repository mirrors object has been registered, otherwise FALSE
+        * @see $mirrors, addMirrors(), getMirrors(), removeMirrors()
+        */
+       public function hasMirrors() {
+               $hasMirrors = FALSE;
+               if (is_object($this->mirrors)) {
+                       $hasMirrors = TRUE;
+               }
+               return $hasMirrors;
+       }
+
+       /**
+        * Method returns a repository mirrors object.
+        *
+        * @access public
+        * @return Tx_Extensionmanager_Domain_Model_Mirrors mirrors for repository
+        * @see $mirrors, addMirrors(), hasMirrors(), removeMirrors()
+        */
+       public function getMirrors() {
+               return $this->hasMirrors() ? $this->mirrors : NULL;
+       }
+
+       /**
+        * Method unregisters a repository mirrors object.
+        *
+        * @access public
+        * @return void
+        * @see $mirrors, addMirrors(), getMirrors(), hasMirrors()
+        */
+       public function removeMirrors() {
+               unset($this->mirrors);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Repository/ConfigurationItemRepository.php b/typo3/sysext/extensionmanager/Classes/Domain/Repository/ConfigurationItemRepository.php
new file mode 100644 (file)
index 0000000..a88cf33
--- /dev/null
@@ -0,0 +1,280 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for extension configuration items
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Repository
+ */
+class Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManagerInterface
+        */
+       protected $objectManager;
+
+       /**
+        * Injects the object manager
+        *
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * Find configuration options by extension
+        *
+        * @param array $extension array with extension information
+        * @return null|SplObjectStorage
+        */
+       public function findByExtension(array $extension) {
+               $configRaw = t3lib_div::getUrl(PATH_site . $extension['siteRelPath'] . '/ext_conf_template.txt');
+               $configurationObjectStorage = NULL;
+               if ($configRaw) {
+                       $configurationObjectStorage = $this->convertRawConfigurationToObject($configRaw, $extension);
+               }
+               return $configurationObjectStorage;
+       }
+
+       /**
+        * Converts the raw configuration file content to an configuration object storage
+        *
+        * @param string $configRaw
+        * @param array $extension array with extension information
+        * @return SplObjectStorage
+        */
+       protected function convertRawConfigurationToObject($configRaw, array $extension) {
+               $defaultConfiguration = $this->createArrayFromConstants($configRaw, $extension);
+               $metaInformation = $this->addMetaInformation($defaultConfiguration);
+               $configuration = $this->mergeWithExistingConfiguration($defaultConfiguration, $extension);
+               $hierarchicConfiguration = array();
+
+               foreach ($configuration as $configurationOption) {
+                       $hierarchicConfiguration = t3lib_div::array_merge_recursive_overrule(
+                               $this->buildConfigurationArray($configurationOption, $extension),
+                               $hierarchicConfiguration
+                       );
+               }
+               $configurationObjectStorage = $this->convertHierarchicArrayToObject(
+                       t3lib_div::array_merge_recursive_overrule(
+                               $hierarchicConfiguration,
+                               $metaInformation
+                       )
+               );
+               return $configurationObjectStorage;
+       }
+
+       /**
+        * Builds a configuration array from each line (option) of the config file
+        *
+        * @param string $configurationOption config file line representing one setting
+        * @param array $extension
+        * @return array
+        */
+       protected function buildConfigurationArray($configurationOption, $extension) {
+               $hierarchicConfiguration = array();
+               if (t3lib_div::isFirstPartOfStr($configurationOption['type'], 'user')) {
+                       $configurationOption = $this->extractInformationForConfigFieldsOfTypeUser($configurationOption);
+               } elseif (t3lib_div::isFirstPartOfStr($configurationOption['type'], 'options')) {
+                       $configurationOption = $this->extractInformationForConfigFieldsOfTypeOptions($configurationOption);
+               }
+               if (Tx_Extbase_Utility_Localization::translate($configurationOption['label'], $extension['key'])) {
+                       $configurationOption['label'] = Tx_Extbase_Utility_Localization::translate($configurationOption['label'], $extension['key']);
+               }
+               $configurationOption['labels'] = t3lib_div::trimExplode(
+                       ':',
+                       $configurationOption['label'],
+                       FALSE,
+                       2
+               );
+               $configurationOption['subcat_name'] = $configurationOption['subcat_name'] ? $configurationOption['subcat_name'] : '__default';
+               $hierarchicConfiguration[$configurationOption['cat']][$configurationOption['subcat_name']][$configurationOption['name']] = $configurationOption;
+               return $hierarchicConfiguration;
+       }
+
+       /**
+        * Extracts additional information for fields of type "options"
+        * Extracts "type", "label" and values information
+        *
+        * @param array $configurationOption
+        * @return array
+        */
+       protected function extractInformationForConfigFieldsOfTypeOptions(array $configurationOption) {
+               preg_match('/options\[(.*)\]/is', $configurationOption['type'], $typeMatches);
+               preg_match('/options\[(.*)\]/is', $configurationOption['label'], $labelMatches);
+               $optionValues = explode(',', $typeMatches[1]);
+               $optionLabels = explode(',', $labelMatches[1]);
+               $configurationOption['generic'] = $labelMatches ? array_combine($optionLabels, $optionValues) : array_combine($optionValues, $optionValues);
+               $configurationOption['type'] = 'options';
+               $configurationOption['label'] = str_replace($labelMatches[0], '', $configurationOption['label']);
+               return $configurationOption;
+       }
+
+       /**
+        * Extract additional information for fields of type "user"
+        * Extracts "type" and the function to be called
+        *
+        * @param array $configurationOption
+        * @return array
+        */
+       protected function extractInformationForConfigFieldsOfTypeUser(array $configurationOption) {
+               preg_match('/user\[(.*)\]/is', $configurationOption['type'], $matches);
+               $configurationOption['generic'] = $matches[1];
+               $configurationOption['type'] = 'user';
+               return $configurationOption;
+       }
+
+       /**
+        * Gets meta information from configuration array and
+        * returns only the meta information
+        *
+        * @param array $configuration
+        * @return array
+        */
+       protected function addMetaInformation(&$configuration) {
+               $metaInformation = $configuration['__meta__'] ? $configuration['__meta__'] : array();
+               unset($configuration['__meta__']);
+               return $metaInformation;
+       }
+
+       /**
+        * Generate an array from the typoscript style constants
+        * Add meta data like TSConstantEditor comments
+        *
+        * @param string $configRaw
+        * @param array $extension
+        * @return array
+        */
+       public function createArrayFromConstants($configRaw, array $extension) {
+               $tsStyleConfig = $this->getT3libTsStyleConfig();
+               $tsStyleConfig->doNotSortCategoriesBeforeMakingForm = TRUE;
+               $theConstants = $tsStyleConfig->ext_initTSstyleConfig(
+                       $configRaw,
+                       $extension['siteRelPath'],
+                       PATH_site . $extension['siteRelPath'],
+                       $GLOBALS['BACK_PATH']
+               );
+               if (isset($tsStyleConfig->setup['constants']['TSConstantEditor.'])) {
+                       foreach ($tsStyleConfig->setup['constants']['TSConstantEditor.'] as $category => $highlights) {
+                               $theConstants['__meta__'][rtrim($category, '.')]['highlightText'] = $highlights['description'];
+                               foreach ($highlights as $highlightNumber => $value) {
+                                       if (rtrim($category, '.') == $theConstants[$value]['cat']) {
+                                               $theConstants[$value]['highlight'] = $highlightNumber;
+                                       }
+                               }
+                       }
+               }
+               return $theConstants;
+       }
+
+       /**
+        * Wrapper for makeInstance to make it possible to mock
+        * the class
+        *
+        * @return t3lib_tsStyleConfig
+        */
+       protected function getT3libTsStyleConfig() {
+               return t3lib_div::makeInstance('t3lib_tsStyleConfig');
+       }
+
+       /**
+        * Merge new configuration with existing configuration
+        *
+        * @param array $configuration the new configuration array
+        * @param array $extension the extension information
+        * @return array
+        */
+       protected function mergeWithExistingConfiguration(array $configuration, array $extension) {
+               $currentExtensionConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extension['key']]);
+               if (is_array($currentExtensionConfig)) {
+                       $configuration =  t3lib_div::array_merge_recursive_overrule($configuration, $currentExtensionConfig);
+               }
+               return $configuration;
+       }
+
+       /**
+        * Converts a hierarchic configuration array to an
+        * hierarchic object storage structure
+        *
+        * @param array $configuration
+        * @return SplObjectStorage
+        */
+       protected function convertHierarchicArrayToObject(array $configuration) {
+               $configurationObjectStorage = new SplObjectStorage();
+               foreach ($configuration as $category => $subcategory) {
+                       /** @var $configurationCategoryObject Tx_Extensionmanager_Domain_Model_ConfigurationCategory */
+                       $configurationCategoryObject = $this->objectManager->get('Tx_Extensionmanager_Domain_Model_ConfigurationCategory');
+                       $configurationCategoryObject->setName($category);
+                       if ($subcategory['highlightText']) {
+                               $configurationCategoryObject->setHighlightText($subcategory['highlightText']);
+                               unset($subcategory['highlightText']);
+                       }
+                       foreach ($subcategory as $subcatName => $configurationItems) {
+                               /** @var $configurationSubcategoryObject Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory */
+                               $configurationSubcategoryObject = $this->objectManager->get('Tx_Extensionmanager_Domain_Model_ConfigurationSubcategory');
+                               $configurationSubcategoryObject->setName($subcatName);
+                               foreach ($configurationItems as $configurationItem) {
+                                       /** @var $configurationObject Tx_Extensionmanager_Domain_Model_ConfigurationItem */
+                                       $configurationObject = $this->objectManager->get('Tx_Extensionmanager_Domain_Model_ConfigurationItem');
+                                       if (isset($configurationItem['generic'])) {
+                                               $configurationObject->setGeneric($configurationItem['generic']);
+                                       }
+                                       if (isset($configurationItem['cat'])) {
+                                               $configurationObject->setCategory($configurationItem['cat']);
+                                       }
+                                       if (isset($configurationItem['subcat_name'])) {
+                                               $configurationObject->setSubCategory($configurationItem['subcat_name']);
+                                       }
+                                       if (isset($configurationItem['labels']) && isset($configurationItem['labels'][0])) {
+                                               $configurationObject->setLabelHeadline($configurationItem['labels'][0]);
+                                       }
+                                       if (isset($configurationItem['labels']) && isset($configurationItem['labels'][1])) {
+                                               $configurationObject->setLabelText($configurationItem['labels'][1]);
+                                       }
+                                       if (isset($configurationItem['type'])) {
+                                               $configurationObject->setType($configurationItem['type']);
+                                       }
+                                       if (isset($configurationItem['name'])) {
+                                               $configurationObject->setName($configurationItem['name']);
+                                       }
+                                       if (isset($configurationItem['value'])) {
+                                               $configurationObject->setValue($configurationItem['value']);
+                                       }
+                                       if (isset($configurationItem['highlight'])) {
+                                               $configurationObject->setHighlight($configurationItem['highlight']);
+                                       }
+                                       $configurationSubcategoryObject->addItem($configurationObject);
+                               }
+                               $configurationCategoryObject->addSubcategory($configurationSubcategoryObject);
+                       }
+                       $configurationObjectStorage->attach($configurationCategoryObject);
+               }
+               return $configurationObjectStorage;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Repository/ExtensionRepository.php b/typo3/sysext/extensionmanager/Classes/Domain/Repository/ExtensionRepository.php
new file mode 100644 (file)
index 0000000..8e68ee0
--- /dev/null
@@ -0,0 +1,290 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for extensions
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Repository
+ */
+class Tx_Extensionmanager_Domain_Repository_ExtensionRepository extends Tx_Extbase_Persistence_Repository {
+
+       /**
+        * @var Tx_Extbase_Persistence_Mapper_DataMapper
+        */
+       protected $dataMapper;
+
+       /**
+        * Injects the DataMapper to map records to objects
+        *
+        * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
+        * @return void
+        */
+       public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
+               $this->dataMapper = $dataMapper;
+       }
+
+       /**
+        * Count all extensions
+        *
+        * @return integer
+        */
+       public function countAll() {
+               $query = $this->createQuery();
+               $query = $this->addDefaultConstraints($query);
+               return $query->execute()->count();
+       }
+
+       /**
+        * Finds all extensions
+        *
+        * @return array|Tx_Extbase_Persistence_QueryResultInterface
+        */
+       public function findAll() {
+               $query = $this->createQuery();
+               $query = $this->addDefaultConstraints($query);
+               return $query->execute();
+       }
+
+       /**
+        * Find an extension by extension key ordered by version
+        *
+        * @param string $extensionKey
+        * @return Tx_Extbase_Persistence_QueryResultInterface
+        */
+       public function findByExtensionKeyOrderedByVersion($extensionKey) {
+               $query = $this->createQuery();
+               $query->matching(
+                       $query->logicalAnd(
+                               $query->equals('extensionKey', $extensionKey),
+                               $query->greaterThanOrEqual('reviewState', 0)
+                       )
+               );
+               $query->setOrderings(array('version' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING));
+               return $query->execute();
+       }
+
+       /**
+        * Find one extension by extension key and version
+        *
+        * @param string $extensionKey
+        * @param string $version (example: 4.3.10)
+        * @return array|Tx_Extbase_Persistence_QueryResultInterface
+        */
+       public function findOneByExtensionKeyAndVersion($extensionKey, $version) {
+               $query = $this->createQuery();
+               $query->matching(
+                       $query->logicalAnd(
+                               $query->equals('extensionKey', $extensionKey),
+                               $query->equals('version', $version)
+                       )
+               );
+               return $query->setLimit(1)
+                       ->execute()
+                       ->getFirst();
+       }
+
+       /**
+        * Find an extension by title, author name or extension key
+        * This is the function used by the TER search. It is using a
+        * scoring for the matches to sort the extension with an
+        * exact key match on top
+        *
+        * @param $searchString the string to search for
+        * @return mixed
+        */
+       public function findByTitleOrAuthorNameOrExtensionKey($searchString) {
+               $searchStringForLike = '%' . $searchString . '%';
+               $select = 'cache_extensions.*,
+                       (
+                               (extkey like "' . $searchString . '") * 8 +
+                               (extkey like "' . $searchStringForLike . '") * 4 +
+                               (title like "' . $searchStringForLike . '") * 2 +
+                               (authorname like "' . $searchStringForLike . '")
+                       ) as position';
+               $from = 'cache_extensions';
+               $where = '(
+                                       extkey = "' . $searchString . '"
+                                       OR
+                                       extkey LIKE "' . $searchStringForLike . '"
+                                       OR
+                                       description LIKE "' . $searchStringForLike . '"
+                                       OR
+                                       title LIKE "' . $searchStringForLike . '"
+                               )
+                               AND lastversion=1
+                               HAVING position > 0';
+               $order = 'position desc';
+               $result = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows($select, $from, $where, '', $order);
+               return $this->dataMapper->map('Tx_Extensionmanager_Domain_Model_Extension', $result);
+       }
+
+       /**
+        * Find an extension between a certain version range ordered by version number
+        *
+        * @param string $extensionKey
+        * @param integer $lowestVersion
+        * @param integer $highestVersion
+        * @return Tx_Extbase_Persistence_QueryResultInterface
+        */
+       public function findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $lowestVersion = 0, $highestVersion = 0) {
+               $query = $this->createQuery();
+               $constraint = NULL;
+
+               if ($lowestVersion !== 0 && $highestVersion !== 0) {
+                       $constraint = $query->logicalAnd(
+                               $query->lessThan('integerVersion', $highestVersion),
+                               $query->greaterThan('integerVersion', $lowestVersion),
+                               $query->equals('extensionKey', $extensionKey)
+                       );
+               } elseif ($lowestVersion === 0 && $highestVersion !== 0) {
+                       $constraint = $query->logicalAnd(
+                               $query->lessThan('integerVersion', $highestVersion),
+                               $query->equals('extensionKey', $extensionKey)
+                       );
+               } elseif ($lowestVersion !== 0 && $highestVersion === 0) {
+                       $constraint = $query->logicalAnd(
+                               $query->greaterThan('integerVersion', $lowestVersion),
+                               $query->equals('extensionKey', $extensionKey)
+                       );
+               } elseif ($lowestVersion === 0 && $highestVersion === 0) {
+                       $constraint = $query->equals('extensionKey', $extensionKey);
+               }
+               if ($constraint) {
+                       $query->matching(
+                               $query->logicalAnd(
+                                       $constraint,
+                                       $query->greaterThanOrEqual('reviewState', 0)
+                               )
+                       );
+               }
+               $query->setOrderings(
+                       array(
+                               'integerVersion' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
+                       )
+               );
+               return $query->execute();
+       }
+
+       /**
+        * Count extensions with a certain key between a given version range
+        *
+        * @param string $extensionKey
+        * @param integer $lowestVersion
+        * @param integer $highestVersion
+        * @return integer
+        */
+       public function countByVersionRangeAndExtensionKey($extensionKey, $lowestVersion = 0, $highestVersion = 0) {
+               return $this->findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $lowestVersion, $highestVersion)->count();
+       }
+
+       /**
+        * Find highest version available of an extension
+        *
+        * @param string $extensionKey
+        * @return object
+        */
+       public function findHighestAvailableVersion($extensionKey) {
+               $query = $this->createQuery();
+               $query->matching(
+                       $query->logicalAnd(
+                               $query->equals('extensionKey', $extensionKey),
+                               $query->greaterThanOrEqual('reviewState', 0)
+                       )
+               );
+               $query->setOrderings(
+                       array(
+                               'integerVersion' => Tx_Extbase_Persistence_QueryInterface::ORDER_DESCENDING
+                       )
+               );
+               return $query->setLimit(1)
+                       ->execute()
+                       ->getFirst();
+       }
+
+       /**
+        * Update the lastversion field after update
+        * For performance reason "native" TYPO3_DB is
+        * used here directly.
+        *
+        * @param integer $repositoryUid
+        * @return integer
+        */
+       public function insertLastVersion($repositoryUid = 1) {
+               $groupedRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                       'extkey, version, max(intversion) maxintversion',
+                       'cache_extensions',
+                       'repository=' . intval($repositoryUid),
+                       'extkey'
+               );
+               $extensions = count($groupedRows);
+
+               if ($extensions > 0) {
+                               // set all to 0
+                       $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
+                               'cache_extensions',
+                               'lastversion=1 AND repository=' . intval($repositoryUid),
+                               array('lastversion' => 0)
+                       );
+
+                               // Find latest version of extensions and set lastversion to 1 for these
+                       foreach ($groupedRows as $row) {
+                               $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
+                                       'cache_extensions',
+                                       'extkey=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($row['extkey'], 'cache_extensions') .
+                                               ' AND intversion=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($row['maxintversion'], 'cache_extensions') .
+                                               ' AND repository=' . intval($repositoryUid),
+                                       array('lastversion' => 1)
+                               );
+                       }
+               }
+
+               return $extensions;
+       }
+
+       /**
+        * Adds default constraints to the query - in this case it
+        * enables us to always just search for the latest version of an extension
+        *
+        * @param Tx_Extbase_Persistence_Query $query the query to adjust
+        * @return Tx_Extbase_Persistence_Query
+        */
+       protected function addDefaultConstraints(Tx_Extbase_Persistence_Query $query) {
+               if($query->getConstraint()) {
+                       $query->matching(
+                               $query->logicalAnd(
+                                       $query->getConstraint(),
+                                       $query->equals('lastversion', TRUE)
+                               )
+                       );
+               } else {
+                       $query->matching(
+                               $query->equals('lastversion', TRUE)
+                       );
+               }
+               return $query;
+       }
+}
+?>
diff --git a/typo3/sysext/extensionmanager/Classes/Domain/Repository/RepositoryRepository.php b/typo3/sysext/extensionmanager/Classes/Domain/Repository/RepositoryRepository.php
new file mode 100644 (file)
index 0000000..175e322
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A repository for extension repositories
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Repository
+ */
+class Tx_Extensionmanager_Domain_Repository_RepositoryRepository extends Tx_Extbase_Persistence_Repository {
+
+       /**
+        * Updates ExtCount and lastUpdated in Repository eg after import
+        *
+        * @param integer $extCount
+        * @param integer $uid
+        * @return void
+        */
+       public function updateRepositoryCount($extCount, $uid = 1) {
+               $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
+                       'sys_ter',
+                       'uid=' . intval($uid),
+                       array (
+                               'lastUpdated' => time(),
+                               'extCount' => intval($extCount)
+                       ));
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Exception/ExtensionManager.php b/typo3/sysext/extensionmanager/Classes/Exception/ExtensionManager.php
new file mode 100644 (file)
index 0000000..4d64cfe
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <typo3@susannemoog.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+
+/**
+ * An exception when something is wrong within the extension manager
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Exception
+ */
+class Tx_Extensionmanager_Exception_ExtensionManager extends t3lib_exception {
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Service/Management.php b/typo3/sysext/extensionmanager/Classes/Service/Management.php
new file mode 100644 (file)
index 0000000..c9d0259
--- /dev/null
@@ -0,0 +1,228 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Service class for managing multiple step processes (dependencies for example)
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Service_Management implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Model_DownloadQueue
+        */
+       protected $downloadQueue;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Dependency
+        */
+       protected $dependencyUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_DownloadQueue $downloadQueue
+        * @return void
+        */
+       public function injectDownloadQueue(Tx_Extensionmanager_Domain_Model_DownloadQueue $downloadQueue) {
+               $this->downloadQueue = $downloadQueue;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Dependency $dependencyUtility
+        * @return void
+        */
+       public function injectDependencyUtility(Tx_Extensionmanager_Utility_Dependency $dependencyUtility) {
+               $this->dependencyUtility = $dependencyUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Download
+        */
+       protected $downloadUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Download $downloadUtility
+        * @return void
+        */
+       public function injectDownloadUtility(Tx_Extensionmanager_Utility_Download $downloadUtility) {
+               $this->downloadUtility = $downloadUtility;
+       }
+
+       /**
+        * @param string $extensionKey
+        * @return void
+        */
+       public function markExtensionForInstallation($extensionKey) {
+               $this->downloadQueue->addExtensionToInstallQueue($extensionKey);
+       }
+
+       /**
+        * Mark an extension for download
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       public function markExtensionForDownload(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               $this->downloadQueue->addExtensionToQueue($extension);
+               $this->dependencyUtility->buildExtensionDependenciesTree($extension);
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       public function markExtensionForUpdate(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               $this->downloadQueue->addExtensionToQueue($extension, 'update');
+               $this->dependencyUtility->buildExtensionDependenciesTree($extension);
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return array
+        */
+       public function resolveDependenciesAndInstall(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               $this->dependencyUtility->buildExtensionDependenciesTree($extension);
+               $this->downloadQueue->addExtensionToQueue($extension);
+
+               $queue = $this->downloadQueue->getExtensionQueue();
+               $downloadedDependencies = array();
+               $updatedDependencies = array();
+               $installedDependencies = array();
+
+               if (array_key_exists('download', $queue)) {
+                       $downloadedDependencies = $this->downloadDependencies($queue['download']);
+               }
+
+               if (array_key_exists('update', $queue)) {
+                       $this->downloadDependencies($queue['update']);
+                       $updatedDependencies = $this->uninstallDependenciesToBeUpdated($queue['update']);
+               }
+
+                       // add extension at the end of the download queue
+               $this->downloadQueue->addExtensionToInstallQueue($extension->getExtensionKey());
+
+               $installQueue = $this->downloadQueue->getExtensionInstallStorage();
+               if (count($installQueue) > 0) {
+                       $installedDependencies = $this->installDependencies($installQueue);
+               }
+
+               return array_merge($downloadedDependencies, $updatedDependencies, $installedDependencies);
+       }
+
+       /**
+        * Uninstall extensions that will be updated
+        * This is not strictly necessary but cleaner all in all
+        *
+        * @param array<Tx_Extensionmanager_Domain_Model_Extension> $updateQueue
+        * @return array
+        */
+       protected function uninstallDependenciesToBeUpdated(array $updateQueue) {
+               $resolvedDependencies = array();
+               foreach ($updateQueue as $extensionToUpdate) {
+                       $this->installUtility->uninstall($extensionToUpdate->getExtensionKey());
+                       $resolvedDependencies['updated'][$extensionToUpdate->getExtensionKey()] = $extensionToUpdate;
+               }
+               return $resolvedDependencies;
+       }
+
+       /**
+        * Install dependent extensions
+        *
+        * @param array $installQueue
+        * @return array
+        */
+       protected function installDependencies(array $installQueue) {
+               $resolvedDependencies = array();
+               foreach ($installQueue as $extensionToInstall) {
+                       $this->installUtility->install($extensionToInstall);
+                       $resolvedDependencies['installed'][$extensionToInstall] = $extensionToInstall;
+               }
+               return $resolvedDependencies;
+       }
+
+       /**
+        * Download dependencies
+        * expects an array of extension objects to download
+        *
+        * @param array<Tx_Extensionmanager_Domain_Model_Extension> $downloadQueue
+        * @return array
+        */
+       protected function downloadDependencies(array $downloadQueue) {
+               $resolvedDependencies = array();
+               foreach ($downloadQueue as $extensionToDownload) {
+                       $this->downloadUtility->download($extensionToDownload);
+                       $this->downloadQueue->removeExtensionFromQueue($extensionToDownload);
+                       $resolvedDependencies['downloaded'][$extensionToDownload->getExtensionKey()] = $extensionToDownload;
+                       $this->markExtensionForInstallation($extensionToDownload->getExtensionKey());
+               }
+               return $resolvedDependencies;
+       }
+
+       /**
+        * Get and resolve dependencies
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return array
+        */
+       public function getAndResolveDependencies(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               $this->dependencyUtility->buildExtensionDependenciesTree($extension);
+               $installQueue = $this->downloadQueue->getExtensionInstallStorage();
+               if (is_array($installQueue) && count($installQueue) > 0) {
+                       $installQueue = array('install' => $installQueue);
+               }
+               return array_merge($this->downloadQueue->getExtensionQueue(), $installQueue);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Configuration.php b/typo3/sysext/extensionmanager/Classes/Utility/Configuration.php
new file mode 100644 (file)
index 0000000..94640c0
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with ext_emconf
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_Configuration implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManager
+        */
+       protected $objectManager;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository
+        */
+       protected $configurationItemRepository;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManager $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManager $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository $configurationItemRepository
+        * @return void
+        */
+       public function injectConfigurationItemRepository(
+               Tx_Extensionmanager_Domain_Repository_ConfigurationItemRepository $configurationItemRepository
+       ) {
+               $this->configurationItemRepository = $configurationItemRepository;
+       }
+
+       /**
+        * Saves default configuration of an extension to localConfiguration
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       public function saveDefaultConfiguration($extensionKey) {
+               $currentConfiguration = $this->getCurrentConfiguration($extensionKey);
+               $this->writeConfiguration($currentConfiguration, $extensionKey);
+       }
+
+       /**
+        * Write extension specific configuration to localconf
+        *
+        * @param array $configuration
+        * @param $extensionKey
+        * @return void
+        */
+       public function writeConfiguration(array $configuration, $extensionKey) {
+               /** @var $installUtility Tx_Extensionmanager_Utility_Install */
+               $installUtility = $this->objectManager->get('Tx_Extensionmanager_Utility_Install');
+               $installUtility->writeExtensionTypoScriptStyleConfigurationToLocalconf($extensionKey, $configuration);
+       }
+
+       /**
+        * Get current configuration of an extension
+        *
+        * @param string $extensionKey
+        * @return array
+        */
+       public function getCurrentConfiguration($extensionKey) {
+               $extension = $GLOBALS['TYPO3_LOADED_EXT'][$extensionKey];
+               $defaultConfig = $this->configurationItemRepository->createArrayFromConstants(
+                       t3lib_div::getUrl(PATH_site . $extension['siteRelPath'] . '/ext_conf_template.txt'),
+                       $extension
+               );
+               $currentExtensionConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$extension['key']]);
+               $currentExtensionConfig = is_array($currentExtensionConfig) ? $currentExtensionConfig : array();
+               $currentFullConfiguration = t3lib_div::array_merge_recursive_overrule($defaultConfig, $currentExtensionConfig);
+
+               return $currentFullConfiguration;
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Connection/Ter.php b/typo3/sysext/extensionmanager/Classes/Utility/Connection/Ter.php
new file mode 100644 (file)
index 0000000..f9b6e71
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+/* **************************************************************
+*  Copyright notice
+*
+*  (c) 1999-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
+*  (c) 2006-2010 Karsten Dambekalns <karsten@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * TER2 connection handling class for the TYPO3 Extension Manager.
+ *
+ * It contains methods for downloading and uploading extensions and related code
+ *
+ * @author Karsten Dambekalns <karsten@typo3.org>
+ * @author Kasper Skårhøj <kasperYYYY@typo3.com>
+ * @package TYPO3
+ * @subpackage EM
+ */
+class Tx_Extensionmanager_Utility_Connection_Ter {
+
+       /**
+        * @var string
+        */
+       public $wsdlUrl;
+
+       /**
+        * Fetches an extension from the given mirror
+        *
+        * @param string $extensionKey Extension Key
+        * @param string $version Version to install
+        * @param string $expectedMd5 Expected MD5 hash of extension file
+        * @param string $mirrorUrl URL of mirror to use
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return array T3X data
+        */
+       public function fetchExtension($extensionKey, $version, $expectedMd5, $mirrorUrl) {
+               $extensionPath = t3lib_div::strtolower($extensionKey);
+               $mirrorUrl .= $extensionPath{0} . '/' . $extensionPath{1} . '/' . $extensionPath . '_' . $version . '.t3x';
+               $t3x = t3lib_div::getUrl($mirrorUrl, 0, array(TYPO3_user_agent));
+               $md5 = md5($t3x);
+
+               if ($t3x === FALSE) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               sprintf(
+                                       'The T3X file "%s" could not be fetched. Possible reasons: network problems, allow_url_fopen is off,' .
+                                       ' cURL is not enabled in Install Tool.',
+                                       $mirrorUrl
+                               ),
+                               1334426097
+                       );
+               }
+
+               if ($md5 == $expectedMd5) {
+                               // Fetch and return:
+                       $extensionData = $this->decodeExchangeData($t3x);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Error: MD5 hash of downloaded file not as expected:<br />' . $md5 . ' != ' . $expectedMd5,
+                               1334426098
+                       );
+               }
+
+               return $extensionData;
+       }
+
+
+       /**
+        * Decode server data
+        * This is information like the extension list, extension
+        * information etc., return data after uploads (new em_conf)
+        * On success, returns an array with data array and stats
+        * array as key 0 and 1.
+        *
+        * @param string $externalData Data stream from remove server
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return array $externalData
+        * @see fetchServerData(), processRepositoryReturnData()
+        */
+       public function decodeServerData($externalData) {
+               $parts = explode(':', $externalData, 4);
+               $dat = base64_decode($parts[2]);
+               gzuncompress($dat);
+                       // compare hashes ignoring any leading whitespace. See bug #0000365.
+               if (ltrim($parts[0]) == md5($dat)) {
+                       if ($parts[1] == 'gzcompress') {
+                               if (function_exists('gzuncompress')) {
+                                       $dat = gzuncompress($dat);
+                               } else {
+                                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                               'Decoding Error: No decompressor available for compressed content. gzuncompress() function is not available!',
+                                               1342859463
+                                       );
+                               }
+                       }
+                       $listArr = unserialize($dat);
+
+                       if (!is_array($listArr)) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Error: Unserialized information was not an array - strange!',
+                                       1342859489
+                               );
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Error: MD5 hashes in T3X data did not match!',
+                               1342859505
+                       );
+               }
+               return $listArr;
+       }
+
+       /**
+        * Decodes extension upload array.
+        * This kind of data is when an extension is uploaded to TER
+        *
+        * @param string $stream Data stream
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return array Array with result on success, otherwise an error string.
+        */
+       public function decodeExchangeData($stream) {
+               $parts = explode(':', $stream, 3);
+               if ($parts[1] == 'gzcompress') {
+                       if (function_exists('gzuncompress')) {
+                               $parts[2] = gzuncompress($parts[2]);
+                       } else {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Decoding Error: No decompressor available for compressed content. gzcompress()/gzuncompress() ' .
+                                       'functions are not available!',
+                                       1344761814
+                               );
+                       }
+               }
+               if (md5($parts[2]) == $parts[0]) {
+                       $output = unserialize($parts[2]);
+                       if (!is_array($output)) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Error: Content could not be unserialized to an array. Strange (since MD5 hashes match!)',
+                                       1344761938
+                               );
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Error: MD5 mismatch. Maybe the extension file was downloaded and saved as a text file by the ' .
+                               'browser and thereby corrupted!? (Always select "All" filetype when saving extensions)',
+                               1344761991
+                       );
+               }
+               return $output;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Database.php b/typo3/sysext/extensionmanager/Classes/Utility/Database.php
new file mode 100644 (file)
index 0000000..d17d6a6
--- /dev/null
@@ -0,0 +1,157 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog, <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with database related operations
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_Database implements t3lib_Singleton {
+
+       /**
+        * @var string
+        */
+       const MULTI_LINEBREAKS = "\n\n\n";
+
+       /**
+        * Dump content for static tables
+        *
+        * @param array $dbFields
+        * @return string
+        */
+       public function dumpStaticTables($dbFields) {
+               $out = '';
+                       // Traverse the table list and dump each:
+               foreach ($dbFields as $table => $fields) {
+                       if (is_array($dbFields[$table]['fields'])) {
+                               $header = $this->dumpHeader();
+                               $tableHeader = $this->dumpTableHeader($table, $dbFields[$table], TRUE);
+                               $insertStatements = $this->dumpTableContent($table, $dbFields[$table]['fields']);
+                               $out .= $header . self::MULTI_LINEBREAKS .
+                                       $tableHeader . self::MULTI_LINEBREAKS .
+                                       $insertStatements . self::MULTI_LINEBREAKS;
+                       }
+               }
+               return $out;
+       }
+
+       /**
+        * Header comments of the SQL dump file
+        *
+        * @return string Table header
+        */
+       protected function dumpHeader() {
+               return trim('
+# TYPO3 Extension Manager dump 1.1
+#
+# Host: ' . TYPO3_db_host . '    Database: ' . TYPO3_db . '
+#--------------------------------------------------------
+');
+       }
+
+       /**
+        * Dump CREATE TABLE definition
+        *
+        * @param string $table
+        * @param array $fieldKeyInfo
+        * @param boolean $dropTableIfExists
+        * @return string
+        */
+       protected function dumpTableHeader($table, array $fieldKeyInfo, $dropTableIfExists = FALSE) {
+               $lines = array();
+               $dump = '';
+
+                       // Create field definitions
+               if (is_array($fieldKeyInfo['fields'])) {
+                       foreach ($fieldKeyInfo['fields'] as $fieldN => $data) {
+                               $lines[] = '  ' . $fieldN . ' ' . $data;
+                       }
+               }
+
+                       // Create index key definitions
+               if (is_array($fieldKeyInfo['keys'])) {
+                       foreach ($fieldKeyInfo['keys'] as $fieldN => $data) {
+                               $lines[] = '  ' . $data;
+                       }
+               }
+
+                       // Compile final output:
+               if (count($lines)) {
+                       $dump = trim('
+#
+# Table structure for table "' . $table . '"
+#
+' . ($dropTableIfExists ? 'DROP TABLE IF EXISTS ' . $table . ';
+' : '') . 'CREATE TABLE ' . $table . ' (
+' . implode(',' . LF, $lines) . '
+);');
+               }
+
+               return $dump;
+       }
+
+       /**
+        * Dump table content
+        * Is DBAL compliant, but the dump format is written as MySQL standard.
+        * If the INSERT statements should be imported in a DBMS using other
+        * quoting than MySQL they must first be translated. t3lib_sqlengine
+        * can parse these queries correctly and translate them somehow.
+        *
+        * @param string $table Table name
+        * @param array $fieldStructure Field structure
+        * @return string SQL Content of dump (INSERT statements)
+        */
+       protected function dumpTableContent($table, array $fieldStructure) {
+
+                       // Substitution of certain characters (borrowed from phpMySQL):
+               $search = array('\\', '\'', "\x00", "\x0a", "\x0d", "\x1a");
+               $replace = array('\\\\', '\\\'', '\0', '\n', '\r', '\Z');
+
+               $lines = array();
+
+                       // Select all rows from the table:
+               $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, '');
+
+                       // Traverse the selected rows and dump each row as a line in the file:
+               while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
+                       $values = array();
+                       foreach ($fieldStructure as $field => $structure) {
+                               $values[] = isset($row[$field]) ? "'" . str_replace($search, $replace, $row[$field]) . "'" : 'NULL';
+                       }
+                       $lines[] = 'INSERT INTO ' . $table . ' VALUES (' . implode(', ', $values) . ');';
+               }
+
+                       // Free DB result:
+               $GLOBALS['TYPO3_DB']->sql_free_result($result);
+
+                       // Implode lines and return:
+               return implode(LF, $lines);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Dependency.php b/typo3/sysext/extensionmanager/Classes/Utility/Dependency.php
new file mode 100644 (file)
index 0000000..3e28f2c
--- /dev/null
@@ -0,0 +1,479 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with dependencies
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_Dependency implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManager
+        */
+       protected $objectManager;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       protected $extensionRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_EmConf
+        */
+       protected $emConfUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Service_Management
+        */
+       protected $managementService;
+
+       /**
+        * @var array
+        */
+       protected $availableExtensions = array();
+
+       /**
+        * @var array
+        */
+       protected $errors = array();
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManager $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManager $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_EmConf $emConfUtility
+        * @return void
+        */
+       public function injectEmConfUtility(Tx_Extensionmanager_Utility_EmConf $emConfUtility) {
+               $this->emConfUtility = $emConfUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Service_Management $managementService
+        * @return void
+        */
+       public function injectManagementService(Tx_Extensionmanager_Service_Management $managementService) {
+               $this->managementService = $managementService;
+       }
+
+       /**
+        * Setter for available extensions
+        * gets available extensions from list utility if not already done
+        *
+        * @return void
+        */
+       protected function setAvailableExtensions() {
+               $this->availableExtensions = $this->listUtility->getAvailableExtensions();
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       public function buildExtensionDependenciesTree($extension) {
+               $dependencies = $extension->getDependencies();
+               $this->checkDependencies($dependencies);
+       }
+
+       /**
+        * @param string $dependencies
+        * @return SplObjectStorage
+        */
+       public function convertDependenciesToObjects($dependencies) {
+               $unserializedDependencies = unserialize($dependencies);
+               $dependenciesObject = new SplObjectStorage();
+               foreach ($unserializedDependencies as $dependencyType => $dependencyValues) {
+                       foreach ($dependencyValues as $dependency => $versions) {
+                               if ($dependencyType && $dependency) {
+                                       list($highest, $lowest) = t3lib_utility_VersionNumber::convertVersionsStringToVersionNumbers($versions);
+                                       /** @var $dependencyObject Tx_Extensionmanager_Domain_Model_Dependency */
+                                       $dependencyObject = $this->objectManager->create('Tx_Extensionmanager_Domain_Model_Dependency');
+                                       $dependencyObject->setType($dependencyType);
+                                       $dependencyObject->setIdentifier($dependency);
+                                       $dependencyObject->setLowestVersion($lowest);
+                                       $dependencyObject->setHighestVersion($highest);
+                                       $dependenciesObject->attach($dependencyObject);
+                                       unset($dependencyObject);
+                               }
+                       }
+               }
+               return $dependenciesObject;
+       }
+
+       /**
+        * Checks dependencies for special cases (currently typo3 and php)
+        *
+        * @param SplObjectStorage $dependencies
+        * @return boolean
+        */
+       protected function checkDependencies(SplObjectStorage $dependencies) {
+               $dependenciesToResolve = FALSE;
+               foreach ($dependencies as $dependency) {
+                       $identifier = strtolower($dependency->getIdentifier());
+                       if (in_array($identifier, Tx_Extensionmanager_Domain_Model_Dependency::$specialDependencies)) {
+                               $methodname = 'check' .  ucfirst($identifier) . 'Dependency';
+                               try {
+                                       $this->{$methodname}($dependency);
+                               } catch (Tx_Extensionmanager_Exception_ExtensionManager $e) {
+                                       $this->errors[] = array(
+                                               'identifier' => $identifier,
+                                               'message' => $e->getMessage()
+                                       );
+                               }
+                       } else {
+                               if ($dependency->getType() === 'depends') {
+                                       $dependenciesToResolve = !((bool)$this->checkExtensionDependency($dependency));
+                               }
+                       }
+               }
+               return $dependenciesToResolve;
+       }
+
+       /**
+        * Returns true if current TYPO3 version fulfills extension requirements
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        */
+       protected function checkTypo3Dependency(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $lowerCaseIdentifier = strtolower($dependency->getIdentifier());
+               if ($lowerCaseIdentifier === 'typo3') {
+                       if (
+                               !($dependency->getLowestVersion() === '') &&
+                               version_compare(t3lib_utility_VersionNumber::getNumericTypo3Version(), $dependency->getLowestVersion()) === -1
+                       ) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Your TYPO3 version is lower than necessary. You need at least TYPO3 version ' .
+                                               $dependency->getLowestVersion()
+                               );
+                       }
+                       if (
+                               !($dependency->getHighestVersion() === '') &&
+                               version_compare($dependency->getHighestVersion(), t3lib_utility_VersionNumber::getNumericTypo3Version()) === -1
+                       ) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Your TYPO3 version is higher than allowed. You can use TYPO3 versions ' .
+                                               $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion()
+                               );
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'checkTypo3Dependency can only check TYPO3 dependencies. Found dependency with identifier "' .
+                                       $dependency->getIdentifier() . '"'
+                       );
+               }
+               return TRUE;
+       }
+
+       /**
+        * Returns true if current php version fulfills extension requirements
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        */
+       protected function checkPhpDependency(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $lowerCaseIdentifier = strtolower($dependency->getIdentifier());
+               if ($lowerCaseIdentifier === 'php') {
+                       if (!($dependency->getLowestVersion() === '') && version_compare(PHP_VERSION, $dependency->getLowestVersion()) === -1) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Your PHP version is lower than necessary. You need at least PHP version ' .
+                                               $dependency->getLowestVersion()
+                               );
+                       }
+                       if (!($dependency->getHighestVersion() === '') && version_compare($dependency->getHighestVersion(), PHP_VERSION) === -1) {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'Your PHP version is higher than allowed. You can use PHP versions ' .
+                                               $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion()
+                               );
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'checkPhpDependency can only check PHP dependencies. Found dependency with identifier "' .
+                                       $dependency->getIdentifier() . '"'
+                       );
+               }
+               return TRUE;
+       }
+
+       /**
+        * Main controlling function for checking dependencies
+        * Dependency check is done in the following way:
+        * - installed extension in matching version ? - return true
+        * - available extension in matching version ? - mark for installation
+        * - remote (TER) extension in matching version? - mark for download
+        *
+        * @todo handle exceptions / markForUpload
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        */
+       protected function checkExtensionDependency(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $extensionKey = $dependency->getIdentifier();
+               $extensionIsLoaded = $this->isDependentExtensionLoaded($extensionKey);
+               if ($extensionIsLoaded === TRUE) {
+                       $isLoadedVersionCompatible = $this->isLoadedVersionCompatible($dependency);
+                       if ($isLoadedVersionCompatible === TRUE) {
+                               return TRUE;
+                       } else {
+                               $this->getExtensionFromTer($extensionKey, $dependency);
+                       }
+               } else {
+                       $extensionIsAvailable = $this->isDependentExtensionAvailable($extensionKey);
+                       if ($extensionIsAvailable === TRUE) {
+                               $isAvailableVersionCompatible = $this->isAvailableVersionCompatible($dependency);
+                               if ($isAvailableVersionCompatible) {
+                                       $this->managementService->markExtensionForInstallation($extensionKey);
+                               } else {
+                                       $this->getExtensionFromTer($extensionKey, $dependency);
+                               }
+                       } else {
+                               $this->getExtensionFromTer($extensionKey, $dependency);
+                       }
+               }
+               return FALSE;
+       }
+
+       /**
+        * Handles checks to find a compatible extension version from TER
+        * to fulfill given dependency
+        *
+        * @todo unit tests
+        * @param string $extensionKey
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       protected function getExtensionFromTer($extensionKey, Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $isExtensionDownloadableFromTer = $this->isExtensionDownloadableFromTer($extensionKey);
+               if ($isExtensionDownloadableFromTer === TRUE) {
+                       $isDownloadableVersionCompatible = $this->isDownloadableVersionCompatible($dependency);
+                       if ($isDownloadableVersionCompatible === TRUE) {
+                               $latestCompatibleExtensionByIntegerVersionDependency = $this->getLatestCompatibleExtensionByIntegerVersionDependency(
+                                       $dependency
+                               );
+                               if ($latestCompatibleExtensionByIntegerVersionDependency instanceof Tx_Extensionmanager_Domain_Model_Extension) {
+                                       if ($this->isDependentExtensionLoaded($extensionKey)) {
+                                               $this->managementService->markExtensionForUpdate($latestCompatibleExtensionByIntegerVersionDependency);
+                                       } else {
+                                               $this->managementService->markExtensionForDownload($latestCompatibleExtensionByIntegerVersionDependency);
+                                       }
+                               } else {
+                                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                               'Something went wrong.'
+                                       );
+                               }
+                       } else {
+                               throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                                       'No compatible version found for extension ' . $extensionKey
+                               );
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'The extension ' . $extensionKey . ' is not available from TER.'
+                       );
+               }
+       }
+
+       /**
+        * @param string $extensionKey
+        * @return bool
+        */
+       protected function isDependentExtensionLoaded($extensionKey) {
+               return t3lib_extMgm::isLoaded($extensionKey);
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        */
+       protected function isLoadedVersionCompatible(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $extensionVersion = t3lib_extMgm::getExtensionVersion($dependency->getIdentifier());
+               return $this->isVersionCompatible($extensionVersion, $dependency);
+       }
+
+       /**
+        * @param string $version
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        */
+       protected function isVersionCompatible($version, Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               if (!($dependency->getLowestVersion() === '') && version_compare($version, $dependency->getLowestVersion()) === -1) {
+                       return FALSE;
+               }
+               if (!($dependency->getHighestVersion() === '') && version_compare($dependency->getHighestVersion(), $version) === -1) {
+                       return FALSE;
+               }
+               return TRUE;
+       }
+
+       /**
+        * Checks whether the needed extension is available
+        * (not necessarily installed, but present in system)
+        *
+        * @param string $extensionKey
+        * @return boolean
+        */
+       protected function isDependentExtensionAvailable($extensionKey) {
+               $this->setAvailableExtensions();
+               return array_key_exists($extensionKey, $this->availableExtensions);
+       }
+
+       /**
+        * Checks whether the available version is compatible
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        */
+       protected function isAvailableVersionCompatible(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $this->setAvailableExtensions();
+               $extensionData = $this->emConfUtility->includeEmConf($this->availableExtensions[$dependency->getIdentifier()]);
+               return $this->isVersionCompatible($extensionData['version'], $dependency);
+       }
+
+       /**
+        * Checks whether a ter extension with $extensionKey exists
+        *
+        * @param string $extensionKey
+        * @return boolean
+        */
+       protected function isExtensionDownloadableFromTer($extensionKey) {
+               return ($this->extensionRepository->countByExtensionKey($extensionKey) > 0);
+       }
+
+       /**
+        * Checks whether a compatible version of the extension exists in TER
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return boolean
+        */
+       protected function isDownloadableVersionCompatible(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $versions = $this->getLowestAndHighestIntegerVersions($dependency);
+               return (
+                       count(
+                               $this->extensionRepository->countByVersionRangeAndExtensionKey(
+                                       $dependency->getIdentifier(),
+                                       $versions['lowestIntegerVersion'],
+                                       $versions['highestIntegerVersion']
+                               )
+                       )
+                       > 0
+               );
+       }
+
+       /**
+        * Get the latest compatible version of an extension that
+        * fulfills the given dependency from TER
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return Tx_Extensionmanager_Domain_Model_Extension
+        */
+       protected function getLatestCompatibleExtensionByIntegerVersionDependency(
+               Tx_Extensionmanager_Domain_Model_Dependency $dependency
+       ) {
+               $versions = $this->getLowestAndHighestIntegerVersions($dependency);
+               $compatibleDataSets = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
+                       $dependency->getIdentifier(),
+                       $versions['lowestIntegerVersion'],
+                       $versions['highestIntegerVersion']
+               );
+               return $compatibleDataSets->getFirst();
+       }
+
+       /**
+        * Return array of lowest and highest version of dependency as integer
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Dependency $dependency
+        * @return array
+        */
+       protected function getLowestAndHighestIntegerVersions(Tx_Extensionmanager_Domain_Model_Dependency $dependency) {
+               $lowestVersion = $dependency->getLowestVersion();
+               $lowestVersionInteger = $lowestVersion ? t3lib_utility_VersionNumber::convertVersionNumberToInteger($lowestVersion) : 0;
+               $highestVersion = $dependency->getHighestVersion();
+               $highestVersionInteger = $highestVersion ? t3lib_utility_VersionNumber::convertVersionNumberToInteger($highestVersion) : 0;
+
+               return array (
+                       'lowestIntegerVersion' => $lowestVersionInteger,
+                       'highestIntegerVersion' => $highestVersionInteger
+               );
+       }
+
+       public function findInstalledExtensionsThatDependOnMe($extensionKey) {
+               $availableExtensions = $this->listUtility->getAvailableExtensions();
+               $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensions($availableExtensions);
+               $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
+                       $availableAndInstalledExtensions
+               );
+               $dependentExtensions = array();
+               foreach ($availableAndInstalledExtensions as $availableAndInstalledExtensionKey => $availableAndInstalledExtension) {
+                       if (
+                               isset($availableAndInstalledExtension['installed']) &&
+                               $availableAndInstalledExtension['installed'] === TRUE
+                       ) {
+                               if (
+                                       is_array($availableAndInstalledExtension['constraints']) &&
+                                       is_array($availableAndInstalledExtension['constraints']['depends']) &&
+                                       array_key_exists($extensionKey, $availableAndInstalledExtension['constraints']['depends'])
+                               ) {
+                                       $dependentExtensions[] = $availableAndInstalledExtensionKey;
+                               }
+                       }
+               }
+               return $dependentExtensions;
+       }
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Download.php b/typo3/sysext/extensionmanager/Classes/Utility/Download.php
new file mode 100644 (file)
index 0000000..504ddb7
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with ext_emconf
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_Download implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Connection_Ter
+        */
+       protected $terUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Repository_Helper
+        */
+       protected $repositoryHelper;
+
+       /**
+        * @var string
+        */
+       protected $downloadPath = 'Local';
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Connection_Ter $terUtility
+        * @return void
+        */
+       public function injectTerUtility(Tx_Extensionmanager_Utility_Connection_Ter $terUtility) {
+               $this->terUtility = $terUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Repository_Helper $repositoryHelper
+        * @return void
+        */
+       public function injectRepositoryHelper(Tx_Extensionmanager_Utility_Repository_Helper $repositoryHelper) {
+               $this->repositoryHelper = $repositoryHelper;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_FileHandling
+        */
+       protected $fileHandlingUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility
+        * @return void
+        */
+       public function injectFileHandlingUtility(Tx_Extensionmanager_Utility_FileHandling $fileHandlingUtility) {
+               $this->fileHandlingUtility = $fileHandlingUtility;
+       }
+
+       /**
+        * Download an extension
+        *
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       public function download(Tx_Extensionmanager_Domain_Model_Extension $extension) {
+               $mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
+               $fetchedExtension = $this->terUtility->fetchExtension(
+                       $extension->getExtensionKey(),
+                       $extension->getVersion(),
+                       $extension->getMd5hash(),
+                       $mirrorUrl
+               );
+               if (isset($fetchedExtension['extKey']) && !empty($fetchedExtension['extKey']) && is_string($fetchedExtension['extKey'])) {
+                       $this->fileHandlingUtility->unpackExtensionFromExtensionDataArray($fetchedExtension, $extension, $this->getDownloadPath());
+               }
+       }
+
+       /**
+        * Set the download path
+        *
+        * @param string $downloadPath
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function setDownloadPath($downloadPath) {
+               if (!in_array($downloadPath, Tx_Extensionmanager_Domain_Model_Extension::returnAllowedInstallTypes())) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               htmlspecialchars($downloadPath) . ' not in allowed download paths',
+                               1344766387
+                       );
+               }
+               $this->downloadPath = $downloadPath;
+       }
+
+       /**
+        * Get the download path
+        *
+        * @return string
+        */
+       public function getDownloadPath() {
+               return $this->downloadPath;
+       }
+
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/EmConf.php b/typo3/sysext/extensionmanager/Classes/Utility/EmConf.php
new file mode 100644 (file)
index 0000000..c80f9df
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with ext_emconf
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_EmConf implements t3lib_Singleton {
+
+       /**
+        * Returns the $EM_CONF array from an extensions ext_emconf.php file
+        *
+        * @param array $extension Extension information array
+        * @return array EMconf array values.
+        */
+       public function includeEmConf(array $extension) {
+               $_EXTKEY = $extension['key'];
+               $path = PATH_site . $extension['siteRelPath'] . '/ext_emconf.php';
+               $EM_CONF = NULL;
+
+               if (file_exists($path)) {
+                       include($path);
+                       if (is_array($EM_CONF[$_EXTKEY])) {
+                               return $EM_CONF[$_EXTKEY];
+                       }
+               }
+               return FALSE;
+       }
+
+       /**
+        * Generates the content for the ext_emconf.php file
+        * Sets dependencies from TER data if any
+        *
+        * @internal
+        * @param array $extensionData
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension Extension object from TER data
+        * @return string
+        */
+       public function constructEmConf(array $extensionData, Tx_Extensionmanager_Domain_Model_Extension $extension = NULL) {
+               if (is_object($extension)) {
+                       $extensionData['EM_CONF']['constraints'] = unserialize($extension->getSerializedDependencies());
+               }
+               $emConf = $this->fixEmConf($extensionData['EM_CONF']);
+               $emConf = var_export($emConf, TRUE);
+               $code = '<?php
+
+/***************************************************************
+* Extension Manager/Repository config file for ext "' . $extensionData['extKey'] . '".
+*
+* Auto generated ' . date('d-m-Y H:i') . '
+*
+* Manual updates:
+* Only the data in the array - everything else is removed by next
+* writing. "version" and "dependencies" must not be touched!
+***************************************************************/
+
+$EM_CONF[$_EXTKEY] = ' . $emConf . ';
+
+?>';
+               return str_replace('  ', TAB, $code);
+       }
+
+       /**
+        * Fix the em conf - Converts old / ter em_conf format to new format
+        *
+        * @param array $emConf
+        * @return array
+        */
+       public function fixEmConf(array $emConf) {
+               if (!isset($emConf['constraints']) ||
+                       !isset($emConf['constraints']['depends']) ||
+                       !isset($emConf['constraints']['conflicts']) ||
+                       !isset($emConf['constraints']['suggests'])
+               ) {
+                       if (!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) {
+                               $emConf['constraints']['depends'] = $this->stringToDependency($emConf['dependencies']);
+                               if (strlen($emConf['PHP_version'])) {
+                                       $emConf['constraints']['depends']['php'] = $emConf['PHP_version'];
+                               }
+                               if (strlen($emConf['TYPO3_version'])) {
+                                       $emConf['constraints']['depends']['typo3'] = $emConf['TYPO3_version'];
+                               }
+                       }
+                       if (!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) {
+                               $emConf['constraints']['conflicts'] = $this->dependencyToString($emConf['conflicts']);
+                       }
+                       if (!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) {
+                               $emConf['constraints']['suggests'] = array();
+                       }
+               } elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) {
+                       $emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array();
+                       $emConf['dependencies'] = $this->dependencyToString($emConf['constraints']);
+                       $emConf['conflicts'] = $this->dependencyToString($emConf['constraints'], 'conflicts');
+               }
+
+               unset($emConf['private']);
+               unset($emConf['download_password']);
+               unset($emConf['TYPO3_version']);
+               unset($emConf['PHP_version']);
+
+               return $emConf;
+       }
+
+       /**
+        * Checks whether the passed dependency is TER2-style (array) and returns a
+        * single string for displaying the dependencies.
+        *
+        * It leaves out all version numbers and the "php" and "typo3" dependencies,
+        * as they are implicit and of no interest without the version number.
+        *
+        * @param mixed $dependency Either a string or an array listing dependencies.
+        * @param string $type The dependency type to list if $dep is an array
+        * @return string A simple dependency list for display
+        */
+       public static function dependencyToString($dependency, $type = 'depends') {
+               if (is_array($dependency)) {
+                       if (isset($dependency[$type]['php'])) {
+                               unset($dependency[$type]['php']);
+                       }
+                       if (isset($dependency[$type]['typo3'])) {
+                               unset($dependency[$type]['typo3']);
+                       }
+                       $dependencyString = (count($dependency[$type])) ? implode(',', array_keys($dependency[$type])) : '';
+                       return $dependencyString;
+               }
+               return '';
+       }
+
+       /**
+        * Checks whether the passed dependency is TER-style (string) or
+        * TER2-style (array) and returns a single string for displaying the
+        * dependencies.
+        *
+        * It leaves out all version numbers and the "php" and "typo3" dependencies,
+        * as they are implicit and of no interest without the version number.
+        *
+        * @param mixed $dependency Either a string or an array listing dependencies.
+        * @return string A simple dependency list for display
+        */
+       public function stringToDependency($dependency) {
+               $constraint = array();
+               if (is_string($dependency) && strlen($dependency)) {
+                       $dependency = explode(',', $dependency);
+                       foreach ($dependency as $v) {
+                               $constraint[$v] = '';
+                       }
+               }
+               return $constraint;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/FileHandling.php b/typo3/sysext/extensionmanager/Classes/Utility/FileHandling.php
new file mode 100644 (file)
index 0000000..1ca4191
--- /dev/null
@@ -0,0 +1,364 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with files and folders
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_FileHandling implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extensionmanager_Utility_EmConf
+        */
+       protected $emConfUtility;
+
+       /**
+        * Injector for Tx_Extensionmanager_Utility_EmConf
+        *
+        * @param Tx_Extensionmanager_Utility_EmConf $emConfUtility
+        * @return void
+        */
+       public function injectEmConfUtility(Tx_Extensionmanager_Utility_EmConf $emConfUtility) {
+               $this->emConfUtility = $emConfUtility;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * Injector for Tx_Extensionmanager_Utility_Install
+        *
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * Unpack an extension in t3x data format and write files
+        *
+        * @param array $extensionData
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @param string $pathType
+        * @return void
+        */
+       public function unpackExtensionFromExtensionDataArray(
+               array $extensionData,
+               Tx_Extensionmanager_Domain_Model_Extension $extension = NULL,
+               $pathType = 'Local'
+       ) {
+               $extensionDir = $this->makeAndClearExtensionDir($extensionData['extKey'], $pathType);
+               $files = $this->extractFilesArrayFromExtensionData($extensionData);
+               $directories = $this->extractDirectoriesFromExtensionData($files);
+               $this->createDirectoriesForExtensionFiles($directories, $extensionDir);
+               $this->writeExtensionFiles($files, $extensionDir);
+               $this->writeEmConfToFile($extensionData, $extensionDir, $extension);
+       }
+
+       /**
+        * Extract needed directories from given extensionDataFilesArray
+        *
+        * @param array $files
+        * @return array
+        */
+       protected function extractDirectoriesFromExtensionData(array $files) {
+               $directories = array();
+               foreach ($files as $filePath => $file) {
+                       preg_match('/(.*)\//', $filePath, $matches);
+                       $directories[] = $matches[0];
+               }
+               return $directories;
+       }
+
+       /**
+        * Returns the "FILES" part from the data array
+        *
+        * @param array $extensionData
+        * @return mixed
+        */
+       protected function extractFilesArrayFromExtensionData(array $extensionData) {
+               return $extensionData['FILES'];
+       }
+
+       /**
+        * Loops over an array of directories and creates them in the given root path
+        * It also creates nested directory structures
+        *
+        * @param array $directories
+        * @param string $rootPath
+        * @return void
+        */
+       protected function createDirectoriesForExtensionFiles(array $directories, $rootPath) {
+               foreach ($directories as $directory) {
+                       t3lib_div::mkdir_deep($rootPath . $directory);
+               }
+       }
+
+       /**
+        * Loops over an array of files and writes them to the given rootPath
+        *
+        * @param array $files
+        * @param string $rootPath
+        * @return void
+        */
+       protected function writeExtensionFiles(array $files, $rootPath) {
+               foreach ($files as $file) {
+                       t3lib_div::writeFile($rootPath . $file['name'], $file['content']);
+               }
+       }
+       /**
+        * Removes the current extension of $type and creates the base folder for
+        * the new one (which is going to be imported)
+        *
+        * @param string $extensionkey
+        * @param string $pathType Extension installation scope (Local,Global,System)
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return string
+        */
+       protected function makeAndClearExtensionDir($extensionkey, $pathType = 'Local') {
+               $paths = Tx_Extensionmanager_Domain_Model_Extension::returnInstallPaths();
+               $path = $paths[$pathType];
+               if (!$path || !is_dir($path) || !$extensionkey) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               sprintf('ERROR: The extension install path "%s" was no directory!', $path),
+                               1337280417
+                       );
+               } else {
+                       $extDirPath = $path . $extensionkey . '/';
+                       if (is_dir($extDirPath)) {
+                               $this->removeDirectory($extDirPath);
+                       }
+                       $this->addDirectory($extDirPath);
+               }
+               return $extDirPath;
+       }
+
+       /**
+        * Add specified directory
+        *
+        * @param string $extDirPath
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       protected function addDirectory($extDirPath) {
+               t3lib_div::mkdir($extDirPath);
+               if (!is_dir($extDirPath)) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_create_dir'), $extDirPath),
+                               1337280416
+                       );
+               }
+       }
+
+       /**
+        * Remove specified directory
+        *
+        * @param string $extDirPath
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function removeDirectory($extDirPath) {
+               $res = t3lib_div::rmdir($extDirPath, TRUE);
+               if ($res === FALSE) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_remove_dir'), $extDirPath),
+                               1337280415
+                       );
+               }
+       }
+
+       /**
+        * Constructs emConf and writes it to corresponding file
+        *
+        * @param array $extensionData
+        * @param string $rootPath
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extension
+        * @return void
+        */
+       protected function writeEmConfToFile(
+               array $extensionData,
+               $rootPath,
+               Tx_Extensionmanager_Domain_Model_Extension $extension = NULL
+       ) {
+               $emConfContent = $this->emConfUtility->constructEmConf($extensionData, $extension);
+               t3lib_div::writeFile($rootPath . 'ext_emconf.php', $emConfContent);
+       }
+
+       /**
+        * Is the given path a valid path for extension installation
+        *
+        * @param string $path the absolute (!) path in question
+        * @return boolean
+        */
+       public function isValidExtensionPath($path) {
+               $allowedPaths = Tx_Extensionmanager_Domain_Model_Extension::returnAllowedInstallPaths();
+               foreach ($allowedPaths as $allowedPath) {
+                       if (t3lib_div::isFirstPartOfStr($path, $allowedPath)) {
+                               return TRUE;
+                       }
+               }
+               return FALSE;
+       }
+
+       /**
+        * Returns absolute path
+        *
+        * @param string $relativePath
+        * @return string
+        */
+       public function returnAbsolutePath($relativePath) {
+               return t3lib_div::resolveBackPath(PATH_site . $relativePath);
+       }
+
+       /**
+        * Get extension path for an available or installed extension
+        *
+        * @param string $extension
+        * @return string
+        */
+       public function getAbsoluteExtensionPath($extension) {
+               $extension = $this->installUtility->enrichExtensionWithDetails($extension);
+               $absolutePath = $this->returnAbsolutePath($extension['siteRelPath']);
+               return $absolutePath;
+       }
+
+       /**
+        * Create a zip file from an extension
+        *
+        * @param array $extension
+        * @return string
+        */
+       public function createZipFileFromExtension($extension) {
+               $extensionPath = $this->getAbsoluteExtensionPath($extension);
+               $fileName = PATH_site . 'typo3temp/' . $extension . '.zip';
+               $zip = new ZipArchive;
+               $zip->open($fileName, ZipArchive::CREATE);
+               $iterator = new RecursiveIteratorIterator(
+                       new RecursiveDirectoryIterator($extensionPath)
+               );
+
+               foreach ($iterator as $key => $value) {
+                       $archiveName = str_replace($extensionPath, '', $key);
+                       if (t3lib_utility_String::isLastPartOfString($key, '.')) {
+                               continue;
+                       } else {
+                               $zip->addFile($key, $archiveName);
+                       }
+               }
+
+               $zip->close();
+               return $fileName;
+       }
+
+       /**
+        * Unzip an extension.zip.
+        *
+        * @param string $file path to zip file
+        * @param string $fileName file name
+        * @param string $pathType path type (Local, Global, System)
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function unzipExtensionFromFile($file, $fileName, $pathType = 'Local') {
+               $extensionDir = $this->makeAndClearExtensionDir($fileName, $pathType);
+               $zip = zip_open($file);
+               if (is_resource($zip)) {
+                       while (($zipEntry = zip_read($zip)) !== FALSE) {
+                               if (strpos(zip_entry_name($zipEntry), DIRECTORY_SEPARATOR) !== FALSE) {
+                                       $last = strrpos(zip_entry_name($zipEntry), DIRECTORY_SEPARATOR);
+                                       $dir = substr(zip_entry_name($zipEntry), 0, $last);
+                                       $file = substr(zip_entry_name($zipEntry), strrpos(zip_entry_name($zipEntry), DIRECTORY_SEPARATOR) + 1);
+                                       if (!is_dir($dir)) {
+                                               t3lib_div::mkdir_deep($extensionDir . $dir);
+                                       }
+                                       if (strlen(trim($file)) > 0) {
+                                               $return = t3lib_div::writeFile(
+                                                       $extensionDir . $dir . '/' . $file, zip_entry_read($zipEntry, zip_entry_filesize($zipEntry))
+                                               );
+                                               if ($return === FALSE) {
+                                                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Could not write file ' . $file, 1344691048);
+                                               }
+                                       }
+                               } else {
+                                       t3lib_div::writeFile($extensionDir . zip_entry_name($zipEntry), zip_entry_read($zipEntry, zip_entry_filesize($zipEntry)));
+                               }
+                       }
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Unable to open zip file ' . $file, 1344691049);
+               }
+       }
+
+       /**
+        * Sends a zip file to the browser and deletes it afterwards
+        *
+        * @param string $fileName
+        * @param string $downloadName
+        * @return void
+        */
+       public function sendZipFileToBrowserAndDelete($fileName, $downloadName = '') {
+               if ($downloadName === '') {
+                       $downloadName = basename($fileName, '.zip');
+               }
+               header('Content-Type: application/zip');
+               header('Content-Length: ' . filesize($fileName));
+               header('Content-Disposition: attachment; filename="' . $downloadName . '.zip"');
+               readfile($fileName);
+               unlink($fileName);
+               exit();
+       }
+
+       /**
+        * Sends the sql dump file to the browser and deletes it afterwards
+        *
+        * @param string $fileName
+        * @param string $downloadName
+        * @return void
+        */
+       public function sendSqlDumpFileToBrowserAndDelete($fileName, $downloadName = '') {
+               if ($downloadName === '') {
+                       $downloadName = basename($fileName, '.sql');
+               } else {
+                       $downloadName = basename($downloadName, '.sql');
+               }
+               header('Content-Type: text');
+               header('Content-Length: ' . filesize($fileName));
+               header('Content-Disposition: attachment; filename="' . $downloadName . '.sql"');
+               readfile($fileName);
+               unlink($fileName);
+               exit();
+       }
+
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Importer/ExtensionList.php b/typo3/sysext/extensionmanager/Classes/Utility/Importer/ExtensionList.php
new file mode 100644 (file)
index 0000000..811e608
--- /dev/null
@@ -0,0 +1,233 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ * Steffen Kamper <info@sk-typo3.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ * Module: Extension manager - Extension list importer
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ */
+
+/**
+ * Importer object for extension list
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since 2010-02-10
+ * @package Extension Manager
+ * @subpackage Utility/Importer
+ */
+class Tx_Extensionmanager_Utility_Importer_ExtensionList implements SplObserver {
+
+       /**
+        * Keeps instance of a XML parser.
+        *
+        * @var Tx_Extensionmanager_Utility_Parser_ExtensionXmlAbstractParser
+        */
+       protected $parser;
+
+       /**
+        * Keeps number of processed version records.
+        *
+        * @var integer
+        */
+       protected $sumRecords = 0;
+
+       /**
+        * Keeps record values to be inserted into database.
+        *
+        * @var array
+        */
+       protected $arrRows = array();
+
+       /**
+        * Keeps fieldnames of cache_extension table.
+        *
+        * @var array
+        */
+       static protected $fieldNames = array(
+               'extkey',
+               'version',
+               'intversion',
+               'alldownloadcounter',
+               'downloadcounter',
+               'title',
+               'ownerusername',
+               'authorname',
+               'authoremail',
+               'authorcompany',
+               'lastuploaddate',
+               't3xfilemd5',
+               'repository',
+               'state',
+               'reviewstate',
+               'category',
+               'description',
+               'dependencies',
+               'uploadcomment'
+       );
+
+       /**
+        * Keeps indexes of fields that should not be quoted.
+        *
+        * @var array
+        */
+       static protected $fieldIndicesNoQuote = array(2, 3, 4, 10, 12, 13, 14, 15);
+
+
+       /**
+        * Keeps repository UID.
+        *
+        * The UID is necessary for inserting records.
+        *
+        * @var integer
+        */
+       protected $repositoryUid = 1;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_RepositoryRepository
+        */
+       protected $repositoryRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       protected $extensionRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Model_Extension
+        */
+       protected $extensionModel;
+
+       /**
+        * Class constructor.
+        *
+        * Method retrieves and initializes extension XML parser instance.
+        *
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        */
+       public function __construct() {
+               /** @var $objectManager Tx_Extbase_Object_ObjectManager */
+               $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
+               $this->repositoryRepository = $this->objectManager->get('Tx_Extensionmanager_Domain_Repository_RepositoryRepository');
+               $this->extensionRepository = $this->objectManager->get('Tx_Extensionmanager_Domain_Repository_ExtensionRepository');
+               $this->extensionModel = $this->objectManager->get('Tx_Extensionmanager_Domain_Model_Extension');
+                       // TODO catch parser exception
+               $this->parser = Tx_Extensionmanager_Utility_Parser_XmlParserFactory::getParserInstance('extension');
+               if (is_object($this->parser)) {
+                       $this->parser->attach($this);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(get_class($this) . ': No XML parser available.');
+               }
+       }
+
+       /**
+        * Method initializes parsing of extension.xml.gz file.
+        *
+        * @param string $localExtensionListFile absolute path to extension list xml.gz
+        * @param integer $repositoryUid UID of repository when inserting records into DB
+        * @return integer total number of imported extension versions
+        */
+       public function import($localExtensionListFile, $repositoryUid = NULL) {
+               if (!is_null($repositoryUid) && is_int($repositoryUid)) {
+                       $this->repositoryUid = $repositoryUid;
+               }
+               $zlibStream = 'compress.zlib://';
+               $this->sumRecords = 0;
+
+               $this->parser->parseXML($zlibStream . $localExtensionListFile);
+
+                       // flush last rows to database if existing
+               if (count($this->arrRows)) {
+                       $GLOBALS['TYPO3_DB']->exec_INSERTmultipleRows(
+                               'cache_extensions',
+                               self::$fieldNames,
+                               $this->arrRows,
+                               self::$fieldIndicesNoQuote
+                       );
+               }
+               $extensions = $this->extensionRepository->insertLastVersion($this->repositoryUid);
+               $this->repositoryRepository->updateRepositoryCount($extensions, $this->repositoryUid);
+
+               return $this->sumRecords;
+       }
+
+       /**
+        * Method collects and stores extension version details into the database.
+        *
+        * @param SplSubject &$subject a subject notifying this observer
+        * @return void
+        */
+       protected function loadIntoDatabase(SplSubject &$subject) {
+                       // flush every 50 rows to database
+               if ($this->sumRecords !== 0 && $this->sumRecords % 50 === 0) {
+                       $GLOBALS['TYPO3_DB']->exec_INSERTmultipleRows(
+                               'cache_extensions',
+                               self::$fieldNames,
+                               $this->arrRows,
+                               self::$fieldIndicesNoQuote
+                       );
+                       $this->arrRows = array();
+               }
+               $versionRepresentations = t3lib_utility_VersionNumber::convertVersionStringToArray($subject->getVersion());
+                       // order must match that of self::$fieldNamses!
+               $this->arrRows[] = array(
+                       $subject->getExtkey(),
+                       $subject->getVersion(),
+                       $versionRepresentations['version_int'],
+                       intval($subject->getAlldownloadcounter()),
+                       intval($subject->getDownloadcounter()),
+                       !is_null($subject->getTitle()) ? $subject->getTitle() : '',
+                       $subject->getOwnerusername(),
+                       !is_null($subject->getAuthorname()) ? $subject->getAuthorname() : '',
+                       !is_null($subject->getAuthoremail()) ? $subject->getAuthoremail() : '',
+                       !is_null($subject->getAuthorcompany()) ? $subject->getAuthorcompany() : '',
+                       intval($subject->getLastuploaddate()),
+                       $subject->getT3xfilemd5(),
+                       $this->repositoryUid,
+                       $this->extensionModel->getDefaultState($subject->getState() ? $subject->getState() : ''),
+                       intval($subject->getReviewstate()),
+                       $this->extensionModel->getDefaultCategory($subject->getCategory() ? $subject->getCategory() : ''),
+                       $subject->getDescription() ? $subject->getDescription() : '',
+                       $subject->getDependencies() ? $subject->getDependencies() : '',
+                       $subject->getUploadcomment() ? $subject->getUploadcomment() : '',
+               );
+               ++$this->sumRecords;
+       }
+
+       /**
+        * Method receives an update from a subject.
+        *
+        * @param SplSubject $subject a subject notifying this observer
+        * @return void
+        */
+       public function update(SplSubject $subject) {
+               if (is_subclass_of($subject, 'Tx_Extensionmanager_Utility_Parser_ExtensionXmlAbstractParser')) {
+                       $this->loadIntoDatabase($subject);
+               }
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Importer/MirrorList.php b/typo3/sysext/extensionmanager/Classes/Utility/Importer/MirrorList.php
new file mode 100644 (file)
index 0000000..d54b41a
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ *                Steffen Kamper <info@sk-typo3.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ * Module: Extension manager - Mirror list importer
+ *
+ * @author  Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author  Steffen Kamper <info@sk-typo3.de>
+ */
+
+
+/**
+ * Importer object for mirror list.
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since 2010-02-10
+ * @package Extension Manager
+ * @subpackage Utility/Importer
+ */
+class Tx_Extensionmanager_Utility_Importer_MirrorList implements SplObserver {
+
+       /**
+        * Keeps instance of a XML parser.
+        *
+        * @var  Tx_Extensionmanager_Utility_Parser_MirrorXmlAbstractParser
+        */
+       protected $parser;
+
+       /**
+        * Keeps mirrors' details.
+        *
+        * @var  array
+        */
+       protected $arrTmpMirrors = array();
+
+       /**
+        * Class constructor.
+        *
+        * Method retrieves and initializes extension XML parser instance.
+        *
+        * @throws tx_em_XmlException
+        */
+       public function __construct() {
+                       // TODO catch parser exception
+               $this->parser = Tx_Extensionmanager_Utility_Parser_XmlParserFactory::getParserInstance('mirror');
+               if (is_object($this->parser)) {
+                       $this->parser->attach($this);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(get_class($this) . ': No XML parser available.',
+                       1342640390);
+               }
+       }
+
+       /**
+        * Method collects mirrors' details and returns instance of
+        * Tx_Extensionmanager_Domain_Model_Mirrors with retrieved details.
+        *
+        * @param string $localMirrorListFile absolute path to local mirror xml.gz file
+        * @return Tx_Extensionmanager_Domain_Model_Mirrors
+        */
+       public function getMirrors($localMirrorListFile) {
+               $zlibStream = 'compress.zlib://';
+
+               $this->parser->parseXml($zlibStream . $localMirrorListFile);
+               /** @var $objRepositoryMirrors Tx_Extensionmanager_Domain_Model_Mirrors */
+               $objRepositoryMirrors = t3lib_div::makeInstance('Tx_Extensionmanager_Domain_Model_Mirrors');
+               $objRepositoryMirrors->setMirrors($this->arrTmpMirrors);
+               $this->arrTmpMirrors = array();
+               return $objRepositoryMirrors;
+       }
+
+       /**
+        * Method receives an update from a subject.
+        *
+        * @param SplSubject $subject a subject notifying this observer
+        * @return void
+        */
+       public function update(SplSubject $subject) {
+                       // TODO mirrorxml_abstract_parser
+               if (is_subclass_of($subject, 'Tx_Extensionmanager_Utility_Parser_XmlAbstractParser')) {
+                       $this->arrTmpMirrors[] = $subject->getAll();
+               }
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Install.php b/typo3/sysext/extensionmanager/Classes/Utility/Install.php
new file mode 100644 (file)
index 0000000..72d2ae3
--- /dev/null
@@ -0,0 +1,398 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Susanne Moog <susanne.moog@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Extension Manager Install Utility
+ *
+ * @author Susanne Moog <susanne.moog@typo3.org>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_Install implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManager
+        */
+       public $objectManager;
+
+       /**
+        * @var t3lib_install_Sql
+        */
+       public $installToolSqlParser;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Dependency
+        */
+       protected $dependencyUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_FileHandling
+        */
+       protected $filehandlingUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_List
+        */
+       protected $listUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Database
+        */
+       protected $databaseUtility;
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       public $extensionRepository;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_List $listUtility
+        * @return void
+        */
+       public function injectListUtility(Tx_Extensionmanager_Utility_List $listUtility) {
+               $this->listUtility = $listUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_FileHandling $filehandlingUtility
+        * @return void
+        */
+       public function injectFilehandlingUtility(Tx_Extensionmanager_Utility_FileHandling $filehandlingUtility) {
+               $this->filehandlingUtility = $filehandlingUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Dependency $dependencyUtility
+        * @return void
+        */
+       public function injectDependencyUtility(Tx_Extensionmanager_Utility_Dependency $dependencyUtility) {
+               $this->dependencyUtility = $dependencyUtility;
+       }
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Database $databaseUtility
+        * @return void
+        */
+       public function injectDatabaseUtility(Tx_Extensionmanager_Utility_Database $databaseUtility) {
+               $this->databaseUtility = $databaseUtility;
+       }
+
+       /**
+        * Inject emConfUtility
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+
+       /**
+        * __construct
+        */
+       public function __construct() {
+               $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
+               /** @var $installToolSqlParser t3lib_install_Sql */
+               $this->installToolSqlParser = $this->objectManager->get('t3lib_install_Sql');
+               $this->dependencyUtility = $this->objectManager->get('Tx_Extensionmanager_Utility_Dependency');
+       }
+
+       /**
+        * Helper function to uninstall an extension
+        *
+        * @param string $extensionKey
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function uninstall($extensionKey) {
+               $dependentExtensions = $this->dependencyUtility->findInstalledExtensionsThatDependOnMe($extensionKey);
+               if (is_array($dependentExtensions) && count($dependentExtensions) > 0) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(
+                               'Cannot deactivate extension ' . $extensionKey . ' - The extension(s) ' . implode(',', $dependentExtensions) .
+                               ' depend on it',
+                               1342554622
+                       );
+               } else {
+                       $this->unloadExtension($extensionKey);
+               }
+       }
+
+       /**
+        * Wrapper function for unloading extensions
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       protected function unloadExtension($extensionKey) {
+               t3lib_extMgm::unloadExtension($extensionKey);
+       }
+
+       /**
+        * Helper function to install an extension
+        * also processes db updates and clears the cache if the extension asks for it
+        *
+        * @param string $extensionKey
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function install($extensionKey) {
+               $extension = $this->enrichExtensionWithDetails($extensionKey);
+               $this->processDatabaseUpdates($extension);
+               if ($extension['clearcacheonload']) {
+                       $GLOBALS['typo3CacheManager']->flushCaches();
+               }
+               $this->loadExtension($extensionKey);
+               $this->reloadCaches();
+               $this->saveDefaultConfiguration($extension['key']);
+       }
+
+       /**
+        * Wrapper function for loading extensions
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       protected function loadExtension($extensionKey) {
+               t3lib_extMgm::loadExtension($extensionKey);
+       }
+
+       /**
+        * Fetch additional information for an extension key
+        *
+        * @param string $extensionKey
+        * @internal
+        * @return mixed
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        */
+       public function enrichExtensionWithDetails($extensionKey) {
+               $availableExtensions = $this->listUtility->getAvailableExtensions();
+               if (isset($availableExtensions[$extensionKey])) {
+                       $extension = $availableExtensions[$extensionKey];
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Extension ' . $extensionKey . ' is not available', 1342864081);
+               }
+               $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
+                       array($extensionKey => $extension)
+               );
+               return $availableAndInstalledExtensions[$extensionKey];
+       }
+
+       /**
+        * Gets the content of the ext_tables.sql and ext_tables_static+adt.sql files
+        * Additionally adds the table definitions for the cache tables
+        *
+        * @param string $extension
+        * @return void
+        */
+       public function processDatabaseUpdates($extension) {
+               $extTablesSqlFile = PATH_site . $extension['siteRelPath'] . '/ext_tables.sql';
+               if (file_exists($extTablesSqlFile)) {
+                       $extTablesSqlContent = t3lib_div::getUrl($extTablesSqlFile);
+                       $extTablesSqlContent .= t3lib_cache::getDatabaseTableDefinitions();
+                       $this->updateDbWithExtTablesSql($extTablesSqlContent);
+               }
+               $extTablesStaticSqlFile = PATH_site . $extension['siteRelPath'] .  '/ext_tables_static+adt.sql';
+               if (file_exists($extTablesStaticSqlFile)) {
+                       $extTablesStaticSqlContent = t3lib_div::getUrl($extTablesStaticSqlFile);
+                       $this->importStaticSql($extTablesStaticSqlContent);
+               }
+       }
+
+       /**
+        * Wrapper for make instance to make
+        * mocking possible
+        *
+        * @return t3lib_install
+        */
+       protected function getT3libInstallInstance() {
+               return t3lib_div::makeInstance('t3lib_install');
+       }
+
+       /**
+        * Reload Cache files and Typo3LoadedExtensions
+        *
+        * @return void
+        */
+       public function reloadCaches() {
+               t3lib_extMgm::removeCacheFiles();
+
+                       // Set new extlist / extlistArray for extension load changes at runtime
+               $localConfiguration = t3lib_Configuration::getLocalConfiguration();
+               $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'] = $localConfiguration['EXT']['extList'];
+               $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray'] = $localConfiguration['EXT']['extListArray'];
+
+               Typo3_Bootstrap::getInstance()
+                       ->populateTypo3LoadedExtGlobal(FALSE)
+                       ->loadAdditionalConfigurationFromExtensions(FALSE);
+       }
+
+       /**
+        * Save default configuration of an extension
+        *
+        * @param string $extensionKey
+        * @return void
+        */
+       protected function saveDefaultConfiguration($extensionKey) {
+               /** @var $configUtility Tx_Extensionmanager_Utility_Configuration */
+               $configUtility = $this->objectManager->get('Tx_Extensionmanager_Utility_Configuration');
+               $configUtility->saveDefaultConfiguration($extensionKey);
+       }
+
+       /**
+        * Update database / process db updates from ext_tables
+        *
+        * @param string $rawDefinitions The raw SQL statements from ext_tables.sql
+        * @return void
+        */
+       public function updateDbWithExtTablesSql($rawDefinitions) {
+               $fieldDefinitionsFromFile = $this->installToolSqlParser->getFieldDefinitions_fileContent($rawDefinitions);
+
+               if (count($fieldDefinitionsFromFile)) {
+                       $fieldDefinitionsFromCurrentDatabase = $this->installToolSqlParser->getFieldDefinitions_database();
+                       $diff = $this->installToolSqlParser->getDatabaseExtra($fieldDefinitionsFromFile, $fieldDefinitionsFromCurrentDatabase);
+                       $updateStatements = $this->installToolSqlParser->getUpdateSuggestions($diff);
+
+                       foreach ((array)$updateStatements['add'] as $string) {
+                               $GLOBALS['TYPO3_DB']->admin_query($string);
+                       }
+                       foreach ((array)$updateStatements['change'] as $string) {
+                               $GLOBALS['TYPO3_DB']->admin_query($string);
+                       }
+                       foreach ((array)$updateStatements['create_table'] as $string) {
+                               $GLOBALS['TYPO3_DB']->admin_query($string);
+                       }
+               }
+       }
+
+       /**
+        * Import static SQL data (normally used for ext_tables_static+adt.sql)
+        *
+        * @param string $rawDefinitions
+        * @return void
+        */
+       public function importStaticSql($rawDefinitions) {
+               $statements = $this->installToolSqlParser->getStatementarray($rawDefinitions, 1);
+               list($statementsPerTable, $insertCount) = $this->installToolSqlParser->getCreateTables($statements, 1);
+
+                       // Traverse the tables
+               foreach ($statementsPerTable as $table => $query) {
+                       $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table);
+                       $GLOBALS['TYPO3_DB']->admin_query($query);
+
+                       if ($insertCount[$table]) {
+                               $insertStatements = $this->installToolSqlParser->getTableInsertStatements($statements, $table);
+
+                               foreach ($insertStatements as $statement) {
+                                       $GLOBALS['TYPO3_DB']->admin_query($statement);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Writes the TSstyleconf values to "localconf.php"
+        * Removes the temp_CACHED* files before return.
+        *
+        * @param string $extensionKey Extension key
+        * @param array $newConfiguration Configuration array to write back
+        * @return void
+        */
+       public function writeExtensionTypoScriptStyleConfigurationToLocalconf($extensionKey, $newConfiguration) {
+               t3lib_Configuration::setLocalConfigurationValueByPath('EXT/extConf/' . $extensionKey, serialize($newConfiguration));
+               t3lib_extMgm::removeCacheFiles();
+       }
+
+       /**
+        * Remove an extension (delete the directory)
+        *
+        * @param string $extension
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager
+        * @return void
+        */
+       public function removeExtension($extension) {
+               $absolutePath = $this->filehandlingUtility->getAbsoluteExtensionPath($extension);
+               if ($this->filehandlingUtility->isValidExtensionPath($absolutePath)) {
+                       $this->filehandlingUtility->removeDirectory($absolutePath);
+               } else {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('No valid extension path given.', 1342875724);
+               }
+       }
+
+       /**
+        * Get the data dump for an extension
+        *
+        * @param string $extension
+        * @return array
+        */
+       public function getExtensionSqlDataDump($extension) {
+               $extension = $this->enrichExtensionWithDetails($extension);
+               $filePrefix = PATH_site . $extension['siteRelPath'];
+               $sqlData['extTables'] = $this->getSqlDataDumpForFile($filePrefix . '/ext_tables.sql');
+               $sqlData['staticSql'] = $this->getSqlDataDumpForFile($filePrefix . '/ext_tables_static+adt.sql');
+               return $sqlData;
+       }
+
+       /**
+        * Gets the sql data dump for a specific sql file (for example ext_tables.sql)
+        *
+        * @param string $sqlFile
+        * @return string
+        */
+       protected function getSqlDataDumpForFile($sqlFile) {
+               $sqlData = '';
+               if (file_exists($sqlFile)) {
+                       $sqlContent = t3lib_div::getUrl($sqlFile);
+                       $fieldDefinitions = $this->installToolSqlParser->getFieldDefinitions_fileContent($sqlContent);
+                       $sqlData = $this->databaseUtility->dumpStaticTables($fieldDefinitions);
+               }
+               return $sqlData;
+       }
+
+       /**
+        * Checks if an update for an extension is available
+        *
+        * @internal
+        * @param Tx_Extensionmanager_Domain_Model_Extension $extensionData
+        * @return boolean
+        */
+       public function isUpdateAvailable(Tx_Extensionmanager_Domain_Model_Extension $extensionData) {
+                       // Only check for update for TER extensions
+               $version = $extensionData->getIntegerVersion();
+               /** @var $highestTerVersionExtension Tx_Extensionmanager_Domain_Model_Extension */
+               $highestTerVersionExtension = $this->extensionRepository->findHighestAvailableVersion($extensionData->getExtensionKey());
+               if ($highestTerVersionExtension instanceof Tx_Extensionmanager_Domain_Model_Extension) {
+                       $highestVersion = $highestTerVersionExtension->getIntegerVersion();
+                       if ($highestVersion > $version) {
+                               return TRUE;
+                       }
+               }
+               return FALSE;
+       }
+
+}
+
+?>
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/List.php b/typo3/sysext/extensionmanager/Classes/Utility/List.php
new file mode 100644 (file)
index 0000000..c587fa0
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Utility for dealing with extension list related functions
+ *
+ * @author Susanne Moog <typo3@susannemoog.de>
+ * @package Extension Manager
+ * @subpackage Utility
+ */
+class Tx_Extensionmanager_Utility_List implements t3lib_Singleton {
+
+       /**
+        * @var Tx_Extbase_Object_ObjectManager
+        */
+       public $objectManager;
+
+       /**
+        * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
+        * @return void
+        */
+       public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
+               $this->objectManager = $objectManager;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Utility_EmConf
+        */
+       public $emConfUtility;
+
+       /**
+        * Inject emConfUtility
+        *
+        * @param Tx_Extensionmanager_Utility_EmConf $emConfUtility
+        * @return void
+        */
+       public function injectEmConfUtility(Tx_Extensionmanager_Utility_EmConf $emConfUtility) {
+               $this->emConfUtility = $emConfUtility;
+       }
+
+       /**
+        * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
+        */
+       public $extensionRepository;
+
+       /**
+        * @var Tx_Extensionmanager_Utility_Install
+        */
+       protected $installUtility;
+
+       /**
+        * @param Tx_Extensionmanager_Utility_Install $installUtility
+        * @return void
+        */
+       public function injectInstallUtility(Tx_Extensionmanager_Utility_Install $installUtility) {
+               $this->installUtility = $installUtility;
+       }
+
+       /**
+        * Inject emConfUtility
+        *
+        * @param Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository
+        * @return void
+        */
+       public function injectExtensionRepository(Tx_Extensionmanager_Domain_Repository_ExtensionRepository $extensionRepository) {
+               $this->extensionRepository = $extensionRepository;
+       }
+       /**
+        * Returns the list of available (installed) extensions
+        *
+        * @return array Array with two sub-arrays, list array (all extensions with info) and category index
+        * @see getInstExtList()
+        */
+       public function getAvailableExtensions() {
+               $extensions = array();
+               $paths = Tx_Extensionmanager_Domain_Model_Extension::returnInstallPaths();
+               foreach ($paths as $installationType => $path) {
+                       try {
+                               if (is_dir($path)) {
+                                       $extList = t3lib_div::get_dirs($path);
+                                       if (is_array($extList)) {
+                                               foreach ($extList as $extKey) {
+                                                       $extensions[$extKey] = array(
+                                                               'siteRelPath' => str_replace(PATH_site, '', $path . $extKey),
+                                                               'type' => $installationType,
+                                                               'key' => $extKey
+                                                       );
+                                               }
+                                       }
+                               }
+                       } catch (Exception $e) {
+                               t3lib_div::sysLog($e->getMessage(), 'extensionmanager');
+                       }
+               }
+               return $extensions;
+       }
+
+       /**
+        * Reduce the available extensions list to only installed extensions
+        *
+        * @param array $availableExtensions
+        * @return array
+        */
+       public function getAvailableAndInstalledExtensions(array $availableExtensions) {
+               foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extKey => $properties) {
+                       if (array_key_exists($extKey, $availableExtensions)) {
+                               $availableExtensions[$extKey]['installed'] = TRUE;
+                       }
+               }
+               return $availableExtensions;
+       }
+
+       /**
+        * Adds the information from the emconf array to the extension information
+        *
+        * @param array $extensions
+        * @return array
+        */
+       public function enrichExtensionsWithEmConfAndTerInformation(array $extensions) {
+               foreach ($extensions as $extensionKey => $properties) {
+                       $emconf = $this->emConfUtility->includeEmConf($properties);
+                       if ($emconf) {
+                               $extensions[$extensionKey] = array_merge($emconf, $properties);
+                               $terObject = $this->extensionRepository->findOneByExtensionKeyAndVersion(
+                                       $extensionKey,
+                                       $extensions[$extensionKey]['version']
+                               );
+                               if ($terObject instanceof Tx_Extensionmanager_Domain_Model_Extension) {
+                                       $extensions[$extensionKey]['terObject'] = $terObject;
+                                       $extensions[$extensionKey]['updateAvailable'] = $this->installUtility->isUpdateAvailable($terObject);
+                               }
+
+                       } else {
+                               unset($extensions[$extensionKey]);
+                       }
+               }
+               return $extensions;
+       }
+
+       /**
+        * Gets all available and installed extension with additional information
+        * from em_conf and TER (if available)
+        *
+        * @return array
+        */
+       public function getAvailableAndInstalledExtensionsWithAdditionalInformation() {
+               $availableExtensions = $this->getAvailableExtensions();
+               $availableAndInstalledExtensions = $this->getAvailableAndInstalledExtensions($availableExtensions);
+               return $this->enrichExtensionsWithEmConfAndTerInformation($availableAndInstalledExtensions);
+       }
+}
+
+?>
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlAbstractParser.php b/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlAbstractParser.php
new file mode 100644 (file)
index 0000000..dd96899
--- /dev/null
@@ -0,0 +1,432 @@
+<?php
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ *      Steffen Kamper <info@sk-typo3.de>
+ * All rights reserved
+ *
+ * This script is part of the TYPO3 project. The TYPO3 project is
+ * free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The GNU General Public License can be found at
+ * http://www.gnu.org/copyleft/gpl.html.
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ *
+ * Module: Extension manager - Extension.xml abstract parser
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ */
+
+/**
+ * Abstract parser for TYPO3's extension.xml file.
+ *
+ * @author Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since 2010-02-09
+ * @package TYPO3
+ * @subpackage EM
+ */
+abstract class Tx_Extensionmanager_Utility_Parser_ExtensionXmlAbstractParser
+       extends Tx_Extensionmanager_Utility_Parser_XmlAbstractParser {
+
+       /**
+        * Keeps current author company of an extension's version.
+        *
+        * @var string
+        */
+       protected $authorcompany = NULL;
+
+       /**
+        * Keeps current author mail address of an extension's version.
+        *
+        * @var string
+        */
+       protected $authoremail = NULL;
+
+       /**
+        * Keeps current author name of an extension's version.
+        *
+        * @var string
+        */
+       protected $authorname = NULL;
+
+       /**
+        * Keeps current category of an extension's version.
+        *
+        * @var string
+        */
+       protected $category = NULL;
+
+       /**
+        * Keeps current dependencies of an extension's version.
+        *
+        * @var string
+        */
+       protected $dependencies = NULL;
+
+       /**
+        * Keeps current description of an extension's version.
+        *
+        * @var string
+        */
+       protected $description = NULL;
+
+       /**
+        * Keeps current download number sum of all extension's versions.
+        *
+        * @var string
+        */
+       protected $extensionDownloadCounter = NULL;
+
+       /**
+        * Keeps current key of an extension.
+        *
+        * @var string
+        */
+       protected $extensionKey = NULL;
+
+       /**
+        * Keeps current upload date of an extension's version.
+        *
+        * @var string
+        */
+       protected $lastuploaddate = NULL;
+
+       /**
+        * Keeps current owner username of an extension's version.
+        *
+        * @var string
+        */
+       protected $ownerusername = NULL;
+
+       /**
+        * Keeps current reviewstate of an extension's version.
+        *
+        * @var string
+        */
+       protected $reviewstate = NULL;
+
+       /**
+        * Keeps current state of an extension's version.
+        *
+        * @var string
+        */
+       protected $state = NULL;
+
+       /**
+        * Keeps current t3x file hash of an extension's version.
+        *
+        * @var string
+        */
+       protected $t3xfilemd5 = NULL;
+
+       /**
+        * Keeps current title of an extension's version.
+        *
+        * @var string
+        */
+       protected $title = NULL;
+
+       /**
+        * Keeps current upload comment of an extension's version.
+        *
+        * @var string
+        */
+       protected $uploadcomment = NULL;
+
+       /**
+        * Keeps current version number.
+        *
+        * @var string
+        */
+       protected $version = NULL;
+
+       /**
+        * Keeps current download number of an extension's version.
+        *
+        * @var string
+        */
+       protected $versionDownloadCounter = NULL;
+
+
+       /**
+        * Returns an assoziative array of all extension version properties.
+        *
+        * Valid array keys of returned array are:
+        * extkey, version, alldownloadcounter, downloadcounter, title, description,
+        * state, reviewstate, category, lastuploaddate, uploadcomment, dependencies,
+        * authorname, authoremail, authorcompany, ownerusername, t3xfilemd5
+        *
+        * @access public
+        * @see $extensionKey, $version, $extensionDownloadCounter,
+        *   $versionDownloadCounter, $title, $description, $state,
+        *   $reviewstate, $category, $lastuploaddate, $uploadcomment,
+        *   $dependencies, $authorname, $authoremail, $authorcompany,
+        *   $ownerusername, $t3xfilemd5
+        * @return array assoziative array of an extension version's properties
+        */
+       public function getAll() {
+               $versionProperties = array();
+               $versionProperties['extkey'] = $this->extensionKey;
+               $versionProperties['version'] = $this->version;
+               $versionProperties['alldownloadcounter'] = $this->extensionDownloadCounter;
+               $versionProperties['downloadcounter'] = $this->versionDownloadCounter;
+               $versionProperties['title'] = $this->title;
+               $versionProperties['description'] = $this->description;
+               $versionProperties['state'] = $this->state;
+               $versionProperties['reviewstate'] = $this->reviewstate;
+               $versionProperties['category'] = $this->category;
+               $versionProperties['lastuploaddate'] = $this->lastuploaddate;
+               $versionProperties['uploadcomment'] = $this->uploadcomment;
+               $versionProperties['dependencies'] = $this->dependencies;
+               $versionProperties['authorname'] = $this->authorname;
+               $versionProperties['authoremail'] = $this->authoremail;
+               $versionProperties['authorcompany'] = $this->authorcompany;
+               $versionProperties['ownerusername'] = $this->ownerusername;
+               $versionProperties['t3xfilemd5'] = $this->t3xfilemd5;
+               return $versionProperties;
+       }
+
+       /**
+        * Returns download number sum of all extension's versions.
+        *
+        * @access public
+        * @return string download number sum
+        * @see $extensionDLCounter, getAll()
+        */
+       public function getAlldownloadcounter() {
+               return $this->extensionDownloadCounter;
+       }
+
+       /**
+        * Returns company name of extension author.
+        *
+        * @access public
+        * @return string company name of extension author
+        * @see $authorcompany, getAll()
+        */
+       public function getAuthorcompany() {
+               return $this->authorcompany;
+       }
+
+       /**
+        * Returns e-mail address of extension author.
+        *
+        * @access public
+        * @return string e-mail address of extension author
+        * @see  $authoremail, getAll()
+        */
+       public function getAuthoremail() {
+               return $this->authoremail;
+       }
+
+       /**
+        * Returns name of extension author.
+        *
+        * @access public
+        * @return string name of extension author
+        * @see $authorname, getAll()
+        */
+       public function getAuthorname() {
+               return $this->authorname;
+       }
+
+       /**
+        * Returns category of an extension.
+        *
+        * @access public
+        * @return string extension category
+        * @see $category, getAll()
+        */
+       public function getCategory() {
+               return $this->category;
+       }
+
+       /**
+        * Returns dependencies of an extension's version.
+        *
+        * @access public
+        * @return string extension dependencies
+        * @see $dependencies, getAll()
+        */
+       public function getDependencies() {
+               return $this->dependencies;
+       }
+
+       /**
+        * Returns description of an extension's version.
+        *
+        * @access public
+        * @return string extension description
+        * @see $description, getAll()
+        */
+       public function getDescription() {
+               return $this->description;
+       }
+
+       /**
+        * Returns download number of an extension's version.
+        *
+        * @access public
+        * @return string download number
+        * @see $versionDLCounter, getAll()
+        */
+       public function getDownloadcounter() {
+               return $this->versionDownloadCounter;
+       }
+
+       /**
+        * Returns key of an extension.
+        *
+        * @access public
+        * @return string extension key
+        * @see $extensionKey, getAll()
+        */
+       public function getExtkey() {
+               return $this->extensionKey;
+       }
+
+       /**
+        * Returns last uploaddate of an extension's version.
+        *
+        * @access public
+        * @return string last upload date of an extension's version
+        * @see $lastuploaddate, getAll()
+        */
+       public function getLastuploaddate() {
+               return $this->lastuploaddate;
+       }
+
+       /**
+        * Returns username of extension owner.
+        *
+        * @access public
+        * @return string extension owner's username
+        * @see $ownerusername, getAll()
+        */
+       public function getOwnerusername() {
+               return $this->ownerusername;
+       }
+
+       /**
+        * Returns review state of an extension's version.
+        *
+        * @access public
+        * @return string extension review state
+        * @see $reviewstate, getAll()
+        */
+       public function getReviewstate() {
+               return $this->reviewstate;
+       }
+
+       /**
+        * Returns state of an extension's version.
+        *
+        * @access public
+        * @return string extension state
+        * @see $state, getAll()
+        */
+       public function getState() {
+               return $this->state;
+       }
+
+       /**
+        * Returns t3x file hash of an extension's version.
+        *
+        * @access public
+        * @return string t3x file hash  *
+        * @see $t3xfilemd5, getAll()
+        */
+       public function getT3xfilemd5() {
+               return $this->t3xfilemd5;
+       }
+
+       /**
+        * Returns title of an extension's version.
+        *
+        * @access public
+        * @return string extension title
+        * @see $title, getAll()
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Returns extension upload comment.
+        *
+        * @access public
+        * @return string extension upload comment
+        * @see $uploadcomment, getAll()
+        */
+       public function getUploadcomment() {
+               return $this->uploadcomment;
+       }
+
+       /**
+        * Returns version number.
+        *
+        * @access public
+        * @return string version number
+        * @see $version, getAll()
+        */
+       public function getVersion() {
+               return $this->version;
+       }
+
+       /**
+        * Method resets version class properties.
+        *
+        * @param $resetAll $all if TRUE, additionally extension properties are reset
+        * @return void
+        * @see $extensionKey, $version, $extensionDLCounter, $versionDLCounter,
+        *       $title, $description, $state, $reviewstate, $category,
+        *       $lastuploaddate, $uploadcomment, $dependencies, $authorname,
+        *       $authoremail, $authorcompany, $ownerusername, $t3xfilemd5
+        */
+       protected function resetProperties($resetAll = FALSE) {
+                       // resetting at least class property "version" is mandatory
+                       // as we need to do some magic in regards to
+                       // an extension's and version's child node "downloadcounter"
+               $this->version = $this->title = $this->versionDownloadCounter =
+                               $this->description = $this->state = $this->reviewstate =
+                                               $this->category = $this->lastuploaddate = $this->uploadcomment =
+                                                               $this->dependencies = $this->authorname = $this->authoremail =
+                                                                               $this->authorcompany = $this->ownerusername = $this->t3xfilemd5 = NULL;
+               if ($resetAll) {
+                       $this->extensionKey = $this->extensionDownloadCounter = NULL;
+               }
+       }
+
+       /**
+        * Convert dependencies from TER format to EM_CONF format
+        *
+        * @param string $dependencies serialized dependency array
+        * @return string
+        */
+       protected function convertDependencies($dependencies) {
+               $newDependencies = array();
+               $dependenciesArray = unserialize($dependencies);
+               if (is_array($dependenciesArray)) {
+                       foreach ($dependenciesArray as $version) {
+                               $newDependencies[$version['kind']][$version['extensionKey']] = $version['versionRange'];
+                       }
+               }
+               return serialize($newDependencies);
+       }
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPullParser.php b/typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPullParser.php
new file mode 100644 (file)
index 0000000..f99001e
--- /dev/null
@@ -0,0 +1,240 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
+ *                Steffen Kamper <info@sk-typo3.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+/**
+ * Module: Extension manager - Extension.xml pull-parser
+ */
+
+/**
+ * Parser for TYPO3's extension.xml file.
+ *
+ * Depends on PHP ext/xmlreader which should be available
+ * with PHP >= 5.1.0.
+ *
+ * @author       Marcus Krause <marcus#exp2010@t3sec.info>
+ * @author       Steffen Kamper <info@sk-typo3.de>
+ *
+ * @since         2010-02-09
+ * @package     TYPO3
+ * @subpackage  EM
+ */
+class Tx_Extensionmanager_Utility_Parser_ExtensionXmlPullParser extends Tx_Extensionmanager_Utility_Parser_ExtensionXmlAbstractParser implements SplSubject {
+
+
+       /**
+        * Keeps list of attached observers.
+        *
+        * @var  SplObserver[]
+        */
+       protected $observers = array();
+
+       /**
+        * Class constructor.
+        */
+       public function __construct() {
+               $this->requiredPhpExtensions = 'xmlreader';
+
+               if ($this->isAvailable()) {
+                       $this->objXml = new XMLReader();
+               }
+       }
+
+       /**
+        * Method parses an extensions.xml file.
+        *
+        * @param string $file GZIP stream resource
+        * @return void
+        * @throws Tx_Extensionmanager_Exception_ExtensionManager in case of parser error
+        */
+       public function parseXml($file) {
+               if (!(is_object($this->objXml) && (get_class($this->objXml) == 'XMLReader'))) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager('Unable to create XML parser.', 1342640540);
+               }
+               if ($this->objXml->open($file, 'utf-8') === FALSE) {
+                       throw new Tx_Extensionmanager_Exception_ExtensionManager(sprintf('Unable to open file resource %s.', htmlspecialchars($file)));
+               }
+
+               while ($this->objXml->read()) {
+                       if ($this->objXml->nodeType == XMLReader::ELEMENT) {
+                               $this->startElement($this->objXml->name);
+                       } else {
+                               if ($this->objXml->nodeType == XMLReader::END_ELEMENT) {
+                                       $this->endElement($this->objXml->name);
+                               } else {
+                                       continue;
+                               }
+                       }
+               }
+               $this->objXml->close();
+       }
+
+       /**
+        * Method is invoked when parser accesses start tag of an element.
+        *
+        * @param string $elementName element name at parser's current position
+        * @return void
+        */
+       protected function startElement($elementName) {
+               switch ($elementName) {
+                       case 'extension':
+                               $this->extensionKey = $this->objXml->getAttribute('extensionkey');
+                               break;
+                       case 'version':
+                               $this->version = $this->objXml->getAttribute('version');
+                               break;
+                       case 'downloadcounter':
+                                       // downloadcounter could be a child node of
+                                       // extension or version
+                               if ($this->version == NULL) {
+                                       $this->extensionDownloadCounter = $this->getElementValue($elementName);
+                               } else {
+                                       $this->versionDownloadCounter = $this->getElementValue($elementName);
+                               }
+                               break;
+                       case 'title':
+                               $this->title = $this->getElementValue($elementName);
+                               break;
+                       case 'description':
+                               $this->description = $this->getElementValue($elementName);
+                               break;
+                       case 'state':
+                               $this->state = $this->getElementValue($elementName);
+                               break;
+                       case 'reviewstate':
+                               $this->reviewstate = $this->getElementValue($elementName);
+                               break;
+                       case 'category':
+                               $this->category = $this->getElementValue($elementName);
+                               break;
+                       case 'lastuploaddate':
+                               $this->lastuploaddate = $this->getElementValue($elementName);
+                               break;
+                       case 'uploadcomment':
+                               $this->uploadcomment = $this->getElementValue($elementName);
+                               break;
+                       case 'dependencies':
+                               $this->dependencies = $this->convertDependencies($this->getElementValue($elementName));
+                               break;
+                       case 'authorname':
+                               $this->authorname = $this->getElementValue($elementName);
+                               break;
+                       case 'authoremail':
+                               $this->authoremail = $this->getElementValue($elementName);
+                               break;
+                       case 'authorcompany':
+                               $this->authorcompany = $this->getElementValue($elementName);
+                               break;
+                       case 'ownerusername':
+                               $this->ownerusername = $this->getElementValue($elementName);
+                               break;
+                       case 't3xfilemd5':
+                               $this->t3xfilemd5 = $this->getElementValue($elementName);
+                               break;
+               }
+       }
+
+       /**
+        * Method is invoked when parser accesses end tag of an element.
+        *
+        * @param string $elementName: element name at parser's current position
+        * @return void
+        */
+       protected function endElement($elementName) {
+               switch ($elementName) {
+                       case 'extension':
+                               $this->resetProperties(TRUE);
+                               break;
+                       case 'version':
+                               $this->notify();
+                               $this->resetProperties();
+                               break;
+               }
+       }
+
+       /**
+        * Method returns the value of an element at XMLReader's current
+        * position.
+        *
+        * Method will read until it finds the end of the given element.
+        * If element has no value, method returns NULL.
+        *
+        * @param   string  $elementName: name of element to retrieve it's value from
+        * @return  string  an element's value if it has a value, otherwise NULL
+        */
+       protected function getElementValue(&$elementName) {
+               $value = NULL;
+               if (!$this->objXml->isEmptyElement) {
+                       $value = '';
+                       while ($this->objXml->read()) {
+                               if ($this->objXml->nodeType == XMLReader::TEXT
+                                               || $this->objXml->nodeType == XMLReader::CDATA
+                                               || $this->objXml->nodeType == XMLReader::WHITESPACE
+                                               || $this->objXml->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) {
+                                       $value .= $this->objXml->value;
+                               } else {
+                                       if ($this->objXml->nodeType == XMLReader::END_ELEMENT
+                                                       && $this->objXml->name === $elementName) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               return $value;
+       }
+
+       /**
+        * Method attaches an observer.
+        *
+        * @param   SplObserver  $observer: an observer to attach
+        * @return  void
+        */
+       public function attach(SplObserver $observer) {
+               $this->observers[] = $observer;
+       }
+
+       /**
+        * Method detaches an attached observer
+        *
+        * @param   SplObserver  $observer: an observer to detach
+        * @return  void
+        */
+       public function detach(SplObserver $observer) {
+               $key = array_search($observer, $this->observers, TRUE);
+               if (!($key === FALSE)) {
+                       unset($this->observers[$key]);
+               }
+     &nbs