Passed
Push — master ( 934b11...b6e26a )
by
unknown
13:34
created

InstallUtility::injectLateBootService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Extensionmanager\Utility;
17
18
use Psr\EventDispatcher\EventDispatcherInterface;
19
use Psr\Log\LoggerAwareInterface;
20
use Psr\Log\LoggerAwareTrait;
21
use Symfony\Component\Finder\Finder;
22
use TYPO3\CMS\Core\Cache\CacheManager;
23
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
24
use TYPO3\CMS\Core\Configuration\SiteConfiguration;
25
use TYPO3\CMS\Core\Core\BootService;
26
use TYPO3\CMS\Core\Core\Bootstrap;
27
use TYPO3\CMS\Core\Core\Environment;
28
use TYPO3\CMS\Core\Database\Schema\SchemaMigrator;
29
use TYPO3\CMS\Core\Database\Schema\SqlReader;
30
use TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent;
31
use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent;
32
use TYPO3\CMS\Core\Package\PackageManager;
33
use TYPO3\CMS\Core\Registry;
34
use TYPO3\CMS\Core\Service\OpcodeCacheService;
35
use TYPO3\CMS\Core\SingletonInterface;
36
use TYPO3\CMS\Core\Site\Entity\Site;
37
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
38
use TYPO3\CMS\Core\Utility\GeneralUtility;
39
use TYPO3\CMS\Core\Utility\PathUtility;
40
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
41
use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
42
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent;
43
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent;
44
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionSiteFilesHaveBeenImportedEvent;
45
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent;
46
use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
47
use TYPO3\CMS\Impexp\Import;
48
use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
49
50
/**
51
 * Extension Manager Install Utility
52
 * @internal This class is a specific ExtensionManager implementation and is not part of the Public TYPO3 API.
53
 */
54
class InstallUtility implements SingletonInterface, LoggerAwareInterface
55
{
56
    use LoggerAwareTrait;
57
58
    /**
59
     * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
60
     */
61
    protected $fileHandlingUtility;
62
63
    /**
64
     * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
65
     */
66
    protected $listUtility;
67
68
    /**
69
     * @var \TYPO3\CMS\Core\Package\PackageManager
70
     */
71
    protected $packageManager;
72
73
    /**
74
     * @var \TYPO3\CMS\Core\Cache\CacheManager
75
     */
76
    protected $cacheManager;
77
78
    /**
79
     * @var \TYPO3\CMS\Core\Registry
80
     */
81
    protected $registry;
82
83
    /**
84
     * @var EventDispatcherInterface
85
     */
86
    protected $eventDispatcher;
87
88
    /**
89
     * @var BootService
90
     */
91
    protected $bootService;
92
93
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher)
94
    {
95
        $this->eventDispatcher = $eventDispatcher;
96
    }
97
98
    /**
99
     * @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
100
     */
101
    public function injectFileHandlingUtility(FileHandlingUtility $fileHandlingUtility)
102
    {
103
        $this->fileHandlingUtility = $fileHandlingUtility;
104
    }
105
106
    /**
107
     * @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
108
     */
109
    public function injectListUtility(ListUtility $listUtility)
110
    {
111
        $this->listUtility = $listUtility;
112
    }
113
114
    /**
115
     * @param \TYPO3\CMS\Core\Package\PackageManager $packageManager
116
     */
117
    public function injectPackageManager(PackageManager $packageManager)
118
    {
119
        $this->packageManager = $packageManager;
120
    }
121
122
    /**
123
     * @param \TYPO3\CMS\Core\Cache\CacheManager $cacheManager
124
     */
125
    public function injectCacheManager(CacheManager $cacheManager)
126
    {
127
        $this->cacheManager = $cacheManager;
128
    }
129
130
    /**
131
     * @param \TYPO3\CMS\Core\Registry $registry
132
     */
133
    public function injectRegistry(Registry $registry)
134
    {
135
        $this->registry = $registry;
136
    }
137
138
    /**
139
     * @param  BootService $bootService
140
     */
141
    public function injectBootService(BootService $bootService)
142
    {
143
        $this->bootService = $bootService;
144
    }
145
146
    /**
147
     * Helper function to install an extension
148
     * also processes db updates and clears the cache if the extension asks for it
149
     *
150
     * @param string ...$extensionKeys
151
     * @throws ExtensionManagerException
152
     */
153
    public function install(...$extensionKeys)
