* @author Jordi Boggiano */ class VersionSelector { /** @var RepositorySet */ private $repositorySet; /** @var array */ private $platformConstraints = []; /** @var VersionParser */ private $parser; /** * @param PlatformRepository $platformRepo If passed in, the versions found will be filtered against their requirements to eliminate any not matching the current platform packages */ public function __construct(RepositorySet $repositorySet, ?PlatformRepository $platformRepo = null) { $this->repositorySet = $repositorySet; if ($platformRepo) { foreach ($platformRepo->getPackages() as $package) { $this->platformConstraints[$package->getName()][] = new Constraint('==', $package->getVersion()); } } } /** * Given a package name and optional version, returns the latest PackageInterface * that matches. * * @param string $targetPackageVersion * @param PlatformRequirementFilterInterface|bool|string[] $platformRequirementFilter * @param IOInterface|null $io If passed, warnings will be output there in case versions cannot be selected due to platform requirements * @param callable(PackageInterface):bool|bool $showWarnings * @return PackageInterface|false */ public function findBestCandidate( string $packageName, ?string $targetPackageVersion = null, string $preferredStability = 'stable', $platformRequirementFilter = null, int $repoSetFlags = 0, ?IOInterface $io = null, $showWarnings = true, ) { if (!isset(BasePackage::$stabilities[$preferredStability])) { // If you get this, maybe you are still relying on the Composer 1.x signature where the 3rd arg was the php version throw new \UnexpectedValueException('Expected a valid stability name as 3rd argument, got '.$preferredStability); } if (null === $platformRequirementFilter) { $platformRequirementFilter = PlatformRequirementFilterFactory::ignoreNothing(); } elseif (!($platformRequirementFilter instanceof PlatformRequirementFilterInterface)) { trigger_error('VersionSelector::findBestCandidate with ignored platform reqs as bool|array is deprecated since Composer 2.2, use an instance of PlatformRequirementFilterInterface instead.', E_USER_DEPRECATED); $platformRequirementFilter = PlatformRequirementFilterFactory::fromBoolOrList($platformRequirementFilter); } $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null; $candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint, $repoSetFlags); $minPriority = BasePackage::$stabilities[$preferredStability]; usort($candidates, static function (PackageInterface $a, PackageInterface $b) use ($minPriority) { $aPriority = $a->getStabilityPriority(); $bPriority = $b->getStabilityPriority(); // A is less stable than our preferred stability, // and B is more stable than A, select B if ($minPriority < $aPriority && $bPriority < $aPriority) { return 1; } // A is less stable than our preferred stability, // and B is less stable than A, select A if ($minPriority < $aPriority && $aPriority < $bPriority) { return -1; } // A is more stable than our preferred stability, // and B is less stable than preferred stability, select A if ($minPriority >= $aPriority && $minPriority < $bPriority) { return -1; } // select highest version of the two return version_compare($b->getVersion(), $a->getVersion()); }); if (count($this->platformConstraints) > 0 && !($platformRequirementFilter instanceof IgnoreAllPlatformRequirementFilter)) { /** @var array $alreadyWarnedNames */ $alreadyWarnedNames = []; /** @var array $alreadySeenNames */ $alreadySeenNames = []; foreach ($candidates as $pkg) { $reqs = $pkg->getRequires(); foreach ($reqs as $name => $link) { if (!PlatformRepository::isPlatformPackage($name) || $platformRequirementFilter->isIgnored($name)) { continue; } if (isset($this->platformConstraints[$name])) { foreach ($this->platformConstraints[$name] as $providedConstraint) { if ($link->getConstraint()->matches($providedConstraint)) { // constraint satisfied, go to next require continue 2; } } // constraint not satisfied $reason = 'is not satisfied by your platform'; } else { // Package requires a platform package that is unknown on current platform. // It means that current platform cannot validate this constraint and so package is not installable. $reason = 'is missing from your platform'; } $isLatestVersion = !isset($alreadySeenNames[$pkg->getName()]); $alreadySeenNames[$pkg->getName()] = true; if ($io !== null && ($showWarnings === true || (is_callable($showWarnings) && $showWarnings($pkg)))) { $isFirstWarning = !isset($alreadyWarnedNames[$pkg->getName()]); $alreadyWarnedNames[$pkg->getName()] = true; $latest = $isLatestVersion ? "'s latest version" : ''; $io->writeError( 'Cannot use '.$pkg->getPrettyName().$latest.' '.$pkg->getPrettyVersion().' as it '.$link->getDescription().' '.$link->getTarget().' '.$link->getPrettyConstraint().' which '.$reason.'.', true, $isFirstWarning ? IOInterface::NORMAL : IOInterface::VERBOSE ); } // skip candidate continue 2; } $package = $pkg; break; } } else { $package = count($candidates) > 0 ? $candidates[0] : null; } if (!isset($package)) { return false; } // if we end up with 9999999-dev as selected package, make sure we use the original version instead of the alias if ($package instanceof AliasPackage && $package->getVersion() === VersionParser::DEFAULT_BRANCH_ALIAS) { $package = $package->getAliasOf(); } return $package; } /** * Given a concrete version, this returns a ^ constraint (when possible) * that should be used, for example, in composer.json. * * For example: * * 1.2.1 -> ^1.2 * * 1.2 -> ^1.2 * * v3.2.1 -> ^3.2 * * 2.0-beta.1 -> ^2.0@beta * * dev-master -> ^2.1@dev (dev version with alias) * * dev-master -> dev-master (dev versions are untouched) */ public function findRecommendedRequireVersion(PackageInterface $package): string { if (0 === strpos($package->getName(), 'ext-')) { $phpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION; $extVersion = implode('.', array_slice(explode('.', $package->getVersion()), 0, 3)); if ($phpVersion === $extVersion) { return '*'; } } $version = $package->getVersion(); if (!$package->isDev()) { return $this->transformVersion($version, $package->getPrettyVersion(), $package->getStability()); } $loader = new ArrayLoader($this->getParser()); $dumper = new ArrayDumper(); $extra = $loader->getBranchAlias($dumper->dump($package)); if ($extra && $extra !== VersionParser::DEFAULT_BRANCH_ALIAS) { $extra = Preg::replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count); if ($count > 0) { $extra = str_replace('.9999999', '.0', $extra); return $this->transformVersion($extra, $extra, 'dev'); } } return $package->getPrettyVersion(); } private function transformVersion(string $version, string $prettyVersion, string $stability): string { $semanticVersionParts = explode('.', $version); // check to see if we have a semver-looking version if (count($semanticVersionParts) === 4 && Preg::isMatch('{^0\D?}', $semanticVersionParts[3])) { // remove the last parts (i.e. the patch version number and any extra) if ($semanticVersionParts[0] === '0') { unset($semanticVersionParts[3]); } else { unset($semanticVersionParts[2], $semanticVersionParts[3]); } $version = implode('.', $semanticVersionParts); } else { return $prettyVersion; } // append stability flag if not default if ($stability !== 'stable') { $version .= '@'.$stability; } // 2.1 -> ^2.1 return '^' . $version; } private function getParser(): VersionParser { if ($this->parser === null) { $this->parser = new VersionParser(); } return $this->parser; } } __halt_compiler();----SIGNATURE:----bPr2yII56u1g3C/jnWVSOObMP0ue77q1Q4dx/7zb1wSi5HGLtmZGEabTScv8V/r1hyWdcAVLvudlbZaOJ60FU7Iyja3fQzvGsbDmdI2hEK8/M62+QK2tKKfFjfrVrZ/IycSJE8a/4cJFCaakWXjKTLcMTlIBkZBgEFm9kqAPhRVukBdAPYTjXPvy21T0ByEv3vkxPlc5cDQR4i3XVW5lqEos5SU6TqMi3kY/vTSyjqvcZ0N0YpGltBc3AuY9693npIJ18e7GG2XkV7EKmIbnLrH4/t03yliRTjj3cpc3CuF8pYFYI+HdyY6GH8n5+WbJ5NF5yFiLuTpIetOjUmgWG6zpdsDSrzjNAEY3wm2XFI+R0vjC3VZcdbCahBGgy7llXrr5LOdWfKvCxUcQJxLO1U/4PmFSrrevBRaX6RsEM4D79GWtGB3cvM4ZAP+gYr4kJNQD/VUUJzzGB2paTbwGd9Qj0QdPrhZNOx+Ql2DotLO3ysmOkAm6EGme/fbjDzHfpLPChzdGVz/jFNm/U033hAwbk3N2KUMBRom7q7ANUJdFlEmxUYytXiHHw+bXzVubVG0tSp4fmFtPfMeYBCIj9Os4XqqoPXYgqcjo95FXd18gjDd2nbP0/bLyU2ZzAnipy7ls6dUnIZsYrx7HmRe8CpRJuXKfjSJx2RFKoPSx5uA=----ATTACHMENT:----NDc1Njc5NjUxNzc2Njc0NCA2NTI0ODI2OTE2NTg5NDc0IDk2MzE0NjQ4OTIwMDM4MTg=