Completed
Push — master ( e4f4ca...4e498f )
by
unknown
14:28
created

InstallUtility::injectCacheManager()   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\Bootstrap;
26
use TYPO3\CMS\Core\Core\Environment;
27
use TYPO3\CMS\Core\Database\Schema\SchemaMigrator;
28
use TYPO3\CMS\Core\Database\Schema\SqlReader;
29
use TYPO3\CMS\Core\Package\Event\AfterPackageActivationEvent;
30
use TYPO3\CMS\Core\Package\Event\AfterPackageDeactivationEvent;
31
use TYPO3\CMS\Core\Package\PackageManager;
32
use TYPO3\CMS\Core\Registry;
33
use TYPO3\CMS\Core\Service\OpcodeCacheService;
34
use TYPO3\CMS\Core\SingletonInterface;
35
use TYPO3\CMS\Core\Site\Entity\Site;
36
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
39
use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
40
use TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository;
41
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionDatabaseContentHasBeenImportedEvent;
42
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionFilesHaveBeenImportedEvent;
43
use TYPO3\CMS\Extensionmanager\Event\AfterExtensionStaticDatabaseContentHasBeenImportedEvent;
44
use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
45
use TYPO3\CMS\Impexp\Import;
46
use TYPO3\CMS\Impexp\Utility\ImportExportUtility;
47
use TYPO3\CMS\Install\Service\LateBootService;
48
49
/**
50
 * Extension Manager Install Utility
51
 * @internal This class is a specific ExtensionManager implementation and is not part of the Public TYPO3 API.
52
 */