154
    {
155
        $flushCaches = false;
156
        foreach ($extensionKeys as $extensionKey) {
157
            $this->loadExtension($extensionKey);
158
            $extension = $this->enrichExtensionWithDetails($extensionKey, false);
159
            $this->saveDefaultConfiguration($extensionKey);
160
            if (!empty($extension['clearcacheonload']) || !empty($extension['clearCacheOnLoad'])) {
161
                $flushCaches = true;
162
            }
163
        }
164
165
        if ($flushCaches) {
166
            $this->cacheManager->flushCaches();
167
        } else {
168
            $this->cacheManager->flushCachesInGroup('system');
169
        }
170
171
        // Load a new container as reloadCaches will load ext_localconf
172
        $container = $this->bootService->getContainer(false);
173
        $backup = $this->bootService->makeCurrent($container);
174
175
        $this->reloadCaches();
176
        $this->updateDatabase();
177
178
        foreach ($extensionKeys as $extensionKey) {
179
            $this->processExtensionSetup($extensionKey);
180
            $container->get(EventDispatcherInterface::class)->dispatch(new AfterPackageActivationEvent($extensionKey, 'typo3-cms-extension', $this));
181
        }
182
183
        // Reset to the original container instance
184
        $this->bootService->makeCurrent(null, $backup);
185
    }
186
187
    /**
188
     * @param string $extensionKey
189
     */
190
    public function processExtensionSetup(string $extensionKey): void
191
    {
192
        $extension = $this->enrichExtensionWithDetails($extensionKey, false);
193
        $this->importInitialFiles($extension['packagePath'], $extensionKey);
194
        $this->importStaticSqlFile($extensionKey, $extension['packagePath']);
195
        $import = $this->importT3DFile($extensionKey, $extension['packagePath']);
196
        $this->importSiteConfiguration($extensionKey, $extension['packagePath'], $import);
197
    }
198
199
    /**
200
     * Helper function to uninstall an extension
201
     *
202
     * @param string $extensionKey
203
     * @throws ExtensionManagerException
204
     */
205
    public function uninstall($extensionKey)
206
    {
207
        $dependentExtensions = $this->findInstalledExtensionsThatDependOnExtension((string)$extensionKey);
208
        if (!empty($dependentExtensions)) {
209
            throw new ExtensionManagerException(
210
                LocalizationUtility::translate(
211
                    'extensionList.uninstall.dependencyError',
212
                    'extensionmanager',
213
                    [$extensionKey, implode(',', $dependentExtensions)]
214
                ) ?? '',
215
                1342554622
216
            );
217
        }
218
        $this->unloadExtension($extensionKey);
219
    }
220
221
    /**
222
     * Find installed extensions which depend on the given extension.
223
     * This is used at extension uninstall to stop the process if an installed
224
     * extension depends on the extension to be uninstalled.
225
     *
226
     * @param string $extensionKey
227
     * @return array
228
     */
229
    protected function findInstalledExtensionsThatDependOnExtension(string $extensionKey): array
230
    {
231
        $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensionsWithAdditionalInformation();
232
        $dependentExtensions = [];
233
        foreach ($availableAndInstalledExtensions as $availableAndInstalledExtensionKey => $availableAndInstalledExtension) {
234
            if (isset($availableAndInstalledExtension['installed']) && $availableAndInstalledExtension['installed'] === true) {
235
                if (is_array($availableAndInstalledExtension['constraints']) && is_array($availableAndInstalledExtension['constraints']['depends']) && array_key_exists($extensionKey, $availableAndInstalledExtension['constraints']['depends'])) {
236
                    $dependentExtensions[] = $availableAndInstalledExtensionKey;
237
                }
238
            }
239
        }
240
        return $dependentExtensions;
241
    }
242
243
    /**
244
     * Reset and reload the available extensions
245
     */
246
    public function reloadAvailableExtensions()
247
    {
248
        $this->listUtility->reloadAvailableExtensions();
249
    }
250
251
    /**
252
     * Wrapper function for loading extensions
253
     *
254
     * @param string $extensionKey
255
     */
256
    protected function loadExtension($extensionKey)
257
    {
258
        $this->packageManager->activatePackage($extensionKey);
259
    }
260
261
    /**
262
     * Wrapper function for unloading extensions
263
     *
264
     * @param string $extensionKey
265
     */
266
    protected function unloadExtension($extensionKey)
267
    {
268
        $this->packageManager->deactivatePackage($extensionKey);
269
        $this->eventDispatcher->dispatch(new AfterPackageDeactivationEvent($extensionKey, 'typo3-cms-extension', $this));
270
        $this->cacheManager->flushCachesInGroup('system');
271
    }
272
273
    /**
274
     * Checks if an extension is available in the system
275
     *
276
     * @param string $extensionKey
277
     * @return bool
278
     */
