‪TYPO3CMS  11.5
DependencyUtility.php
Go to the documentation of this file.
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 
17 
29 
35 {
39  protected ‪$extensionRepository;
40 
44  protected ‪$listUtility;
45 
49  protected ‪$emConfUtility;
50 
55 
59  protected ‪$availableExtensions = [];
60 
64  protected ‪$dependencyErrors = [];
65 
69  protected ‪$skipDependencyCheck = false;
70 
75  {
76  $this->extensionRepository = ‪$extensionRepository;
77  }
78 
83  {
84  $this->listUtility = ‪$listUtility;
85  }
86 
90  public function ‪injectEmConfUtility(EmConfUtility ‪$emConfUtility)
91  {
92  $this->emConfUtility = ‪$emConfUtility;
93  }
94 
99  {
100  $this->managementService = ‪$managementService;
101  }
102 
107  protected function ‪setAvailableExtensions()
108  {
109  $this->availableExtensions = $this->listUtility->getAvailableExtensions();
110  }
111 
116  {
117  $this->skipDependencyCheck = ‪$skipDependencyCheck;
118  }
119 
125  public function ‪checkDependencies(‪Extension $extension)
126  {
127  $this->dependencyErrors = [];
128  $dependencies = $extension->‪getDependencies();
129  foreach ($dependencies as $dependency) {
131  $identifier = $dependency->getIdentifier();
132  try {
133  if (in_array($identifier, ‪Dependency::$specialDependencies)) {
134  if ($this->skipDependencyCheck) {
135  continue;
136  }
137  if ($identifier === 'typo3') {
139  }
140  if ($identifier === 'php') {
141  $this->‪checkPhpDependency($dependency, PHP_VERSION);
142  }
143  } elseif ($dependency->getType() === 'depends') {
144  $this->‪checkExtensionDependency($dependency);
145  }
146  } catch (‪UnresolvedDependencyException $e) {
147  if (in_array($identifier, ‪Dependency::$specialDependencies)) {
148  $extensionKey = $extension->‪getExtensionKey();
149  } else {
150  $extensionKey = $identifier;
151  }
152  if (!isset($this->dependencyErrors[$extensionKey])) {
153  $this->dependencyErrors[$extensionKey] = [];
154  }
155  $this->dependencyErrors[$extensionKey][] = [
156  'code' => $e->getCode(),
157  'message' => $e->getMessage(),
158  ];
159  }
160  }
161  }
162 
168  public function ‪hasDependencyErrors()
169  {
170  return !empty($this->dependencyErrors);
171  }
172 
178  public function ‪getDependencyErrors(): array
179  {
181  }
182 
191  protected function ‪checkTypo3Dependency(Dependency $dependency, string $version): bool
192  {
193  if ($dependency->getIdentifier() === 'typo3') {
194  if (!($dependency->getLowestVersion() === '') && version_compare($version, $dependency->getLowestVersion()) === -1) {
195  throw new Exception\UnresolvedTypo3DependencyException(
196  'Your TYPO3 version is lower than this extension requires. It requires TYPO3 versions ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion(),
197  1399144499
198  );
199  }
200  if (!($dependency->getHighestVersion() === '') && version_compare($dependency->getHighestVersion(), $version) === -1) {
201  throw new Exception\UnresolvedTypo3DependencyException(
202  'Your TYPO3 version is higher than this extension requires. It requires TYPO3 versions ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion(),
203  1399144521
204  );
205  }
206  } else {
207  throw new Exception\UnresolvedTypo3DependencyException(
208  'checkTypo3Dependency can only check TYPO3 dependencies. Found dependency with identifier "' . $dependency->getIdentifier() . '"',
209  1399144551
210  );
211  }
212  return true;
213  }
214 
223  protected function ‪checkPhpDependency(Dependency $dependency, string $version): bool
224  {
225  if ($dependency->getIdentifier() === 'php') {
226  if (!($dependency->getLowestVersion() === '') && version_compare($version, $dependency->getLowestVersion()) === -1) {
227  throw new Exception\UnresolvedPhpDependencyException(
228  'Your PHP version is lower than necessary. You need at least PHP version ' . $dependency->getLowestVersion(),
229  1377977857
230  );
231  }
232  if (!($dependency->getHighestVersion() === '') && version_compare($dependency->getHighestVersion(), $version) === -1) {
233  throw new Exception\UnresolvedPhpDependencyException(
234  'Your PHP version is higher than allowed. You can use PHP versions ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion(),
235  1377977856
236  );
237  }
238  } else {
239  throw new Exception\UnresolvedPhpDependencyException(
240  'checkPhpDependency can only check PHP dependencies. Found dependency with identifier "' . $dependency->getIdentifier() . '"',
241  1377977858
242  );
243  }
244  return true;
245  }
246 
259  protected function ‪checkExtensionDependency(Dependency $dependency)
260  {
261  $extensionKey = $dependency->getIdentifier();
262  $extensionIsLoaded = $this->‪isDependentExtensionLoaded($extensionKey);
263  if ($extensionIsLoaded === true) {
264  if ($this->skipDependencyCheck || $this->‪isLoadedVersionCompatible($dependency)) {
265  return true;
266  }
267  $extension = $this->listUtility->getExtension($extensionKey);
268  $loadedVersion = $extension->getPackageMetaData()->getVersion();
269  if (version_compare($loadedVersion, $dependency->getHighestVersion()) === -1) {
270  try {
271  $this->‪downloadExtensionFromRemote($extensionKey, $dependency);
272  } catch (UnresolvedDependencyException $e) {
273  throw new MissingVersionDependencyException(
274  'The extension ' . $extensionKey . ' is installed in version ' . $loadedVersion
275  . ' but needed in version ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion() . ' and could not be fetched from TER',
276  1396302624
277  );
278  }
279  } else {
280  throw new MissingVersionDependencyException(
281  'The extension ' . $extensionKey . ' is installed in version ' . $loadedVersion .
282  ' but needed in version ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion(),
283  1430561927
284  );
285  }
286  } else {
287  $extensionIsAvailable = $this->‪isDependentExtensionAvailable($extensionKey);
288  if ($extensionIsAvailable === true) {
289  $isAvailableVersionCompatible = $this->‪isAvailableVersionCompatible($dependency);
290  if ($isAvailableVersionCompatible) {
291  $unresolvedDependencyErrors = ‪$this->dependencyErrors;
292  $this->managementService->markExtensionForInstallation($extensionKey);
293  $this->dependencyErrors = array_merge($unresolvedDependencyErrors, $this->dependencyErrors);
294  } else {
295  $extension = $this->listUtility->getExtension($extensionKey);
296  $availableVersion = $extension->getPackageMetaData()->getVersion();
297  if (version_compare($availableVersion, $dependency->getHighestVersion()) === -1) {
298  try {
299  $this->‪downloadExtensionFromRemote($extensionKey, $dependency);
300  } catch (MissingExtensionDependencyException $e) {
301  if (!$this->skipDependencyCheck) {
302  throw new MissingVersionDependencyException(
303  'The extension ' . $extensionKey . ' is available in version ' . $availableVersion
304  . ' but is needed in version ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion() . ' and could not be fetched from TER',
305  1430560390
306  );
307  }
308  }
309  } else {
310  if (!$this->skipDependencyCheck) {
311  throw new MissingVersionDependencyException(
312  'The extension ' . $extensionKey . ' is available in version ' . $availableVersion
313  . ' but is needed in version ' . $dependency->getLowestVersion() . ' - ' . $dependency->getHighestVersion(),
314  1430562374
315  );
316  }
317  // Dependency check is skipped and the local version has to be installed
318  $this->managementService->markExtensionForInstallation($extensionKey);
319  }
320  }
321  } else {
322  $unresolvedDependencyErrors = ‪$this->dependencyErrors;
323  $this->‪downloadExtensionFromRemote($extensionKey, $dependency);
324  $this->dependencyErrors = array_merge($unresolvedDependencyErrors, $this->dependencyErrors);
325  }
326  }
327 
328  return false;
329  }
330 
338  protected function ‪downloadExtensionFromRemote(string $extensionKey, Dependency $dependency)
339  {
340  if (!$this->‪isExtensionDownloadableFromRemote($extensionKey)) {
341  if (!$this->skipDependencyCheck) {
342  if ($this->extensionRepository->countAll() > 0) {
343  throw new MissingExtensionDependencyException(
344  'The extension ' . $extensionKey . ' is not available from TER.',
345  1399161266
346  );
347  }
348  throw new MissingExtensionDependencyException(
349  'The extension ' . $extensionKey . ' could not be checked. Please update your Extension-List from TYPO3 Extension Repository (TER).',
350  1430580308
351  );
352  }
353  return;
354  }
355 
356  $isDownloadableVersionCompatible = $this->‪isDownloadableVersionCompatible($dependency);
357  if (!$isDownloadableVersionCompatible) {
358  if (!$this->skipDependencyCheck) {
359  throw new MissingVersionDependencyException(
360  'No compatible version found for extension ' . $extensionKey,
361  1399161284
362  );
363  }
364  return;
365  }
366 
367  $latestCompatibleExtensionByDependency = $this->‪getLatestCompatibleExtensionByDependency($dependency);
368  if (!$latestCompatibleExtensionByDependency instanceof Extension) {
369  if (!$this->skipDependencyCheck) {
370  throw new MissingExtensionDependencyException(
371  'Could not resolve dependency for "' . $dependency->getIdentifier() . '"',
372  1399161302
373  );
374  }
375  return;
376  }
377 
378  if ($this->‪isDependentExtensionLoaded($extensionKey)) {
379  $this->managementService->markExtensionForUpdate($latestCompatibleExtensionByDependency);
380  } else {
381  $this->managementService->markExtensionForDownload($latestCompatibleExtensionByDependency);
382  }
383  }
384 
389  protected function ‪isDependentExtensionLoaded($extensionKey)
390  {
392  }
393 
398  protected function ‪isLoadedVersionCompatible(‪Dependency $dependency): bool
399  {
400  $extensionVersion = ‪ExtensionManagementUtility::getExtensionVersion($dependency->‪getIdentifier());
401  return $dependency->‪isVersionCompatible($extensionVersion);
402  }
403 
411  protected function ‪isDependentExtensionAvailable(string $extensionKey): bool
412  {
413  $this->‪setAvailableExtensions();
414  return array_key_exists($extensionKey, $this->availableExtensions);
415  }
416 
423  protected function ‪isAvailableVersionCompatible(‪Dependency $dependency): bool
424  {
425  $this->‪setAvailableExtensions();
426  $extensionData = $this->emConfUtility->includeEmConf(
427  $dependency->‪getIdentifier(),
428  $this->availableExtensions[$dependency->‪getIdentifier()]['packagePath'] ?? ''
429  );
430  return $dependency->‪isVersionCompatible($extensionData['version']);
431  }
432 
439  protected function ‪isExtensionDownloadableFromRemote(string $extensionKey): bool
440  {
441  return $this->extensionRepository->countByExtensionKey($extensionKey) > 0;
442  }
443 
450  protected function ‪isDownloadableVersionCompatible(‪Dependency $dependency): bool
451  {
452  $count = $this->extensionRepository->countByVersionRangeAndExtensionKey(
453  $dependency->‪getIdentifier(),
454  $dependency->‪getLowestVersionAsInteger(),
455  $dependency->‪getHighestVersionAsInteger()
456  );
457  return !empty($count);
458  }
459 
467  protected function ‪getCompatibleExtension(iterable $extensions): ?‪Extension
468  {
469  foreach ($extensions as $extension) {
471  $this->‪checkDependencies($extension);
472  $extensionKey = $extension->getExtensionKey();
473 
474  if (isset($this->dependencyErrors[$extensionKey])) {
475  // reset dependencyErrors and continue with next version
476  unset($this->dependencyErrors[$extensionKey]);
477  continue;
478  }
479 
480  return $extension;
481  }
482 
483  return null;
484  }
485 
493  protected function ‪getLatestCompatibleExtensionByDependency(Dependency $dependency): ?Extension
494  {
495  $compatibleDataSets = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
496  $dependency->getIdentifier(),
497  $dependency->getLowestVersionAsInteger(),
498  $dependency->getHighestVersionAsInteger()
499  );
500  return $this->‪getCompatibleExtension($compatibleDataSets);
501  }
502 }
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\getHighestVersion
‪getHighestVersion()
Definition: Dependency.php:99
‪TYPO3\CMS\Core\Utility\VersionNumberUtility
Definition: VersionNumberUtility.php:24
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency
Definition: Dependency.php:28
‪TYPO3\CMS\Core\Utility\VersionNumberUtility\getNumericTypo3Version
‪static string getNumericTypo3Version()
Definition: VersionNumberUtility.php:51
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\getDependencyErrors
‪array getDependencyErrors()
Definition: DependencyUtility.php:171
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\injectListUtility
‪injectListUtility(ListUtility $listUtility)
Definition: DependencyUtility.php:75
‪TYPO3\CMS\Extensionmanager\Utility
Definition: DependencyUtility.php:16
‪TYPO3\CMS\Extensionmanager\Domain\Model\Extension
Definition: Extension.php:28
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\getLowestVersion
‪getLowestVersion()
Definition: Dependency.php:109
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\injectEmConfUtility
‪injectEmConfUtility(EmConfUtility $emConfUtility)
Definition: DependencyUtility.php:83
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$extensionRepository
‪ExtensionRepository $extensionRepository
Definition: DependencyUtility.php:38
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\getCompatibleExtension
‪Extension null getCompatibleExtension(iterable $extensions)
Definition: DependencyUtility.php:460
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\checkExtensionDependency
‪bool checkExtensionDependency(Dependency $dependency)
Definition: DependencyUtility.php:252
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\checkPhpDependency
‪bool checkPhpDependency(Dependency $dependency, string $version)
Definition: DependencyUtility.php:216
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$availableExtensions
‪array $availableExtensions
Definition: DependencyUtility.php:54
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\getHighestVersionAsInteger
‪getHighestVersionAsInteger()
Definition: Dependency.php:146
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isDependentExtensionAvailable
‪bool isDependentExtensionAvailable(string $extensionKey)
Definition: DependencyUtility.php:404
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$emConfUtility
‪EmConfUtility $emConfUtility
Definition: DependencyUtility.php:46
‪TYPO3\CMS\Extensionmanager\Exception
Definition: ExtensionManagerException.php:16
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$managementService
‪ExtensionManagementService $managementService
Definition: DependencyUtility.php:50
‪TYPO3\CMS\Extensionmanager\Exception\MissingVersionDependencyException
Definition: MissingVersionDependencyException.php:21
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\hasDependencyErrors
‪bool hasDependencyErrors()
Definition: DependencyUtility.php:161
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isDownloadableVersionCompatible
‪bool isDownloadableVersionCompatible(Dependency $dependency)
Definition: DependencyUtility.php:443
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isDependentExtensionLoaded
‪bool isDependentExtensionLoaded($extensionKey)
Definition: DependencyUtility.php:382
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\getIdentifier
‪getIdentifier()
Definition: Dependency.php:104
‪TYPO3\CMS\Extensionmanager\Utility\ListUtility
Definition: ListUtility.php:40
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\setSkipDependencyCheck
‪setSkipDependencyCheck($skipDependencyCheck)
Definition: DependencyUtility.php:108
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\injectManagementService
‪injectManagementService(ExtensionManagementService $managementService)
Definition: DependencyUtility.php:91
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\checkTypo3Dependency
‪bool checkTypo3Dependency(Dependency $dependency, string $version)
Definition: DependencyUtility.php:184
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\injectExtensionRepository
‪injectExtensionRepository(ExtensionRepository $extensionRepository)
Definition: DependencyUtility.php:67
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\getLatestCompatibleExtensionByDependency
‪Extension null getLatestCompatibleExtensionByDependency(Dependency $dependency)
Definition: DependencyUtility.php:486
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isAvailableVersionCompatible
‪bool isAvailableVersionCompatible(Dependency $dependency)
Definition: DependencyUtility.php:416
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\getExtensionVersion
‪static string getExtensionVersion($key)
Definition: ExtensionManagementUtility.php:172
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$listUtility
‪ListUtility $listUtility
Definition: DependencyUtility.php:42
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
Definition: DependencyUtility.php:35
‪TYPO3\CMS\Extensionmanager\Exception\MissingExtensionDependencyException
Definition: MissingExtensionDependencyException.php:21
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\checkDependencies
‪checkDependencies(Extension $extension)
Definition: DependencyUtility.php:118
‪TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
Definition: ExtensionRepository.php:34
‪TYPO3\CMS\Extensionmanager\Domain\Model\Extension\getDependencies
‪SplObjectStorage< Dependency > getDependencies()
Definition: Extension.php:508
‪TYPO3\CMS\Extensionmanager\Domain\Model\Extension\getExtensionKey
‪string getExtensionKey()
Definition: Extension.php:269
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\setAvailableExtensions
‪setAvailableExtensions()
Definition: DependencyUtility.php:100
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isLoadedVersionCompatible
‪bool isLoadedVersionCompatible(Dependency $dependency)
Definition: DependencyUtility.php:391
‪TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService
Definition: ExtensionManagementService.php:36
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\isExtensionDownloadableFromRemote
‪bool isExtensionDownloadableFromRemote(string $extensionKey)
Definition: DependencyUtility.php:432
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\$specialDependencies
‪static array $specialDependencies
Definition: Dependency.php:55
‪TYPO3\CMS\Core\SingletonInterface
Definition: SingletonInterface.php:22
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\isVersionCompatible
‪bool isVersionCompatible(string $version)
Definition: Dependency.php:127
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$dependencyErrors
‪array $dependencyErrors
Definition: DependencyUtility.php:58
‪TYPO3\CMS\Extensionmanager\Domain\Model\Dependency\getLowestVersionAsInteger
‪getLowestVersionAsInteger()
Definition: Dependency.php:138
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\$skipDependencyCheck
‪bool $skipDependencyCheck
Definition: DependencyUtility.php:62
‪TYPO3\CMS\Extensionmanager\Utility\DependencyUtility\downloadExtensionFromRemote
‪downloadExtensionFromRemote(string $extensionKey, Dependency $dependency)
Definition: DependencyUtility.php:331
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static bool isLoaded($key)
Definition: ExtensionManagementUtility.php:114
‪TYPO3\CMS\Extensionmanager\Exception\UnresolvedDependencyException
Definition: UnresolvedDependencyException.php:21