PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | vendor/composer/InstalledVersions.php +60 -14 19.0 → trunk View file →
@@ -20,18 +20,31 @@
20 20 *
21 21 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22 22 *
23 23 * To require its presence, you can require `composer-runtime-api ^2.0`
24 + *
25 + * @final
24 26 */
25 27 class InstalledVersions
26 28 {
27 29 /**
30 + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
31 + * @internal
32 + */
33 + private static $selfDir = null;
34 +
35 + /**
28 36 * @var mixed[]|null
29 - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
37 + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
30 38 */
31 39 private static $installed;
32 40
33 41 /**
42 + * @var bool
43 + */
44 + private static $installedIsLocalDir;
45 +
46 + /**
34 47 * @var bool|null
35 48 */
36 49 private static $canGetVendors;
37 50
@@ -36,9 +49,9 @@
36 49 private static $canGetVendors;
37 50
38 51 /**
39 52 * @var array[]
40 - * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
53 + * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
41 54 */
42 55 private static $installedByVendor = array();
43 56
44 57 /**
@@ -95,9 +108,9 @@
95 108 public static function isInstalled($packageName, $includeDevRequirements = true)
96 109 {
97 110 foreach (self::getInstalled() as $installed) {
98 111 if (isset($installed['versions'][$packageName])) {
99 - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
112 + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
100 113 }
101 114 }
102 115
103 116 return false;
@@ -116,9 +129,9 @@
116 129 * @return bool
117 130 */
118 131 public static function satisfies(VersionParser $parser, $packageName, $constraint)
119 132 {
120 - $constraint = $parser->parseConstraints($constraint);
133 + $constraint = $parser->parseConstraints((string) $constraint);
121 134 $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
122 135
123 136 return $provided->matches($constraint);
124 137 }
@@ -240,9 +253,9 @@
240 253 }
241 254
242 255 /**
243 256 * @return array
244 - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
257 + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
245 258 */
246 259 public static function getRootPackage()
247 260 {
248 261 $installed = self::getInstalled();
@@ -254,9 +267,9 @@
254 267 * Returns the raw installed.php data for custom implementations
255 268 *
256 269 * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
257 270 * @return array[]
258 - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
271 + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
259 272 */
260 273 public static function getRawData()
261 274 {
262 275 @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
@@ -277,9 +290,9 @@
277 290 /**
278 291 * Returns the raw data of all installed.php which are currently loaded for custom implementations
279 292 *
280 293 * @return array[]
281 - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
294 + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
282 295 */
283 296 public static function getAllRawData()
284 297 {
285 298 return self::getInstalled();
@@ -300,19 +313,37 @@
300 313 *
301 314 * @param array[] $data A vendor/composer/installed.php data set
302 315 * @return void
303 316 *
304 - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
317 + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
305 318 */
306 319 public static function reload($data)
307 320 {
308 321 self::$installed = $data;
309 322 self::$installedByVendor = array();
323 +
324 + // when using reload, we disable the duplicate protection to ensure that self::$installed data is
325 + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
326 + // so we have to assume it does not, and that may result in duplicate data being returned when listing
327 + // all installed packages for example
328 + self::$installedIsLocalDir = false;
310 329 }
311 330
312 331 /**
332 + * @return string
333 + */
334 + private static function getSelfDir()
335 + {
336 + if (self::$selfDir === null) {
337 + self::$selfDir = strtr(__DIR__, '\\', '/');
338 + }
339 +
340 + return self::$selfDir;
341 + }
342 +
343 + /**
313 344 * @return array[]
314 - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
345 + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
315 346 */
316 347 private static function getInstalled()
317 348 {
318 349 if (null === self::$canGetVendors) {
@@ -319,19 +350,29 @@
319 350 self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
320 351 }
321 352
322 353 $installed = array();
354 + $copiedLocalDir = false;
323 355
324 356 if (self::$canGetVendors) {
357 + $selfDir = self::getSelfDir();
325 358 foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
359 + $vendorDir = strtr($vendorDir, '\\', '/');
326 360 if (isset(self::$installedByVendor[$vendorDir])) {
327 361 $installed[] = self::$installedByVendor[$vendorDir];
328 362 } elseif (is_file($vendorDir.'/composer/installed.php')) {
329 - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
330 - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
331 - self::$installed = $installed[count($installed) - 1];
363 + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
364 + $required = require $vendorDir.'/composer/installed.php';
365 + self::$installedByVendor[$vendorDir] = $required;
366 + $installed[] = $required;
367 + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
368 + self::$installed = $required;
369 + self::$installedIsLocalDir = true;
332 370 }
333 371 }
372 + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
373 + $copiedLocalDir = true;
374 + }
334 375 }
335 376 }
336 377
337 378 if (null === self::$installed) {
@@ -337,14 +378,19 @@
337 378 if (null === self::$installed) {
338 379 // only require the installed.php file if this file is loaded from its dumped location,
339 380 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
340 381 if (substr(__DIR__, -8, 1) !== 'C') {
341 - self::$installed = require __DIR__ . '/installed.php';
382 + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
383 + $required = require __DIR__ . '/installed.php';
384 + self::$installed = $required;
342 385 } else {
343 386 self::$installed = array();
344 387 }
345 388 }
346 - $installed[] = self::$installed;
389 +
390 + if (self::$installed !== array() && !$copiedLocalDir) {
391 + $installed[] = self::$installed;
392 + }
347 393
348 394 return $installed;
349 395 }
350 396 }