[BUGFIX] Prevent current extension version in update dialog
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / InstallUtility.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Service\OpcodeCacheService;
19 use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
20 use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
21 use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
22
23 /**
24 * Extension Manager Install Utility
25 */
26 class InstallUtility implements \TYPO3\CMS\Core\SingletonInterface {
27
28 /**
29 * @var \TYPO3\CMS\Extbase\Object\ObjectManager
30 */
31 public $objectManager;
32
33 /**
34 * @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService
35 */
36 public $installToolSqlParser;
37
38 /**
39 * @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
40 */
41 protected $dependencyUtility;
42
43 /**
44 * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
45 */
46 protected $fileHandlingUtility;
47
48 /**
49 * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
50 */
51 protected $listUtility;
52
53 /**
54 * @var \TYPO3\CMS\Extensionmanager\Utility\DatabaseUtility
55 */
56 protected $databaseUtility;
57
58 /**
59 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
60 */
61 public $extensionRepository;
62
63 /**
64 * @var \TYPO3\CMS\Core\Package\PackageManager
65 */
66 protected $packageManager;
67
68 /**
69 * @var \TYPO3\CMS\Core\Cache\CacheManager
70 */
71 protected $cacheManager;
72
73 /**
74 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
75 */
76 protected $signalSlotDispatcher;
77
78 /**
79 * @var \TYPO3\CMS\Core\Registry
80 */
81 protected $registry;
82
83 /**
84 * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
85 */
86 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager) {
87 $this->objectManager = $objectManager;
88 }
89
90 /**
91 * @param \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $installToolSqlParser
92 */
93 public function injectInstallToolSqlParser(\TYPO3\CMS\Install\Service\SqlSchemaMigrationService $installToolSqlParser) {
94 $this->installToolSqlParser = $installToolSqlParser;
95 }
96
97 /**
98 * @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility
99 */
100 public function injectDependencyUtility(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility) {
101 $this->dependencyUtility = $dependencyUtility;
102 }
103
104 /**
105 * @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
106 */
107 public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility) {
108 $this->fileHandlingUtility = $fileHandlingUtility;
109 }
110
111 /**
112 * @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
113 */
114 public function injectListUtility(\TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility) {
115 $this->listUtility = $listUtility;
116 }
117
118 /**
119 * @param \TYPO3\CMS\Extensionmanager\Utility\DatabaseUtility $databaseUtility
120 */
121 public function injectDatabaseUtility(\TYPO3\CMS\Extensionmanager\Utility\DatabaseUtility $databaseUtility) {
122 $this->databaseUtility = $databaseUtility;
123 }
124
125 /**
126 * @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
127 */
128 public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository) {
129 $this->extensionRepository = $extensionRepository;
130 }
131
132 /**
133 * @param \TYPO3\CMS\Core\Package\PackageManager $packageManager
134 */
135 public function injectPackageManager(\TYPO3\CMS\Core\Package\PackageManager $packageManager) {
136 $this->packageManager = $packageManager;
137 }
138
139 /**
140 * @param \TYPO3\CMS\Core\Cache\CacheManager $cacheManager
141 */
142 public function injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager) {
143 $this->cacheManager = $cacheManager;
144 }
145
146 /**
147 * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
148 */
149 public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher) {
150 $this->signalSlotDispatcher = $signalSlotDispatcher;
151 }
152
153 /**
154 * @param \TYPO3\CMS\Core\Registry $registry
155 */
156 public function injectRegistry(\TYPO3\CMS\Core\Registry $registry) {
157 $this->registry = $registry;
158 }
159
160 /**
161 * Helper function to install an extension
162 * also processes db updates and clears the cache if the extension asks for it
163 *
164 * @param string $extensionKey
165 * @throws ExtensionManagerException
166 * @return void
167 */
168 public function install($extensionKey) {
169 $extension = $this->enrichExtensionWithDetails($extensionKey);
170 $this->ensureConfiguredDirectoriesExist($extension);
171 $this->loadExtension($extensionKey);
172 if (!empty($extension['clearcacheonload']) || !empty($extension['clearCacheOnLoad'])) {
173 $this->cacheManager->flushCaches();
174 } else {
175 $this->cacheManager->flushCachesInGroup('system');
176 }
177 $this->reloadCaches();
178
179 $this->importInitialFiles($extension['siteRelPath'], $extensionKey);
180 $this->processDatabaseUpdates($extension);
181 $this->processRuntimeDatabaseUpdates($extensionKey);
182 $this->saveDefaultConfiguration($extension['key']);
183
184 $this->emitAfterExtensionInstallSignal($extensionKey);
185 }
186
187 /**
188 * Helper function to uninstall an extension
189 *
190 * @param string $extensionKey
191 * @throws ExtensionManagerException
192 * @return void
193 */
194 public function uninstall($extensionKey) {
195 $dependentExtensions = $this->dependencyUtility->findInstalledExtensionsThatDependOnMe($extensionKey);
196 if (is_array($dependentExtensions) && !empty($dependentExtensions)) {
197 throw new ExtensionManagerException(
198 \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate(
199 'extensionList.uninstall.dependencyError',
200 'extensionmanager',
201 array($extensionKey, implode(',', $dependentExtensions))
202 ),
203 1342554622
204 );
205 } else {
206 $this->unloadExtension($extensionKey);
207 }
208 }
209
210 /**
211 * Wrapper function to check for loaded extensions
212 *
213 * @param string $extensionKey
214 * @return bool TRUE if extension is loaded
215 */
216 public function isLoaded($extensionKey) {
217 return $this->packageManager->isPackageActive($extensionKey);
218 }
219
220 /**
221 * Wrapper function for loading extensions
222 *
223 * @param string $extensionKey
224 * @return void
225 */
226 protected function loadExtension($extensionKey) {
227 $this->packageManager->activatePackage($extensionKey);
228 }
229
230 /**
231 * Wrapper function for unloading extensions
232 *
233 * @param string $extensionKey
234 * @return void
235 */
236 protected function unloadExtension($extensionKey) {
237 $this->packageManager->deactivatePackage($extensionKey);
238 $this->emitAfterExtensionUninstallSignal($extensionKey);
239 $this->cacheManager->flushCachesInGroup('system');
240 }
241
242 /**
243 * Emits a signal after an extension has been installed
244 *
245 * @param string $extensionKey
246 */
247 protected function emitAfterExtensionInstallSignal($extensionKey) {
248 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionInstall', array($extensionKey, $this));
249 }
250
251 /**
252 * Emits a signal after an extension has been uninstalled
253 *
254 * @param string $extensionKey
255 */
256 protected function emitAfterExtensionUninstallSignal($extensionKey) {
257 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionUninstall', array($extensionKey, $this));
258 }
259
260 /**
261 * Checks if an extension is available in the system
262 *
263 * @param string $extensionKey
264 * @return bool
265 */
266 public function isAvailable($extensionKey) {
267 return $this->packageManager->isPackageAvailable($extensionKey);
268 }
269
270 /**
271 * Fetch additional information for an extension key
272 *
273 * @param string $extensionKey
274 * @access private
275 * @return array
276 * @throws ExtensionManagerException
277 */
278 public function enrichExtensionWithDetails($extensionKey) {
279 $availableExtensions = $this->listUtility->getAvailableExtensions();
280 if (isset($availableExtensions[$extensionKey])) {
281 $extension = $availableExtensions[$extensionKey];
282 } else {
283 throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
284 }
285 $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(array($extensionKey => $extension));
286
287 if (!isset($availableAndInstalledExtensions[$extensionKey])) {
288 throw new ExtensionManagerException(
289 'Please check your uploaded extension "' . $extensionKey . '". The configuration file "ext_emconf.php" seems to be invalid.',
290 1391432222
291 );
292 }
293
294 return $availableAndInstalledExtensions[$extensionKey];
295 }
296
297 /**
298 * Creates directories as requested in ext_emconf.php
299 *
300 * @param array $extension
301 */
302 protected function ensureConfiguredDirectoriesExist(array $extension) {
303 $this->fileHandlingUtility->ensureConfiguredDirectoriesExist($extension);
304 }
305
306 /**
307 * Gets the content of the ext_tables.sql and ext_tables_static+adt.sql files
308 * Additionally adds the table definitions for the cache tables
309 *
310 * @param array $extension
311 */
312 public function processDatabaseUpdates(array $extension) {
313 $extTablesSqlFile = PATH_site . $extension['siteRelPath'] . 'ext_tables.sql';
314 $extTablesSqlContent = '';
315 if (file_exists($extTablesSqlFile)) {
316 $extTablesSqlContent .= GeneralUtility::getUrl($extTablesSqlFile);
317 }
318 if ($extTablesSqlContent !== '') {
319 $this->updateDbWithExtTablesSql($extTablesSqlContent);
320 }
321
322 $this->importStaticSqlFile($extension['siteRelPath']);
323 $this->importT3DFile($extension['siteRelPath']);
324 }
325
326 /**
327 * Gets all database updates due to runtime configuration, like caching framework or
328 * category api for example
329 *
330 * @param string $extensionKey
331 */
332 protected function processRuntimeDatabaseUpdates($extensionKey) {
333 $sqlString = $this->emitTablesDefinitionIsBeingBuiltSignal($extensionKey);
334 if (!empty($sqlString)) {
335 $this->updateDbWithExtTablesSql(implode(LF . LF . LF . LF, $sqlString));
336 }
337 }
338
339 /**
340 * Emits a signal to manipulate the tables definitions
341 *
342 * @param string $extensionKey
343 * @return mixed
344 * @throws ExtensionManagerException
345 */
346 protected function emitTablesDefinitionIsBeingBuiltSignal($extensionKey) {
347 $signalReturn = $this->signalSlotDispatcher->dispatch(__CLASS__, 'tablesDefinitionIsBeingBuilt', array(array(), $extensionKey));
348 // This is important to support old associated returns
349 $signalReturn = array_values($signalReturn);
350 $sqlString = $signalReturn[0];
351 if (!is_array($sqlString)) {
352 throw new ExtensionManagerException(
353 sprintf(
354 'The signal %s of class %s returned a value of type %s, but array was expected.',
355 'tablesDefinitionIsBeingBuilt',
356 __CLASS__,
357 gettype($sqlString)
358 ),
359 1382360258
360 );
361 }
362 return $sqlString;
363 }
364
365 /**
366 * Reload Cache files and Typo3LoadedExtensions
367 *
368 * @return void
369 */
370 public function reloadCaches() {
371 GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
372 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::loadExtLocalconf(FALSE);
373 \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadExtensionTables(FALSE);
374 }
375
376 /**
377 * Save default configuration of an extension
378 *
379 * @param string $extensionKey
380 * @return void
381 */
382 protected function saveDefaultConfiguration($extensionKey) {
383 /** @var $configUtility \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility */
384 $configUtility = $this->objectManager->get(\TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility::class);
385 $configUtility->saveDefaultConfiguration($extensionKey);
386 }
387
388 /**
389 * Update database / process db updates from ext_tables
390 *
391 * @param string $rawDefinitions The raw SQL statements from ext_tables.sql
392 * @return void
393 */
394 public function updateDbWithExtTablesSql($rawDefinitions) {
395 $fieldDefinitionsFromFile = $this->installToolSqlParser->getFieldDefinitions_fileContent($rawDefinitions);
396 if (!empty($fieldDefinitionsFromFile)) {
397 $fieldDefinitionsFromCurrentDatabase = $this->installToolSqlParser->getFieldDefinitions_database();
398 $diff = $this->installToolSqlParser->getDatabaseExtra($fieldDefinitionsFromFile, $fieldDefinitionsFromCurrentDatabase);
399 $updateStatements = $this->installToolSqlParser->getUpdateSuggestions($diff);
400 $db = $this->getDatabaseConnection();
401 foreach ((array)$updateStatements['add'] as $string) {
402 $db->admin_query($string);
403 }
404 foreach ((array)$updateStatements['change'] as $string) {
405 $db->admin_query($string);
406 }
407 foreach ((array)$updateStatements['create_table'] as $string) {
408 $db->admin_query($string);
409 }
410 }
411 }
412
413 /**
414 * Import static SQL data (normally used for ext_tables_static+adt.sql)
415 *
416 * @param string $rawDefinitions
417 * @return void
418 */
419 public function importStaticSql($rawDefinitions) {
420 $statements = $this->installToolSqlParser->getStatementarray($rawDefinitions, 1);
421 list($statementsPerTable, $insertCount) = $this->installToolSqlParser->getCreateTables($statements, 1);
422 $db = $this->getDatabaseConnection();
423 // Traverse the tables
424 foreach ($statementsPerTable as $table => $query) {
425 $db->admin_query('DROP TABLE IF EXISTS ' . $table);
426 $db->admin_query($query);
427 if ($insertCount[$table]) {
428 $insertStatements = $this->installToolSqlParser->getTableInsertStatements($statements, $table);
429 foreach ($insertStatements as $statement) {
430 $db->admin_query($statement);
431 }
432 }
433 }
434 }
435
436 /**
437 * Remove an extension (delete the directory)
438 *
439 * @param string $extension
440 * @throws ExtensionManagerException
441 * @return void
442 */
443 public function removeExtension($extension) {
444 $absolutePath = $this->fileHandlingUtility->getAbsoluteExtensionPath($extension);
445 if ($this->fileHandlingUtility->isValidExtensionPath($absolutePath)) {
446 if ($this->packageManager->isPackageAvailable($extension)) {
447 // Package manager deletes the extension and removes the entry from PackageStates.php
448 $this->packageManager->deletePackage($extension);
449 } else {
450 // The extension is not listed in PackageStates.php, we can safely remove it
451 $this->fileHandlingUtility->removeDirectory($absolutePath);
452 }
453 } else {
454 throw new ExtensionManagerException('No valid extension path given.', 1342875724);
455 }
456 }
457
458 /**
459 * Get the data dump for an extension
460 *
461 * @param string $extension
462 * @return array
463 */
464 public function getExtensionSqlDataDump($extension) {
465 $extension = $this->enrichExtensionWithDetails($extension);
466 $filePrefix = PATH_site . $extension['siteRelPath'];
467 $sqlData['extTables'] = $this->getSqlDataDumpForFile($filePrefix . 'ext_tables.sql');
468 $sqlData['staticSql'] = $this->getSqlDataDumpForFile($filePrefix . 'ext_tables_static+adt.sql');
469 return $sqlData;
470 }
471
472 /**
473 * Gets the sql data dump for a specific sql file (for example ext_tables.sql)
474 *
475 * @param string $sqlFile
476 * @return string
477 */
478 protected function getSqlDataDumpForFile($sqlFile) {
479 $sqlData = '';
480 if (file_exists($sqlFile)) {
481 $sqlContent = GeneralUtility::getUrl($sqlFile);
482 $fieldDefinitions = $this->installToolSqlParser->getFieldDefinitions_fileContent($sqlContent);
483 $sqlData = $this->databaseUtility->dumpStaticTables($fieldDefinitions);
484 }
485 return $sqlData;
486 }
487
488
489 /**
490 * Checks if an update for an extension is available which also resolves dependencies.
491 *
492 * @internal
493 * @param Extension $extensionData
494 * @return bool
495 */
496 public function isUpdateAvailable(Extension $extensionData) {
497 return (bool)$this->getUpdateableVersion($extensionData);
498 }
499
500 /**
501 * Returns the updateable version for an extension which also resolves dependencies.
502 *
503 * @internal
504 * @param Extension $extensionData
505 * @return bool|Extension FALSE if no update available otherwise latest possible update
506 */
507 public function getUpdateableVersion(Extension $extensionData) {
508 // Only check for update for TER extensions
509 $version = $extensionData->getIntegerVersion();
510
511 /** @var $extensionUpdates[] \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */
512 $extensionUpdates = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
513 $extensionData->getExtensionKey(),
514 $version,
515 0,
516 FALSE
517 );
518 if ($extensionUpdates->count() > 0) {
519 foreach ($extensionUpdates as $extensionUpdate) {
520 try {
521 $this->dependencyUtility->checkDependencies($extensionUpdate);
522 if (!$this->dependencyUtility->hasDependencyErrors()) {
523 return $extensionUpdate;
524 }
525 } catch (ExtensionManagerException $e) {
526 }
527 }
528 }
529 return FALSE;
530 }
531
532 /**
533 * Uses the export import extension to import a T3D or XML file to PID 0
534 * Execution state is saved in the this->registry, so it only happens once
535 *
536 * @param string $extensionSiteRelPath
537 * @return void
538 */
539 protected function importT3DFile($extensionSiteRelPath) {
540 $registryKeysToCheck = array(
541 $extensionSiteRelPath . 'Initialisation/data.t3d',
542 $extensionSiteRelPath . 'Initialisation/dataImported',
543 );
544 foreach ($registryKeysToCheck as $registryKeyToCheck) {
545 if ($this->registry->get('extensionDataImport', $registryKeyToCheck)) {
546 // Data was imported before => early return
547 return;
548 }
549 }
550 $importFileToUse = NULL;
551 $possibleImportFiles = array(
552 $extensionSiteRelPath . 'Initialisation/data.t3d',
553 $extensionSiteRelPath . 'Initialisation/data.xml'
554 );
555 foreach ($possibleImportFiles as $possibleImportFile) {
556 if (!file_exists(PATH_site . $possibleImportFile)) {
557 continue;
558 }
559 $importFileToUse = $possibleImportFile;
560 }
561 if ($importFileToUse !== NULL) {
562 /** @var ImportExportUtility $importExportUtility */
563 $importExportUtility = $this->objectManager->get(ImportExportUtility::class);
564 try {
565 $importResult = $importExportUtility->importT3DFile(PATH_site . $importFileToUse, 0);
566 $this->registry->set('extensionDataImport', $extensionSiteRelPath . 'Initialisation/dataImported', 1);
567 $this->emitAfterExtensionT3DImportSignal($importFileToUse, $importResult);
568 } catch (\ErrorException $e) {
569 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
570 $logger = $this->objectManager->get(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
571 $logger->log(\TYPO3\CMS\Core\Log\LogLevel::WARNING, $e->getMessage());
572 }
573 }
574 }
575
576 /**
577 * Emits a signal after an t3d file was imported
578 *
579 * @param string $importFileToUse
580 * @param int $importResult
581 */
582 protected function emitAfterExtensionT3DImportSignal($importFileToUse, $importResult) {
583 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionT3DImport', array($importFileToUse, $importResult, $this));
584 }
585
586 /**
587 * Imports a static tables SQL File (ext_tables_static+adt)
588 * Execution state is saved in the this->registry, so it only happens once
589 *
590 * @param string $extensionSiteRelPath
591 * @return void
592 */
593 protected function importStaticSqlFile($extensionSiteRelPath) {
594 $extTablesStaticSqlRelFile = $extensionSiteRelPath . 'ext_tables_static+adt.sql';
595 if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) {
596 $extTablesStaticSqlFile = PATH_site . $extTablesStaticSqlRelFile;
597 if (file_exists($extTablesStaticSqlFile)) {
598 $extTablesStaticSqlContent = GeneralUtility::getUrl($extTablesStaticSqlFile);
599 $this->importStaticSql($extTablesStaticSqlContent);
600 }
601 $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, 1);
602 $this->emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile);
603 }
604 }
605
606 /**
607 * Emits a signal after a static sql file was imported
608 *
609 * @param string $extTablesStaticSqlRelFile
610 */
611 protected function emitAfterExtensionStaticSqlImportSignal($extTablesStaticSqlRelFile) {
612 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionStaticSqlImport', array($extTablesStaticSqlRelFile, $this));
613 }
614
615 /**
616 * Imports files from Initialisation/Files to fileadmin
617 * via lowlevel copy directory method
618 *
619 * @param string $extensionSiteRelPath relative path to extension dir
620 * @param string $extensionKey
621 */
622 protected function importInitialFiles($extensionSiteRelPath, $extensionKey) {
623 $importRelFolder = $extensionSiteRelPath . 'Initialisation/Files';
624 if (!$this->registry->get('extensionDataImport', $importRelFolder)) {
625 $importFolder = PATH_site . $importRelFolder;
626 if (file_exists($importFolder)) {
627 $destinationRelPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . $extensionKey;
628 $destinationAbsolutePath = PATH_site . $destinationRelPath;
629 if (!file_exists($destinationAbsolutePath) &&
630 GeneralUtility::isAllowedAbsPath($destinationAbsolutePath)
631 ) {
632 GeneralUtility::mkdir($destinationAbsolutePath);
633 }
634 GeneralUtility::copyDirectory($importRelFolder, $destinationRelPath);
635 $this->registry->set('extensionDataImport', $importRelFolder, 1);
636 $this->emitAfterExtensionFileImportSignal($destinationAbsolutePath);
637 }
638 }
639 }
640
641 /**
642 * Emits a signal after extension files were imported
643 *
644 * @param string $destinationAbsolutePath
645 */
646 protected function emitAfterExtensionFileImportSignal($destinationAbsolutePath) {
647 $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterExtensionFileImport', array($destinationAbsolutePath, $this));
648 }
649
650 /**
651 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
652 */
653 protected function getDatabaseConnection() {
654 return $GLOBALS['TYPO3_DB'];
655 }
656
657 }