279
    public function isAvailable($extensionKey)
280
    {
281
        return $this->packageManager->isPackageAvailable($extensionKey);
282
    }
283
284
    /**
285
     * Reloads the package information, if the package is already registered
286
     *
287
     * @param string $extensionKey
288
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageStateException if the package isn't available
289
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageKeyException if an invalid package key was passed
290
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackagePathException if an invalid package path was passed
291
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageManifestException if no extension configuration file could be found
292
     */
293
    public function reloadPackageInformation($extensionKey)
294
    {
295
        if ($this->packageManager->isPackageAvailable($extensionKey)) {
296
            $this->reloadOpcache();
297
            $this->packageManager->reloadPackageInformation($extensionKey);
298
        }
299
    }
300
301
    /**
302
     * Fetch additional information for an extension key
303
     *
304
     * @param string $extensionKey
305
     * @param bool $loadTerInformation
306
     * @return array
307
     * @throws ExtensionManagerException
308
     * @internal
309
     */
310
    public function enrichExtensionWithDetails($extensionKey, $loadTerInformation = true)
311
    {
312
        $extension = $this->getExtensionArray($extensionKey);
313
        if (!$loadTerInformation) {
314
            $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfInformation([$extensionKey => $extension]);
315
        } else {
316
            $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation([$extensionKey => $extension]);
317
        }
318
319
        if (!isset($availableAndInstalledExtensions[$extensionKey])) {
320
            throw new ExtensionManagerException(
321
                'Please check your uploaded extension "' . $extensionKey . '". The configuration file "ext_emconf.php" seems to be invalid.',
322
                1391432222
323
            );
324
        }
325
326
        return $availableAndInstalledExtensions[$extensionKey];
327
    }
328
329
    /**
330
     * @param string $extensionKey
331
     * @return array
332
     * @throws ExtensionManagerException
333
     */
334
    protected function getExtensionArray($extensionKey)
335
    {
336
        $availableExtensions = $this->listUtility->getAvailableExtensions();
337
        if (isset($availableExtensions[$extensionKey])) {
338
            return $availableExtensions[$extensionKey];
339
        }
340
        throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
341
    }
342
343
    /**
344
     * Reload Cache files and Typo3LoadedExtensions
345
     */
346
    public function reloadCaches()
347
    {
348
        $this->reloadOpcache();
349
        ExtensionManagementUtility::loadExtLocalconf(false);
350
        Bootstrap::loadBaseTca(false);
351
        Bootstrap::loadExtTables(false);
352
    }
353
354
    /**
355
     * Reloads PHP opcache
356
     */
357
    protected function reloadOpcache()
358
    {
359
        GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
360
    }
361
362
    /**
363
     * Executes all safe database statements.
364
     * Tables and fields are created and altered. Nothing gets deleted or renamed here.
365
     */
366
    protected function updateDatabase()
367
    {
368
        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
369
        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
370
        $sqlStatements = [];
371
        $sqlStatements[] = $sqlReader->getTablesDefinitionString();
372
        $sqlStatements = $sqlReader->getCreateTableStatementArray(implode(LF . LF, array_filter($sqlStatements)));
373
        $updateStatements = $schemaMigrator->getUpdateSuggestions($sqlStatements);
374
375
        $updateStatements = array_merge_recursive(...array_values($updateStatements));
376
        $selectedStatements = [];
377
        foreach (['add', 'change', 'create_table', 'change_table'] as $action) {
378
            if (empty($updateStatements[$action])) {
379
                continue;
380
            }
381
382
            $statements = array_combine(array_keys($updateStatements[$action]), array_fill(0, count($updateStatements[$action]), true));
383
            $statements = is_array($statements) ? $statements : [];
384
            $selectedStatements = array_merge(
385
                $selectedStatements,
386
                $statements
387
            );
388
        }
389
390
        $schemaMigrator->migrate($sqlStatements, $selectedStatements);
391
    }
392
393
    /**
394
     * Save default configuration of an extension
395
     *
396
     * @param string $extensionKey
397
     */
398
    protected function saveDefaultConfiguration($extensionKey)
399
    {
400
        $extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
401
        $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfiguration($extensionKey);
402
    }
403
404
    /**
405
     * Import static SQL data (normally used for ext_tables_static+adt.sql)
406
     *
407
     * @param string $rawDefinitions
408
     */
409
    public function importStaticSql($rawDefinitions)
410
    {
411
        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
412
        $statements = $sqlReader->getStatementArray($rawDefinitions);
413
414
        $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class);