53
class InstallUtility implements SingletonInterface, LoggerAwareInterface
54
{
55
    use LoggerAwareTrait;
56
57
    /**
58
     * @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
59
     */
60
    protected $dependencyUtility;
61
62
    /**
63
     * @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
64
     */
65
    protected $fileHandlingUtility;
66
67
    /**
68
     * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
69
     */
70
    protected $listUtility;
71
72
    /**
73
     * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
74
     */
75
    public $extensionRepository;
76
77
    /**
78
     * @var \TYPO3\CMS\Core\Package\PackageManager
79
     */
80
    protected $packageManager;
81
82
    /**
83
     * @var \TYPO3\CMS\Core\Cache\CacheManager
84
     */
85
    protected $cacheManager;
86
87
    /**
88
     * @var \TYPO3\CMS\Core\Registry
89
     */
90
    protected $registry;
91
92
    /**
93
     * @var EventDispatcherInterface
94
     */
95
    protected $eventDispatcher;
96
97
    /**
98
     * @var LateBootService
99
     */
100
    protected $lateBootService;
101
102
    public function injectEventDispatcher(EventDispatcherInterface $eventDispatcher)
103
    {
104
        $this->eventDispatcher = $eventDispatcher;
105
    }
106
107
    /**
108
     * @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility
109
     */
110
    public function injectDependencyUtility(DependencyUtility $dependencyUtility)
111
    {
112
        $this->dependencyUtility = $dependencyUtility;
113
    }
114
115
    /**
116
     * @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
117
     */
118
    public function injectFileHandlingUtility(FileHandlingUtility $fileHandlingUtility)
119
    {
120
        $this->fileHandlingUtility = $fileHandlingUtility;
121
    }
122
123
    /**
124
     * @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
125
     */
126
    public function injectListUtility(ListUtility $listUtility)
127
    {
128
        $this->listUtility = $listUtility;
129
    }
130
131
    /**
132
     * @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
133
     */
134
    public function injectExtensionRepository(ExtensionRepository $extensionRepository)
135
    {
136
        $this->extensionRepository = $extensionRepository;
137
    }
138
139
    /**
140
     * @param \TYPO3\CMS\Core\Package\PackageManager $packageManager
141
     */
142
    public function injectPackageManager(PackageManager $packageManager)
143
    {
144
        $this->packageManager = $packageManager;
145
    }
146
147
    /**
148
     * @param \TYPO3\CMS\Core\Cache\CacheManager $cacheManager
149
     */
150
    public function injectCacheManager(CacheManager $cacheManager)
151
    {
152
        $this->cacheManager = $cacheManager;
153
    }
154
155
    /**
156
     * @param \TYPO3\CMS\Core\Registry $registry
157
     */
158
    public function injectRegistry(Registry $registry)
159
    {
160
        $this->registry = $registry;
161
    }
162
163
    /**
164
     * @param  LateBootService $lateBootService
165
     */
166
    public function injectLateBootService(LateBootService $lateBootService)
167
    {
168
        $this->lateBootService = $lateBootService;
169
    }
170
171
    /**
172
     * Helper function to install an extension
173
     * also processes db updates and clears the cache if the extension asks for it
174
     *
175
     * @param array<int,mixed> $extensionKeys
176
     * @throws ExtensionManagerException
177
     */
178
    public function install(...$extensionKeys)
179
    {
180
        $flushCaches = false;
181
        foreach ($extensionKeys as $extensionKey) {
182
            $this->loadExtension($extensionKey);
183
            $extension = $this->enrichExtensionWithDetails($extensionKey, false);
184
            $this->saveDefaultConfiguration($extensionKey);
185
            if (!empty($extension['clearcacheonload']) || !empty($extension['clearCacheOnLoad'])) {
186
                $flushCaches = true;
187
            }
188
        }
189
190
        if ($flushCaches) {
191
            $this->cacheManager->flushCaches();
192
        } else {
193
            $this->cacheManager->flushCachesInGroup('system');
194
        }
195
196
        // Load a new container as reloadCaches will load ext_localconf
197
        $container = $this->lateBootService->getContainer();
198
        $backup = $this->lateBootService->makeCurrent($container);
199
200
        $this->reloadCaches();
201
        $this->updateDatabase();
202
203
        foreach ($extensionKeys as $extensionKey) {
204
            $this->processExtensionSetup($extensionKey);
205
            $container->get(EventDispatcherInterface::class)->dispatch(new AfterPackageActivationEvent($extensionKey, 'typo3-cms-extension', $this));
206
        }
207
208
        // Reset to the original container instance
209
        $this->lateBootService->makeCurrent(null, $backup);
210
    }
211
212
    /**
213
     * @param string $extensionKey
214
     */
215
    public function processExtensionSetup(string $extensionKey): void
216
    {
217
        $extension = $this->enrichExtensionWithDetails($extensionKey, false);
218
        $this->importInitialFiles($extension['siteRelPath'] ?? '', $extensionKey);
219
        $this->importStaticSqlFile($extensionKey, $extension['siteRelPath']);
220
        $import = $this->importT3DFile($extensionKey, $extension['siteRelPath']);
221
        $this->importSiteConfiguration($extension['siteRelPath'], $import);
222
    }
223
224
    /**
225
     * Helper function to uninstall an extension
226
     *
227
     * @param string $extensionKey
228
     * @throws ExtensionManagerException
229
     */
230
    public function uninstall($extensionKey)
231
    {
232
        $dependentExtensions = $this->dependencyUtility->findInstalledExtensionsThatDependOnMe($extensionKey);
233
        if (is_array($dependentExtensions) && !empty($dependentExtensions)) {
234
            throw new ExtensionManagerException(
235
                LocalizationUtility::translate(
236
                    'extensionList.uninstall.dependencyError',
237
                    'extensionmanager',
238
                    [$extensionKey, implode(',', $dependentExtensions)]
239
                ),
240
                1342554622
241
            );
242
        }
243
        $this->unloadExtension($extensionKey);
244
    }
245
246
    /**
247
     * Wrapper function to check for loaded extensions
248
     *
249
     * @param string $extensionKey
250
     * @return bool TRUE if extension is loaded
251
     */
252
    public function isLoaded($extensionKey)
253
    {
254
        return $this->packageManager->isPackageActive($extensionKey);
255
    }
256
257
    /**
258
     * Reset and reload the available extensions
259
     */
260
    public function reloadAvailableExtensions()
261
    {
262
        $this->listUtility->reloadAvailableExtensions();
263
    }
264
265
    /**
266
     * Wrapper function for loading extensions
267
     *
268
     * @param string $extensionKey
269
     */
270
    protected function loadExtension($extensionKey)
271
    {
272
        $this->packageManager->activatePackage($extensionKey);
273
    }
274
275
    /**
276
     * Wrapper function for unloading extensions
277
     *
278
     * @param string $extensionKey
279
     */
280
    protected function unloadExtension($extensionKey)
281
    {
282
        $this->packageManager->deactivatePackage($extensionKey);
283
        $this->eventDispatcher->dispatch(new AfterPackageDeactivationEvent($extensionKey, 'typo3-cms-extension', $this));
284
        $this->cacheManager->flushCachesInGroup('system');
285
    }
286
287
    /**
288
     * Checks if an extension is available in the system
289
     *
290
     * @param string $extensionKey
291
     * @return bool
292
     */
293
    public function isAvailable($extensionKey)
294
    {
295
        return $this->packageManager->isPackageAvailable($extensionKey);
296
    }
297
298
    /**
299
     * Reloads the package information, if the package is already registered
300
     *
301
     * @param string $extensionKey
302
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageStateException if the package isn't available
303
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageKeyException if an invalid package key was passed
304
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackagePathException if an invalid package path was passed
305
     * @throws \TYPO3\CMS\Core\Package\Exception\InvalidPackageManifestException if no extension configuration file could be found
306
     */
307
    public function reloadPackageInformation($extensionKey)
308
    {
309
        if ($this->packageManager->isPackageAvailable($extensionKey)) {
310
            $this->reloadOpcache();
311
            $this->packageManager->reloadPackageInformation($extensionKey);
312
        }
313
    }
314
315
    /**
316
     * Fetch additional information for an extension key
317
     *
318
     * @param string $extensionKey
319
     * @param bool $loadTerInformation
320
     * @return array
321
     * @throws ExtensionManagerException
322
     * @internal
323
     */
324
    public function enrichExtensionWithDetails($extensionKey, $loadTerInformation = true)
325
    {
326
        $extension = $this->getExtensionArray($extensionKey);
327
        if (!$loadTerInformation) {
328
            $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfInformation([$extensionKey => $extension]);
329
        } else {
330
            $availableAndInstalledExtensions = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation([$extensionKey => $extension]);
331
        }
332
333
        if (!isset($availableAndInstalledExtensions[$extensionKey])) {
334
            throw new ExtensionManagerException(
335
                'Please check your uploaded extension "' . $extensionKey . '". The configuration file "ext_emconf.php" seems to be invalid.',
336
                1391432222
337
            );
338
        }
339
340
        return $availableAndInstalledExtensions[$extensionKey];
341
    }
342
343
    /**
344
     * @param string $extensionKey
345
     * @return array
346
     * @throws ExtensionManagerException
347
     */
348
    protected function getExtensionArray($extensionKey)
349
    {
350
        $availableExtensions = $this->listUtility->getAvailableExtensions();
351
        if (isset($availableExtensions[$extensionKey])) {
352
            return $availableExtensions[$extensionKey];
353
        }
354
        throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1342864081);
355
    }
