[FEATURE] Integrate preliminary PackageManager API
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Ajax / ExtensionCompatibilityTester.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Ajax;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Susanne Moog <typo3@susanne-moog.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Install\Controller\Action;
28 use TYPO3\CMS\Core\Utility;
29
30 /**
31 * Load Extensions
32 *
33 * The idea is to load ext_localconf and ext_tables of extensions one-by-one
34 * until one of those files throws a fatal. The javascript will then recognise
35 * the fatal and initiates another run that will leave out the fataling extension
36 * to check the rest.
37 */
38 class ExtensionCompatibilityTester extends Action\AbstractAction implements Action\ActionInterface {
39
40 /**
41 * Store extension loading protocol
42 *
43 * @var string
44 */
45 protected $protocolFile = '';
46
47 /**
48 * Construct this class
49 * set default protocol file location
50 */
51 public function __construct() {
52 $this->protocolFile = PATH_site . 'typo3temp/ExtensionCompatibilityTester.txt';
53 }
54
55 /**
56 * Handle this action
57 *
58 * @return string content
59 */
60 public function handle() {
61 $this->initializeHandle();
62 return $this->checkLoadedExtensions();
63 }
64
65 /**
66 * Main entry point for checking extensions to load,
67 * setting up the checks (deleting protocol), and returning
68 * OK if process run through without errors
69 *
70 * @return string
71 */
72 protected function checkLoadedExtensions() {
73 $getVars = Utility\GeneralUtility::_GET('install');
74 if (isset($getVars['extensionCompatibilityTester']) && isset($getVars['extensionCompatibilityTester']['forceCheck']) && ($getVars['extensionCompatibilityTester']['forceCheck'] == 1)) {
75 $this->deleteProtocolFile();
76 }
77 $this->tryToLoadExtLocalconfAndExtTablesOfExtensions($this->getExtensionsToLoad());
78 return 'OK';
79 }
80
81 /**
82 * Delete the protocol file if it exists
83 *
84 * @return void
85 */
86 protected function deleteProtocolFile() {
87 if (file_exists($this->protocolFile)) {
88 unlink($this->protocolFile);
89 }
90 }
91
92 /**
93 * Get extensions that should be loaded.
94 * Fills the TYPO3_LOADED_EXT array.
95 * Only considers local extensions
96 *
97 * @return array
98 */
99 protected function getExtensionsToLoad() {
100 $extensionsToLoad = array();
101 //TODO: FIXME
102 $GLOBALS['TYPO3_LOADED_EXT'] = Utility\ExtensionManagementUtility::loadTypo3LoadedExtensionInformation(FALSE);
103 $extensionsToExclude = $this->getExtensionsToExclude();
104 foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $key => $extension) {
105 if (!in_array($key, $extensionsToExclude)) {
106 $extensionsToLoad[$key] = $extension;
107 }
108 }
109 return $extensionsToLoad;
110 }
111
112 /**
113 * Gets extensions already known to be incompatible
114 * This class is recursively called, and this method is needed
115 * to not run into the same errors twice.
116 *
117 * @return array
118 */
119 protected function getExtensionsToExclude() {
120 $exclude = Utility\GeneralUtility::getUrl($this->protocolFile);
121 return Utility\GeneralUtility::trimExplode(',', (string)$exclude);
122 }
123
124 /**
125 * Tries to load the ext_localconf and ext_tables files of all non-core extensions
126 * Writes current extension name to file and deletes it again when inclusion was
127 * successfull.
128 *
129 * @param array $extensions
130 * @return void
131 */
132 protected function tryToLoadExtLocalconfAndExtTablesOfExtensions(array $extensions) {
133 foreach ($extensions as $extensionKey => $extension) {
134 $this->writeCurrentExtensionToFile($extensionKey);
135 $this->loadExtLocalconfForExtension($extensionKey, $extension);
136 $this->removeCurrentExtensionFromFile($extensionKey);
137 }
138 Utility\ExtensionManagementUtility::loadBaseTca(FALSE);
139 foreach ($extensions as $extensionKey => $extension) {
140 $this->writeCurrentExtensionToFile($extensionKey);
141 $this->loadExtTablesForExtension($extensionKey, $extension);
142 $this->removeCurrentExtensionFromFile($extensionKey);
143 }
144 }
145
146 /**
147 * Loads ext_tables.php for a single extension. Method is a modified copy of
148 * the original bootstrap method.
149 *
150 * @param string $extensionKey
151 * @param array $extension
152 * @return void
153 */
154 protected function loadExtTablesForExtension($extensionKey, array $extension) {
155 // In general it is recommended to not rely on it to be globally defined in that
156 // scope, but we can not prohibit this without breaking backwards compatibility
157 global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
158 global $TBE_MODULES, $TBE_MODULES_EXT, $TCA;
159 global $PAGES_TYPES, $TBE_STYLES, $FILEICONS;
160 global $_EXTKEY;
161 // Load each ext_tables.php file of loaded extensions
162 $_EXTKEY = $extensionKey;
163 if (is_array($extension) && $extension['ext_tables.php']) {
164 // $_EXTKEY and $_EXTCONF are available in ext_tables.php
165 // and are explicitly set in cached file as well
166 $_EXTCONF = $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$_EXTKEY];
167 require $extension['ext_tables.php'];
168 Utility\ExtensionManagementUtility::loadNewTcaColumnsConfigFiles();
169 }
170 }
171
172 /**
173 * Loads ext_localconf.php for a single extension. Method is a modified copy of
174 * the original bootstrap method.
175 *
176 * @param string $extensionKey
177 * @param array $extension
178 * @return void
179 */
180 protected function loadExtLocalconfForExtension($extensionKey, array $extension) {
181 // This is the main array meant to be manipulated in the ext_localconf.php files
182 // In general it is recommended to not rely on it to be globally defined in that
183 // scope but to use $GLOBALS['TYPO3_CONF_VARS'] instead.
184 // Nevertheless we define it here as global for backwards compatibility.
185 global $TYPO3_CONF_VARS;
186 $_EXTKEY = $extensionKey;
187 if (is_array($extension) && $extension['ext_localconf.php']) {
188 // $_EXTKEY and $_EXTCONF are available in ext_localconf.php
189 // and are explicitly set in cached file as well
190 $_EXTCONF = $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$_EXTKEY];
191 require $extension['ext_localconf.php'];
192 }
193 }
194
195 /**
196 * Writes $extensionKey to the protocol file by adding it comma separated at
197 * the end of the file.
198 *
199 * @param string $extensionKey
200 * @return void
201 */
202 protected function writeCurrentExtensionToFile($extensionKey) {
203 $incompatibleExtensions = array_filter(Utility\GeneralUtility::trimExplode(',', (string)Utility\GeneralUtility::getUrl($this->protocolFile)));
204 $incompatibleExtensions = array_merge($incompatibleExtensions, array($extensionKey));
205 Utility\GeneralUtility::writeFile($this->protocolFile, implode(', ', $incompatibleExtensions));
206 }
207
208 /**
209 * Removes $extensionKey from protocol file.
210 *
211 * @param string $extensionKey
212 * @return void
213 */
214 protected function removeCurrentExtensionFromFile($extensionKey) {
215 $extensionsInFile = array_filter(Utility\GeneralUtility::trimExplode(',', (string)Utility\GeneralUtility::getUrl($this->protocolFile)));
216 $extensionsByKey = array_flip($extensionsInFile);
217 unset($extensionsByKey[$extensionKey]);
218 $extensionsForFile = array_flip($extensionsByKey);
219 Utility\GeneralUtility::writeFile($this->protocolFile, implode(', ', $extensionsForFile));
220 }
221 }