415
        $schemaMigrationService->importStaticData($statements, true);
416
    }
417
418
    /**
419
     * Remove an extension (delete the directory)
420
     *
421
     * @param string $extension
422
     * @throws ExtensionManagerException
423
     */
424
    public function removeExtension($extension)
425
    {
426
        $absolutePath = $this->enrichExtensionWithDetails($extension)['packagePath'];
427
        if ($this->isValidExtensionPath($absolutePath)) {
428
            if ($this->packageManager->isPackageAvailable($extension)) {
429
                // Package manager deletes the extension and removes the entry from PackageStates.php
430
                $this->packageManager->deletePackage($extension);
431
            } else {
432
                // The extension is not listed in PackageStates.php, we can safely remove it
433
                $this->fileHandlingUtility->removeDirectory($absolutePath);
434
            }
435
        } else {
436
            throw new ExtensionManagerException('No valid extension path given.', 1342875724);
437
        }
438
    }
439
440
    /**
441
     * Uses the export import extension to import a T3D or XML file to PID 0
442
     * Execution state is saved in the this->registry, so it only happens once
443
     *
444
     * @param string $extensionKey
445
     * @param string $packagePath
446
     * @return Import|null
447
     */
448
    protected function importT3DFile($extensionKey, $packagePath): ?Import
449
    {
450
        $extensionSiteRelPath = PathUtility::stripPathSitePrefix($packagePath);
451
        $registryKeysToCheck = [
452
            $extensionSiteRelPath . 'Initialisation/data.t3d',
453
            $extensionSiteRelPath . 'Initialisation/dataImported',
454
        ];
455
        foreach ($registryKeysToCheck as $registryKeyToCheck) {
456
            if ($this->registry->get('extensionDataImport', $registryKeyToCheck)) {
457
                // Data was imported before => early return
458
                return null;
459
            }
460
        }
461
        $importFileToUse = null;
462
        $possibleImportFiles = [
463
            $packagePath . 'Initialisation/data.t3d',
464
            $packagePath . 'Initialisation/data.xml'
465
        ];
466
        foreach ($possibleImportFiles as $possibleImportFile) {
467
            if (!file_exists($possibleImportFile)) {
468
                continue;
469
            }
470
            $importFileToUse = $possibleImportFile;
471
        }
472
        if ($importFileToUse !== null) {
473
            $importExportUtility = GeneralUtility::makeInstance(ImportExportUtility::class);
474
            try {
475
                $importResult = $importExportUtility->importT3DFile($importFileToUse, 0);
476
                $this->registry->set('extensionDataImport', $extensionSiteRelPath . 'Initialisation/dataImported', 1);
477
                $this->eventDispatcher->dispatch(new AfterExtensionDatabaseContentHasBeenImportedEvent($extensionKey, $importFileToUse, $importResult, $this));
478
                return $importExportUtility->getImport();
479
            } catch (\ErrorException $e) {
480
                $this->logger->warning($e->getMessage(), ['exception' => $e]);
481
            }
482
        }
483
        return null;
484
    }
485
486
    /**
487
     * Imports a static tables SQL File (ext_tables_static+adt)
488
     * Execution state is saved in the this->registry, so it only happens once
489
     *
490
     * @param string $extensionKey
491
     * @param string $packagePath
492
     */
493
    protected function importStaticSqlFile(string $extensionKey, $packagePath)
494
    {
495
        $extTablesStaticSqlFile = $packagePath . 'ext_tables_static+adt.sql';
496
        $extTablesStaticSqlRelFile = PathUtility::stripPathSitePrefix($extTablesStaticSqlFile);
497
        if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) {
498
            $shortFileHash = '';
499
            if (file_exists($extTablesStaticSqlFile)) {
500
                $extTablesStaticSqlContent = (string)file_get_contents($extTablesStaticSqlFile);
501
                $shortFileHash = md5($extTablesStaticSqlContent);
502
                $this->importStaticSql($extTablesStaticSqlContent);
503
            }
504
            $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, $shortFileHash);
505
            $this->eventDispatcher->dispatch(new AfterExtensionStaticDatabaseContentHasBeenImportedEvent($extensionKey, $extTablesStaticSqlFile, $this));
506
        }
507
    }
508
509
    /**
510
     * Imports files from Initialisation/Files to fileadmin
511
     * via lowlevel copy directory method
512
     *
513
     * @param string $packagePath absolute path to extension dir
514
     * @param string $extensionKey
515
     */
516
    protected function importInitialFiles($packagePath, $extensionKey)