356
357
    /**
358
     * Reload Cache files and Typo3LoadedExtensions
359
     */
360
    public function reloadCaches()
361
    {
362
        $this->reloadOpcache();
363
        ExtensionManagementUtility::loadExtLocalconf(false);
364
        Bootstrap::loadBaseTca(false);
365
        Bootstrap::loadExtTables(false);
366
    }
367
368
    /**
369
     * Reloads PHP opcache
370
     */
371
    protected function reloadOpcache()
372
    {
373
        GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive();
374
    }
375
376
    /**
377
     * Executes all safe database statements.
378
     * Tables and fields are created and altered. Nothing gets deleted or renamed here.
379
     */
380
    protected function updateDatabase()
381
    {
382
        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
383
        $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
384
        $sqlStatements = [];
385
        $sqlStatements[] = $sqlReader->getTablesDefinitionString();
386
        $sqlStatements = $sqlReader->getCreateTableStatementArray(implode(LF . LF, array_filter($sqlStatements)));
387
        $updateStatements = $schemaMigrator->getUpdateSuggestions($sqlStatements);
388
389
        $updateStatements = array_merge_recursive(...array_values($updateStatements));
390
        $selectedStatements = [];
391
        foreach (['add', 'change', 'create_table', 'change_table'] as $action) {
392
            if (empty($updateStatements[$action])) {
393
                continue;
394
            }
395
            $selectedStatements = array_merge(
396
                $selectedStatements,
397
                array_combine(array_keys($updateStatements[$action]), array_fill(0, count($updateStatements[$action]), true))
0 ignored issues
show
Bug introduced by
It seems like array_combine(array_keys...ments[$action]), true)) can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

397
                /** @scrutinizer ignore-type */ array_combine(array_keys($updateStatements[$action]), array_fill(0, count($updateStatements[$action]), true))
Loading history...
398
            );
