[FEATURE] Enable automatic t3d import for extensions
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / InstallUtility.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012-2013 Susanne Moog <susanne.moog@typo3.org>
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 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Extension Manager Install Utility
31 *
32 * @author Susanne Moog <susanne.moog@typo3.org>
33 */
34 class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface {
35
36 /**
37 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
38 * @inject
39 */
40 public $objectManager;
41
42 /**
43 * @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService
44 * @inject
45 */
46 public $installToolSqlParser;
47
48 /**
49 * @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
50 * @inject
51 */
52 protected $dependencyUtility;
53
54 /**
55 * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
56 * @inject
57 */
58 protected $fileHandlingUtility;
59
60 /**
61 * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
62 * @inject
63 */
64 protected $listUtility;
65
66 /**
67 * @var \TYPO3\CMS\Extensionmanager\Utility\DatabaseUtility
68 * @inject
69 */
70 protected $databaseUtility;
71
72 /**
73 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
74 * @inject
75 */
76 public $extensionRepository;
77
78 /**
79 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
80 * @inject
81 */
82 protected $signalSlotDispatcher;
83
84 /**
85 * @var \TYPO3\CMS\Core\Registry
86 * @inject
87 */
88 protected $registry;
89
90 /**
91 * __construct
92 */
93 public function __construct() {
94 $this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
95 /** @var $installToolSqlParser \TYPO3\CMS\Install\Service\SqlSchemaMigrationService */
96 $this->installToolSqlParser = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService');
97 $this->dependencyUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\DependencyUtility');
98 }
99
100 /**
101 * Helper function to install an extension
102 * also processes db updates and clears the cache if the extension asks for it
103 *
104 * @param string $extensionKey
105 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
106 * @return void
107 */
108 public function install($extensionKey) {
109 $extension = $this->enrichExtensionWithDetails($extensionKey);
110 $this->processDatabaseUpdates($extension);
111 $this->ensureConfiguredDirectoriesExist($extension);
112 if ($extension['clearcacheonload']) {
113 $GLOBALS['typo3CacheManager']->flushCaches();
114 }
115 if (!$this->isLoaded($extensionKey)) {
116 $this->loadExtension($extensionKey);
117 }
118 $this->reloadCaches();
119 $this->processCachingFrameworkUpdates();
120 $this->saveDefaultConfiguration($extension['key']);
121 }
122
123 /**
124 * Helper function to uninstall an extension
125 *
126 * @param string $extensionKey
127 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
128 * @return void
129 */
130 public function uninstall($extensionKey) {
131 $dependentExtensions = $this->dependencyUtility->findInstalledExtensionsThatDependOnMe($extensionKey);
132 if (is_array($dependentExtensions) && count($dependentExtensions) > 0) {
133 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(
134 \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate(
135 'extensionList.uninstall.dependencyError',
136 'extensionmanager',
137 array($extensionKey, implode(',', $dependentExtensions))
138 ),
139 1342554622
140 );
141 } else {
142 $this->unloadExtension($extensionKey);
143 }
144 }
145
146 /**
147 * Wrapper function to check for loaded extensions
148 *
149 * @param string $extensionKey
150 * @return boolean TRUE if extension is loaded
151 */
152 public function isLoaded($extensionKey) {
153 return \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extensionKey);
154 }
155
156 /**
157 * Wrapper function for loading extensions
158 *
159 * @param string $extensionKey
160 * @return void
161 */
162 protected function loadExtension($extensionKey) {
163 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::loadExtension($extensionKey);
164 }
165
166 /**
167 * Wrapper function for unloading extensions
168 *
169 * @param string $extensionKey
170 * @return void
171 */
172 protected function unloadExtension($extensionKey) {
173 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::unloadExtension($extensionKey);
174 }
175
176 /**
177 * Checks if an extension is available in the system
178 *
179 * @param $extensionKey
180 * @return boolean
181 */
182 public function isAvailable($extensionKey) {
183 $availableExtensions = $this->listUtility->getAvailableExtensions();
184 return array_key_exists($extensionKey, $availableExtensions);
185 }
186
187 /**
188 * Fetch additional information for an extension key
189 *
190 * @param string $extensionKey
191 * @access private
192 * @return array
193 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
194 */
195 public function enrichExtensionWithDetails($extensionKey) {
196 $availableExtensions = $this->listUtility->getAvailableExtensions();
197 if (isset($availableExtensions[$extensionKey])) {
198 $extension = $availableExtensions[$extensionKey];
199 } else {
200 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
201 }
202 $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(array($extensionKey => $extension));
203 return $availableAndInstalledExtensions[$extensionKey];
204 }
205
206 /**
207 * Creates directories as requested in ext_emconf.php
208 *
209 * @param array $extension
210 */
211 protected function ensureConfiguredDirectoriesExist(array $extension) {
212 $this->fileHandlingUtility->ensureConfiguredDirectoriesExist($extension);
213 }
214
215 /**
216 * Gets the content of the ext_tables.sql and ext_tables_static+adt.sql files
217 * Additionally adds the table definitions for the cache tables
218 *
219 * @param array $extension
220 */
221 public function processDatabaseUpdates(array $extension) {
222 $extTablesSqlFile = PATH_site . $extension['siteRelPath'] . '/ext_tables.sql';
223 $extTablesSqlContent = '';
224 if (file_exists($extTablesSqlFile)) {
225 $extTablesSqlContent .= \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($extTablesSqlFile);
226 }
227 if ($extTablesSqlContent !== '') {
228 $this->updateDbWithExtTablesSql($extTablesSqlContent);
229 }
230
231 $this->importStaticSqlFile($extension['siteRelPath']);
232 $this->importT3DFile($extension['siteRelPath']);
233 }
234
235 /**
236 * Gets all registered caches and creates required caching framework tables.
237 *
238 * @return void
239 */
240 protected function processCachingFrameworkUpdates() {
241 $extTablesSqlContent = '';
242
243 // @TODO: This should probably moved to TYPO3\CMS\Core\Cache\Cache->getDatabaseTableDefinitions ?!
244 $GLOBALS['typo3CacheManager']->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
245 $extTablesSqlContent .= \TYPO3\CMS\Core\Cache\Cache::getDatabaseTableDefinitions();
246
247 if ($extTablesSqlContent !== '') {
248 $this->updateDbWithExtTablesSql($extTablesSqlContent);
249 }
250 }
251
252 /**
253 * Reload Cache files and Typo3LoadedExtensions
254 *
255 * @return void
256 */
257 public function reloadCaches() {
258 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::removeCacheFiles();
259 // Set new extlist / extlistArray for extension load changes at runtime
260 /** @var $configurationManager \TYPO3\CMS\Core\Configuration\ConfigurationManager */
261 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
262 $localConfiguration = $configurationManager->getLocalConfiguration();
263 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray'] = $localConfiguration['EXT']['extListArray'];
264 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'] = implode(',', $GLOBALS['TYPO3_CONF_VARS']['EXT']['extListArray']);
265 \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->reloadTypo3LoadedExtAndClassLoaderAndExtLocalconf();
266 }
267
268 /**
269 * Save default configuration of an extension
270 *
271 * @param string $extensionKey
272 * @return void
273 */
274 protected function saveDefaultConfiguration($extensionKey) {
275 /** @var $configUtility \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility */
276 $configUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\ConfigurationUtility');
277 $configUtility->saveDefaultConfiguration($extensionKey);
278 }
279
280 /**
281 * Update database / process db updates from ext_tables
282 *
283 * @param string $rawDefinitions The raw SQL statements from ext_tables.sql
284 * @return void
285 */
286 public function updateDbWithExtTablesSql($rawDefinitions) {
287 $fieldDefinitionsFromFile = $this->installToolSqlParser->getFieldDefinitions_fileContent($rawDefinitions);
288 if (count($fieldDefinitionsFromFile)) {
289 $fieldDefinitionsFromCurrentDatabase = $this->installToolSqlParser->getFieldDefinitions_database();
290 $diff = $this->installToolSqlParser->getDatabaseExtra($fieldDefinitionsFromFile, $fieldDefinitionsFromCurrentDatabase);
291 $updateStatements = $this->installToolSqlParser->getUpdateSuggestions($diff);
292 foreach ((array) $updateStatements['add'] as $string) {
293 $GLOBALS['TYPO3_DB']->admin_query($string);
294 }
295 foreach ((array) $updateStatements['change'] as $string) {
296 $GLOBALS['TYPO3_DB']->admin_query($string);
297 }
298 foreach ((array) $updateStatements['create_table'] as $string) {
299 $GLOBALS['TYPO3_DB']->admin_query($string);
300 }
301 }
302 }
303
304 /**
305 * Import static SQL data (normally used for ext_tables_static+adt.sql)
306 *
307 * @param string $rawDefinitions
308 * @return void
309 */
310 public function importStaticSql($rawDefinitions) {
311 $statements = $this->installToolSqlParser->getStatementarray($rawDefinitions, 1);
312 list($statementsPerTable, $insertCount) = $this->installToolSqlParser->getCreateTables($statements, 1);
313 // Traverse the tables
314 foreach ($statementsPerTable as $table => $query) {
315 $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table);
316 $GLOBALS['TYPO3_DB']->admin_query($query);
317 if ($insertCount[$table]) {
318 $insertStatements = $this->installToolSqlParser->getTableInsertStatements($statements, $table);
319 foreach ($insertStatements as $statement) {
320 $GLOBALS['TYPO3_DB']->admin_query($statement);
321 }
322 }
323 }
324 }
325
326 /**
327 * Remove an extension (delete the directory)
328 *
329 * @param string $extension
330 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
331 * @return void
332 */
333 public function removeExtension($extension) {
334 $absolutePath = $this->fileHandlingUtility->getAbsoluteExtensionPath($extension);
335 if ($this->fileHandlingUtility->isValidExtensionPath($absolutePath)) {
336 $this->fileHandlingUtility->removeDirectory($absolutePath);
337 } else {
338 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('No valid extension path given.', 1342875724);
339 }
340 }
341
342 /**
343 * Get the data dump for an extension
344 *
345 * @param string $extension
346 * @return array
347 */
348 public function getExtensionSqlDataDump($extension) {
349 $extension = $this->enrichExtensionWithDetails($extension);
350 $filePrefix = PATH_site . $extension['siteRelPath'];
351 $sqlData['extTables'] = $this->getSqlDataDumpForFile($filePrefix . '/ext_tables.sql');
352 $sqlData['staticSql'] = $this->getSqlDataDumpForFile($filePrefix . '/ext_tables_static+adt.sql');
353 return $sqlData;
354 }
355
356 /**
357 * Gets the sql data dump for a specific sql file (for example ext_tables.sql)
358 *
359 * @param string $sqlFile
360 * @return string
361 */
362 protected function getSqlDataDumpForFile($sqlFile) {
363 $sqlData = '';
364 if (file_exists($sqlFile)) {
365 $sqlContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($sqlFile);
366 $fieldDefinitions = $this->installToolSqlParser->getFieldDefinitions_fileContent($sqlContent);
367 $sqlData = $this->databaseUtility->dumpStaticTables($fieldDefinitions);
368 }
369 return $sqlData;
370 }
371
372 /**
373 * Checks if an update for an extension is available
374 *
375 * @internal
376 * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData
377 * @return boolean
378 */
379 public function isUpdateAvailable(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData) {
380 // Only check for update for TER extensions
381 $version = $extensionData->getIntegerVersion();
382 /** @var $highestTerVersionExtension \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */
383 $highestTerVersionExtension = $this->extensionRepository->findHighestAvailableVersion($extensionData->getExtensionKey());
384 if ($highestTerVersionExtension instanceof \TYPO3\CMS\Extensionmanager\Domain\Model\Extension) {
385 $highestVersion = $highestTerVersionExtension->getIntegerVersion();
386 if ($highestVersion > $version) {
387 return TRUE;
388 }
389 }
390 return FALSE;
391 }
392
393 /**
394 * Uses the export import extension to import a T3DFile to PID 0
395 * Execution state is saved in the this->registry, so it only happens once
396 *
397 * @param string $extensionSiteRelPath
398 * @return void
399 */
400 protected function importT3DFile($extensionSiteRelPath) {
401 $t3dImportRelFile = $extensionSiteRelPath . '/Initialisation/data.t3d';
402 if (!$this->registry->get('extensionDataImport', $t3dImportRelFile)) {
403 $t3dImportFile = PATH_site . $t3dImportRelFile;
404 if (file_exists($t3dImportFile)) {
405 $importExportUtility = $this->objectManager->get('TYPO3\\CMS\\Impexp\\Utility\\ImportExportUtility');
406 try {
407 $importResult = $importExportUtility->importT3DFile($t3dImportFile, 0);
408 $this->registry->set('extensionDataImport', $t3dImportRelFile, 1);
409 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionT3DImport', array($t3dImportRelFile, $importResult, $this));
410 } catch (\ErrorException $e) {
411 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
412 $logger = $this->objectManager->get('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
413 $logger->log(\TYPO3\CMS\Core\Log\LogLevel::WARNING, $e->getMessage());
414 }
415 }
416 }
417 }
418
419 /**
420 * Imports a static tables SQL File (ext_tables_static+adt)
421 * Execution state is saved in the this->registry, so it only happens once
422 *
423 * @param string $extensionSiteRelPath
424 * @return void
425 */
426 protected function importStaticSqlFile($extensionSiteRelPath) {
427 $extTablesStaticSqlRelFile = $extensionSiteRelPath . '/ext_tables_static+adt.sql';
428 if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) {
429 $extTablesStaticSqlFile = PATH_site . $extTablesStaticSqlRelFile;
430 if (file_exists($extTablesStaticSqlFile)) {
431 $extTablesStaticSqlContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($extTablesStaticSqlFile);
432 $this->importStaticSql($extTablesStaticSqlContent);
433 }
434 $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, 1);
435 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionStaticSqlImport', array($extTablesStaticSqlRelFile, $this));
436 }
437 }
438 }
439
440
441 ?>