517
    {
518
        $importFolder = $packagePath . 'Initialisation/Files';
519
        $importRelFolder = PathUtility::stripPathSitePrefix($importFolder);
520
        if (!$this->registry->get('extensionDataImport', $importRelFolder)) {
521
            if (file_exists($importFolder)) {
522
                $destinationAbsolutePath = GeneralUtility::getFileAbsFileName($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . $extensionKey);
523
                if (!file_exists($destinationAbsolutePath) &&
524
                    GeneralUtility::isAllowedAbsPath($destinationAbsolutePath)
525
                ) {
526
                    GeneralUtility::mkdir($destinationAbsolutePath);
527
                }
528
                GeneralUtility::copyDirectory($importFolder, $destinationAbsolutePath);
529
                $this->registry->set('extensionDataImport', $importRelFolder, 1);
530
                $this->eventDispatcher->dispatch(new AfterExtensionFilesHaveBeenImportedEvent($extensionKey, $destinationAbsolutePath, $this));
531
            }
532
        }
533
    }
534
535
    /**
536
     * @param string $extensionKey
537
     * @param string $packagePath
538
     * @param Import|null $import
539
     */
540
    protected function importSiteConfiguration(string $extensionKey, string $packagePath, Import $import = null): void
541
    {
542
        $importAbsFolder = $packagePath . 'Initialisation/Site';
543
        $destinationFolder = Environment::getConfigPath() . '/sites';
544
545
        if (!is_dir($importAbsFolder)) {
546
            return;
547
        }
548
549
        $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class);
550
        $existingSites = $siteConfiguration->resolveAllExistingSites(false);
551
552
        GeneralUtility::mkdir($destinationFolder);
553
        $finder = GeneralUtility::makeInstance(Finder::class);
554
        $finder->directories()->in($importAbsFolder);
555
        if ($finder->hasResults()) {
556
            foreach ($finder as $siteConfigDirectory) {
557
                $siteIdentifier = $siteConfigDirectory->getBasename();
558
                if (isset($existingSites[$siteIdentifier])) {
559
                    $this->logger->warning(
560
                        sprintf(
561
                            'Skipped importing site configuration from %s due to existing site identifier %s',
562
                            $extensionKey,
563
                            $siteIdentifier
564
                        )
565
                    );
566
                    continue;
567
                }
568
                $targetDir = $destinationFolder . '/' . $siteIdentifier;
569
                if (!$this->registry->get('siteConfigImport', $siteIdentifier) && !is_dir($targetDir)) {
570
                    GeneralUtility::mkdir($targetDir);
571
                    GeneralUtility::copyDirectory($siteConfigDirectory->getPathname(), $targetDir);
572
                    $this->registry->set('siteConfigImport', $siteIdentifier, 1);
573
                }
574
            }
575
        }
576
577
        /** @var Site[] $newSites */
578
        $newSites = array_diff_key($siteConfiguration->resolveAllExistingSites(false), $existingSites);
579
        $importedPages = [];
580
        if ($import instanceof Import && !empty($import->import_mapId['pages'])) {
581
            $importedPages = $import->import_mapId['pages'];
582
        }
583
584
        $newSiteIdentifierList = [];
585
        foreach ($newSites as $newSite) {
586
            $exportedPageId = $newSite->getRootPageId();
587
            $siteIdentifier = $newSite->getIdentifier();
588
            $newSiteIdentifierList[] = $siteIdentifier;
589
            $importedPageId = $importedPages[$exportedPageId] ?? null;
590
            if ($importedPageId === null) {
591
                $this->logger->warning(
592
                    sprintf(
593
                        'Imported site configuration with identifier %s could not be mapped to imported page id',
594
                        $siteIdentifier
595
                    )
596
                );
597
                continue;
598
            }
599
            $configuration = $siteConfiguration->load($siteIdentifier);
600
            $configuration['rootPageId'] = $importedPageId;
601
            $siteConfiguration->write($siteIdentifier, $configuration);
602
        }
603
        $this->eventDispatcher->dispatch(new AfterExtensionSiteFilesHaveBeenImportedEvent($extensionKey, $newSiteIdentifierList));
604
    }
605
606
    /**
607
     * Is the given path a valid path for extension installation
608
     *
609
     * @param string $path the absolute (!) path in question
610
     * @return bool
611
     */
612
    protected function isValidExtensionPath($path): bool
613
    {
614
        $allowedPaths = Extension::returnAllowedInstallPaths();
615
        foreach ($allowedPaths as $allowedPath) {
616
            if (GeneralUtility::isFirstPartOfStr($path, $allowedPath)) {
617
                return true;
618
            }
619
        }
620
        return false;
621
    }
622
}
623