399
        }
400
401
        $schemaMigrator->migrate($sqlStatements, $selectedStatements);
402
    }
403
404
    /**
405
     * Save default configuration of an extension
406
     *
407
     * @param string $extensionKey
408
     */
409
    protected function saveDefaultConfiguration($extensionKey)
410
    {
411
        $extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
412
        $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfiguration($extensionKey);
413
    }
414
415
    /**
416
     * Import static SQL data (normally used for ext_tables_static+adt.sql)
417
     *
418
     * @param string $rawDefinitions
419
     */
420
    public function importStaticSql($rawDefinitions)
421
    {
422
        $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
423
        $statements = $sqlReader->getStatementArray($rawDefinitions);
424
425
        $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class);
426
        $schemaMigrationService->importStaticData($statements, true);
427
    }
428
429
    /**
430
     * Remove an extension (delete the directory)
431
     *
432
     * @param string $extension
433
     * @throws ExtensionManagerException
434
     */
435
    public function removeExtension($extension)
436
    {
437
        $absolutePath = $this->fileHandlingUtility->getAbsoluteExtensionPath($extension);
438
        if ($this->fileHandlingUtility->isValidExtensionPath($absolutePath)) {
439
            if ($this->packageManager->isPackageAvailable($extension)) {
440
                // Package manager deletes the extension and removes the entry from PackageStates.php
441
                $this->packageManager->deletePackage($extension);
442
            } else {
443
                // The extension is not listed in PackageStates.php, we can safely remove it
444
                $this->fileHandlingUtility->removeDirectory($absolutePath);
445
            }
446
        } else {
447
            throw new ExtensionManagerException('No valid extension path given.', 1342875724);
448
        }
449
    }
450
451
    /**
452
     * Returns the updateable version for an extension which also resolves dependencies.
453
     *
454
     * @param Extension $extensionData
455
     * @return bool|Extension FALSE if no update available otherwise latest possible update
456
     * @internal
457
     */
458
    public function getUpdateableVersion(Extension $extensionData)
459
    {
460
        // Only check for update for TER extensions
461
        $version = $extensionData->getIntegerVersion();
462
463
        $extensionUpdates = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
464
            $extensionData->getExtensionKey(),
465
            $version,
466
            0,
467
            false
468
        );
469
        if ($extensionUpdates->count() > 0) {
470
            foreach ($extensionUpdates as $extensionUpdate) {
471
                /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionUpdate */
472
                try {
473
                    $this->dependencyUtility->checkDependencies($extensionUpdate);
474
                    if (!$this->dependencyUtility->hasDependencyErrors()) {
475
                        return $extensionUpdate;
476
                    }
477
                } catch (ExtensionManagerException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
478
                }
479
            }
480
        }
