2 namespace TYPO3\CMS\Core\Package
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Core\Service\DependencyOrderingService
;
18 use TYPO3\CMS\Core\Utility\GeneralUtility
;
21 * This class takes care about dependencies between packages.
22 * It provides functionality to resolve dependencies and to determine
23 * the crucial loading order of the packages.
24 * @deprecated since TYPO3 v9.2, will be removed in TYPO3 v10.0
26 class DependencyResolver
29 * @var DependencyOrderingService
31 protected $dependencyOrderingService;
34 * @param DependencyOrderingService $dependencyOrderingService
36 public function injectDependencyOrderingService(DependencyOrderingService
$dependencyOrderingService)
38 $this->dependencyOrderingService
= $dependencyOrderingService;
42 * @param array $packageStatesConfiguration
43 * @return array Returns the packageStatesConfiguration sorted by dependencies
44 * @throws \UnexpectedValueException
46 public function sortPackageStatesConfigurationByDependency(array $packageStatesConfiguration)
48 trigger_error(self
::class . ' will be removed in TYPO3 v10.0.', E_USER_DEPRECATED
);
49 return $this->dependencyOrderingService
->calculateOrder($this->buildDependencyGraph($packageStatesConfiguration));
53 * Convert the package configuration into a dependency definition
55 * This converts "dependencies" and "suggestions" to "after" syntax for the usage in DependencyOrderingService
57 * @param array $packageStatesConfiguration
58 * @param array $packageKeys
60 * @throws \UnexpectedValueException
62 protected function convertConfigurationForGraph(array $packageStatesConfiguration, array $packageKeys)
65 foreach ($packageKeys as $packageKey) {
66 if (!isset($packageStatesConfiguration[$packageKey]['dependencies']) && !isset($packageStatesConfiguration[$packageKey]['suggestions'])) {
69 $dependencies[$packageKey] = [
72 if (isset($packageStatesConfiguration[$packageKey]['dependencies'])) {
73 foreach ($packageStatesConfiguration[$packageKey]['dependencies'] as $dependentPackageKey) {
74 if (!in_array($dependentPackageKey, $packageKeys, true)) {
75 throw new \
UnexpectedValueException(
76 'The package "' . $packageKey . '" depends on "'
77 . $dependentPackageKey . '" which is not present in the system.',
81 $dependencies[$packageKey]['after'][] = $dependentPackageKey;
84 if (isset($packageStatesConfiguration[$packageKey]['suggestions'])) {
85 foreach ($packageStatesConfiguration[$packageKey]['suggestions'] as $suggestedPackageKey) {
86 // skip suggestions on not existing packages
87 if (in_array($suggestedPackageKey, $packageKeys, true)) {
88 // Suggestions actually have never been meant to influence loading order.
89 // We misuse this currently, as there is no other way to influence the loading order
90 // for not-required packages (soft-dependency).
91 // When considering suggestions for the loading order, we might create a cyclic dependency
92 // if the suggested package already has a real dependency on this package, so the suggestion
93 // has do be dropped in this case and must *not* be taken into account for loading order evaluation.
94 $dependencies[$packageKey]['after-resilient'][] = $suggestedPackageKey;
103 * Adds all root packages of current dependency graph as dependency to all extensions
105 * This ensures that the framework extensions (aka sysext) are
106 * always loaded first, before any other external extension.
108 * @param array $packageStateConfiguration
109 * @param array $rootPackageKeys
112 protected function addDependencyToFrameworkToAllExtensions(array $packageStateConfiguration, array $rootPackageKeys)
114 $frameworkPackageKeys = $this->findFrameworkPackages($packageStateConfiguration);
115 $extensionPackageKeys = array_diff(array_keys($packageStateConfiguration), $frameworkPackageKeys);
116 foreach ($extensionPackageKeys as $packageKey) {
117 // Remove framework packages from list
118 $packageKeysWithoutFramework = array_diff(
119 $packageStateConfiguration[$packageKey]['dependencies'],
120 $frameworkPackageKeys
122 // The order of the array_merge is crucial here,
123 // we want the framework first
124 $packageStateConfiguration[$packageKey]['dependencies'] = array_merge(
126 $packageKeysWithoutFramework
129 return $packageStateConfiguration;
133 * Builds the dependency graph for all packages
135 * This method also introduces dependencies among the dependencies
136 * to ensure the loading order is exactly as specified in the list.
138 * @param array $packageStateConfiguration
141 protected function buildDependencyGraph(array $packageStateConfiguration)
143 $frameworkPackageKeys = $this->findFrameworkPackages($packageStateConfiguration);
144 $frameworkPackagesDependencyGraph = $this->dependencyOrderingService
->buildDependencyGraph($this->convertConfigurationForGraph($packageStateConfiguration, $frameworkPackageKeys));
145 $packageStateConfiguration = $this->addDependencyToFrameworkToAllExtensions($packageStateConfiguration, $this->dependencyOrderingService
->findRootIds($frameworkPackagesDependencyGraph));
147 $packageKeys = array_keys($packageStateConfiguration);
148 return $this->dependencyOrderingService
->buildDependencyGraph($this->convertConfigurationForGraph($packageStateConfiguration, $packageKeys));
152 * @param array $packageStateConfiguration
155 protected function findFrameworkPackages(array $packageStateConfiguration)
157 $frameworkPackageKeys = [];
158 $packageManager = GeneralUtility
::makeInstance(PackageManager
::class);
159 foreach ($packageStateConfiguration as $packageKey => $packageConfiguration) {
160 /** @var Package $package */
161 $package = $packageManager->getPackage($packageKey);
162 if ($package->getValueFromComposerManifest('type') === 'typo3-cms-framework') {
163 $frameworkPackageKeys[] = $packageKey;
167 return $frameworkPackageKeys;