481
        return false;
482
    }
483
484
    /**
485
     * Uses the export import extension to import a T3D or XML file to PID 0
486
     * Execution state is saved in the this->registry, so it only happens once
487
     *
488
     * @param string $extensionKey
489
     * @param string $extensionSiteRelPath
490
     * @return Import|null
491
     */
492
    protected function importT3DFile($extensionKey, $extensionSiteRelPath): ?Import
493
    {
494
        $registryKeysToCheck = [
495
            $extensionSiteRelPath . 'Initialisation/data.t3d',
496
            $extensionSiteRelPath . 'Initialisation/dataImported',
497
        ];
498
        foreach ($registryKeysToCheck as $registryKeyToCheck) {
499
            if ($this->registry->get('extensionDataImport', $registryKeyToCheck)) {
500
                // Data was imported before => early return
501
                return null;
502
            }
503
        }
504
        $importFileToUse = null;
505
        $possibleImportFiles = [
506
            $extensionSiteRelPath . 'Initialisation/data.t3d',
507
            $extensionSiteRelPath . 'Initialisation/data.xml'
508
        ];
509
        foreach ($possibleImportFiles as $possibleImportFile) {
510
            if (!file_exists(Environment::getPublicPath() . '/' . $possibleImportFile)) {
511
                continue;
512
            }
513
            $importFileToUse = $possibleImportFile;
514
        }
515
        if ($importFileToUse !== null) {
516
            $importExportUtility = GeneralUtility::makeInstance(ImportExportUtility::class);
517
            try {
518
                $importResult = $importExportUtility->importT3DFile(Environment::getPublicPath() . '/' . $importFileToUse, 0);
519
                $this->registry->set('extensionDataImport', $extensionSiteRelPath . 'Initialisation/dataImported', 1);
520
                $this->eventDispatcher->dispatch(new AfterExtensionDatabaseContentHasBeenImportedEvent($extensionKey, $importFileToUse, $importResult, $this));
521
                return $importExportUtility->getImport();
522
            } catch (\ErrorException $e) {
523
                $this->logger->warning($e->getMessage(), ['exception' => $e]);
524
            }
525
        }
526
        return null;
527
    }
528
529
    /**
530
     * Imports a static tables SQL File (ext_tables_static+adt)
531
     * Execution state is saved in the this->registry, so it only happens once
532
     *
533
     * @param string $extensionKey
534
     * @param string $extensionSiteRelPath
535
     */
536
    protected function importStaticSqlFile(string $extensionKey, $extensionSiteRelPath)
537
    {
538
        $extTablesStaticSqlRelFile = $extensionSiteRelPath . 'ext_tables_static+adt.sql';
539
        if (!$this->registry->get('extensionDataImport', $extTablesStaticSqlRelFile)) {
540
            $extTablesStaticSqlFile = Environment::getPublicPath() . '/' . $extTablesStaticSqlRelFile;
541
            $shortFileHash = '';
542
            if (file_exists($extTablesStaticSqlFile)) {
543
                $extTablesStaticSqlContent = file_get_contents($extTablesStaticSqlFile);
544
                $shortFileHash = md5($extTablesStaticSqlContent);
545
                $this->importStaticSql($extTablesStaticSqlContent);
546
            }
547
            $this->registry->set('extensionDataImport', $extTablesStaticSqlRelFile, $shortFileHash);
548
            $this->eventDispatcher->dispatch(new AfterExtensionStaticDatabaseContentHasBeenImportedEvent($extensionKey, $extTablesStaticSqlRelFile, $this));
549
        }
550
    }
551
552
    /**
553
     * Imports files from Initialisation/Files to fileadmin
554
     * via lowlevel copy directory method
555
     *
556
     * @param string $extensionSiteRelPath relative path to extension dir
557
     * @param string $extensionKey
558
     */
559
    protected function importInitialFiles($extensionSiteRelPath, $extensionKey)
560
    {
561
        $importRelFolder = $extensionSiteRelPath . 'Initialisation/Files';
562
        if (!$this->registry->get('extensionDataImport', $importRelFolder)) {
563
            $importFolder = Environment::getPublicPath() . '/' . $importRelFolder;
564
            if (file_exists($importFolder)) {
565
                $destinationRelPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . $extensionKey;
566
                $destinationAbsolutePath = Environment::getPublicPath() . '/' . $destinationRelPath;
567
                if (!file_exists($destinationAbsolutePath) &&
568
                    GeneralUtility::isAllowedAbsPath($destinationAbsolutePath)
569
                ) {
570
                    GeneralUtility::mkdir($destinationAbsolutePath);
571
                }
572
                GeneralUtility::copyDirectory($importRelFolder, $destinationRelPath);
573
                $this->registry->set('extensionDataImport', $importRelFolder, 1);
574
                $this->eventDispatcher->dispatch(new AfterExtensionFilesHaveBeenImportedEvent($extensionKey, $destinationAbsolutePath, $this));
575
            }
576
        }
577
    }
578
579
    /**
580
     * @param string $extensionSiteRelPath
581
     * @param Import|null $import
582
     */
583
    protected function importSiteConfiguration(string $extensionSiteRelPath, Import $import = null): void
584
    {
585
        $importRelFolder = $extensionSiteRelPath . 'Initialisation/Site';
586
        $importAbsFolder = Environment::getPublicPath() . '/' . $importRelFolder;
587
        $destinationFolder = Environment::getConfigPath() . '/sites';
588
589
        if (!is_dir($importAbsFolder)) {
590
            return;
591
        }
592
593
        $siteConfiguration = GeneralUtility::makeInstance(
594
            SiteConfiguration::class,
595
            $destinationFolder
596
        );
597
        $existingSites = $siteConfiguration->resolveAllExistingSites(false);
598
599
        GeneralUtility::mkdir($destinationFolder);
600
        $finder = GeneralUtility::makeInstance(Finder::class);
601
        $finder->directories()->in($importAbsFolder);
602
        if ($finder->hasResults()) {
603
            foreach ($finder as $siteConfigDirectory) {
604
                $siteIdentifier = $siteConfigDirectory->getBasename();
605
                if (isset($existingSites[$siteIdentifier])) {
606
                    $this->logger->warning(
607
                        sprintf(
608
                            'Skipped importing site configuration from %s due to existing site identifier %s',
609
                            $extensionSiteRelPath,
610
                            $siteIdentifier
611
                        )
612
                    );
613
                    continue;
614
                }
615
                $targetDir = $destinationFolder . '/' . $siteIdentifier;
616
                if (!$this->registry->get('siteConfigImport', $siteIdentifier) && !is_dir($targetDir)) {
617
                    GeneralUtility::mkdir($targetDir);
618
                    GeneralUtility::copyDirectory($siteConfigDirectory->getPathname(), $targetDir);
619
                    $this->registry->set('siteConfigImport', $siteIdentifier, 1);
620
                }
621
            }
622
        }
623
624
        /** @var Site[] $newSites */
625
        $newSites = array_diff_key($siteConfiguration->resolveAllExistingSites(false), $existingSites);
626
        $importedPages = $import->import_mapId['pages'] ?? null;
627
628
        foreach ($newSites as $newSite) {
629
            $exportedPageId = $newSite->getRootPageId();
630
            $importedPageId = $importedPages[$exportedPageId] ?? null;
631
            if ($importedPageId === null) {
632
                $this->logger->warning(
633
                    sprintf(
634
                        'Imported site configuration with identifier %s could not be mapped to imported page id',
635
                        $newSite->getIdentifier()
636
                    )
637
                );
638
                continue;
639
            }
640
            $configuration = $siteConfiguration->load($newSite->getIdentifier());
641
            $configuration['rootPageId'] = $importedPageId;
642
            $siteConfiguration->write($newSite->getIdentifier(), $configuration);
643
        }
644
    }
645
}
646