* * @see RepositoryUtils for ways to work with single repos */ class RepositorySet { /** Packages are returned even though their stability does not match the required stability */ public const ALLOW_UNACCEPTABLE_STABILITIES = 1; /** Packages will be looked up in all repositories, even after they have been found in a higher prio one */ public const ALLOW_SHADOWED_REPOSITORIES = 2; /** * @var array[] * @phpstan-var array> */ private $rootAliases; /** * @var string[] * @phpstan-var array */ private $rootReferences; /** @var RepositoryInterface[] */ private $repositories = []; /** * @var int[] array of stability => BasePackage::STABILITY_* value * @phpstan-var array */ private $acceptableStabilities; /** * @var int[] array of package name => BasePackage::STABILITY_* value * @phpstan-var array */ private $stabilityFlags; /** * @var ConstraintInterface[] * @phpstan-var array */ private $rootRequires; /** @var array */ private $temporaryConstraints; /** @var bool */ private $locked = false; /** @var bool */ private $allowInstalledRepositories = false; /** * In most cases if you are looking to use this class as a way to find packages from repositories * passing minimumStability is all you need to worry about. The rest is for advanced pool creation including * aliases, pinned references and other special cases. * * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array $stabilityFlags * @param array[] $rootAliases * @phpstan-param list $rootAliases * @param string[] $rootReferences an array of package name => source reference * @phpstan-param array $rootReferences * @param ConstraintInterface[] $rootRequires an array of package name => constraint from the root package * @phpstan-param array $rootRequires * @param array $temporaryConstraints Runtime temporary constraints that will be used to filter packages */ public function __construct( string $minimumStability = 'stable', array $stabilityFlags = [], array $rootAliases = [], array $rootReferences = [], array $rootRequires = [], array $temporaryConstraints = [], ) { $this->rootAliases = self::getRootAliasesPerPackage($rootAliases); $this->rootReferences = $rootReferences; $this->acceptableStabilities = []; foreach (BasePackage::$stabilities as $stability => $value) { if ($value <= BasePackage::$stabilities[$minimumStability]) { $this->acceptableStabilities[$stability] = $value; } } $this->stabilityFlags = $stabilityFlags; $this->rootRequires = $rootRequires; foreach ($rootRequires as $name => $constraint) { if (PlatformRepository::isPlatformPackage($name)) { unset($this->rootRequires[$name]); } } $this->temporaryConstraints = $temporaryConstraints; } public function allowInstalledRepositories(bool $allow = true): void { $this->allowInstalledRepositories = $allow; } /** * @return ConstraintInterface[] an array of package name => constraint from the root package, platform requirements excluded * @phpstan-return array */ public function getRootRequires(): array { return $this->rootRequires; } /** * @return array Runtime temporary constraints that will be used to filter packages */ public function getTemporaryConstraints(): array { return $this->temporaryConstraints; } /** * Adds a repository to this repository set * * The first repos added have a higher priority. As soon as a package is found in any * repository the search for that package ends, and following repos will not be consulted. * * @param RepositoryInterface $repo A package repository */ public function addRepository(RepositoryInterface $repo): void { if ($this->locked) { throw new \RuntimeException("Pool has already been created from this repository set, it cannot be modified anymore."); } if ($repo instanceof CompositeRepository) { $repos = $repo->getRepositories(); } else { $repos = [$repo]; } foreach ($repos as $repo) { $this->repositories[] = $repo; } } /** * Find packages providing or matching a name and optionally meeting a constraint in all repositories * * Returned in the order of repositories, matching priority * * @param int $flags any of the ALLOW_* constants from this class to tweak what is returned * @return BasePackage[] */ public function findPackages(string $name, ?ConstraintInterface $constraint = null, int $flags = 0): array { $ignoreStability = ($flags & self::ALLOW_UNACCEPTABLE_STABILITIES) !== 0; $loadFromAllRepos = ($flags & self::ALLOW_SHADOWED_REPOSITORIES) !== 0; $packages = []; if ($loadFromAllRepos) { foreach ($this->repositories as $repository) { $packages[] = $repository->findPackages($name, $constraint) ?: []; } } else { foreach ($this->repositories as $repository) { $result = $repository->loadPackages([$name => $constraint], $ignoreStability ? BasePackage::$stabilities : $this->acceptableStabilities, $ignoreStability ? [] : $this->stabilityFlags); $packages[] = $result['packages']; foreach ($result['namesFound'] as $nameFound) { // avoid loading the same package again from other repositories once it has been found if ($name === $nameFound) { break 2; } } } } $candidates = $packages ? array_merge(...$packages) : []; // when using loadPackages above (!$loadFromAllRepos) the repos already filter for stability so no need to do it again if ($ignoreStability || !$loadFromAllRepos) { return $candidates; } $result = []; foreach ($candidates as $candidate) { if ($this->isPackageAcceptable($candidate->getNames(), $candidate->getStability())) { $result[] = $candidate; } } return $result; } /** * @param string[] $packageNames * @return ($allowPartialAdvisories is true ? array> : array>) */ public function getSecurityAdvisories(array $packageNames, bool $allowPartialAdvisories = false): array { $map = []; foreach ($packageNames as $name) { $map[$name] = new MatchAllConstraint(); } return $this->getSecurityAdvisoriesForConstraints($map, $allowPartialAdvisories); } /** * @param PackageInterface[] $packages * @return ($allowPartialAdvisories is true ? array> : array>) */ public function getMatchingSecurityAdvisories(array $packages, bool $allowPartialAdvisories = false): array { $map = []; foreach ($packages as $package) { $map[$package->getName()] = new Constraint('=', $package->getVersion()); } return $this->getSecurityAdvisoriesForConstraints($map, $allowPartialAdvisories); } /** * @param array $packageConstraintMap * @return ($allowPartialAdvisories is true ? array> : array>) */ private function getSecurityAdvisoriesForConstraints(array $packageConstraintMap, bool $allowPartialAdvisories): array { $advisories = []; foreach ($this->repositories as $repository) { if (!$repository instanceof AdvisoryProviderInterface || !$repository->hasSecurityAdvisories()) { continue; } $result = $repository->getSecurityAdvisories($packageConstraintMap, $allowPartialAdvisories); foreach ($result['namesFound'] as $nameFound) { unset($packageConstraintMap[$nameFound]); } $advisories = array_merge($advisories, $result['advisories']); } return $advisories; } /** * @return array[] an array with the provider name as key and value of array('name' => '...', 'description' => '...', 'type' => '...') * @phpstan-return array */ public function getProviders(string $packageName): array { $providers = []; foreach ($this->repositories as $repository) { if ($repoProviders = $repository->getProviders($packageName)) { $providers = array_merge($providers, $repoProviders); } } return $providers; } /** * Check for each given package name whether it would be accepted by this RepositorySet in the given $stability * * @param string[] $names * @param string $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' */ public function isPackageAcceptable(array $names, string $stability): bool { return StabilityFilter::isPackageAcceptable($this->acceptableStabilities, $this->stabilityFlags, $names, $stability); } /** * Create a pool for dependency resolution from the packages in this repository set. */ public function createPool( Request $request, IOInterface $io, ?EventDispatcher $eventDispatcher = null, ?PoolOptimizer $poolOptimizer = null, ): Pool { $poolBuilder = new PoolBuilder($this->acceptableStabilities, $this->stabilityFlags, $this->rootAliases, $this->rootReferences, $io, $eventDispatcher, $poolOptimizer, $this->temporaryConstraints); foreach ($this->repositories as $repo) { if (($repo instanceof InstalledRepositoryInterface || $repo instanceof InstalledRepository) && !$this->allowInstalledRepositories) { throw new \LogicException('The pool can not accept packages from an installed repository'); } } $this->locked = true; return $poolBuilder->buildPool($this->repositories, $request); } /** * Create a pool for dependency resolution from the packages in this repository set. */ public function createPoolWithAllPackages(): Pool { foreach ($this->repositories as $repo) { if (($repo instanceof InstalledRepositoryInterface || $repo instanceof InstalledRepository) && !$this->allowInstalledRepositories) { throw new \LogicException('The pool can not accept packages from an installed repository'); } } $this->locked = true; $packages = []; foreach ($this->repositories as $repository) { foreach ($repository->getPackages() as $package) { $packages[] = $package; if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) { $alias = $this->rootAliases[$package->getName()][$package->getVersion()]; while ($package instanceof AliasPackage) { $package = $package->getAliasOf(); } if ($package instanceof CompletePackage) { $aliasPackage = new CompleteAliasPackage($package, $alias['alias_normalized'], $alias['alias']); } else { $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']); } $aliasPackage->setRootPackageAlias(true); $packages[] = $aliasPackage; } } } return new Pool($packages); } public function createPoolForPackage(string $packageName, ?LockArrayRepository $lockedRepo = null): Pool { return $this->createPoolForPackages([$packageName], $lockedRepo); } /** * @param string[] $packageNames */ public function createPoolForPackages(array $packageNames, ?LockArrayRepository $lockedRepo = null): Pool { $request = new Request($lockedRepo); foreach ($packageNames as $packageName) { if (PlatformRepository::isPlatformPackage($packageName)) { throw new \LogicException('createPoolForPackage(s) can not be used for platform packages, as they are never loaded by the PoolBuilder which expects them to be fixed. Use createPoolWithAllPackages or pass in a proper request with the platform packages you need fixed in it.'); } $request->requireName($packageName); } return $this->createPool($request, new NullIO()); } /** * @param array[] $aliases * @phpstan-param list $aliases * * @return array> */ private static function getRootAliasesPerPackage(array $aliases): array { $normalizedAliases = []; foreach ($aliases as $alias) { $normalizedAliases[$alias['package']][$alias['version']] = [ 'alias' => $alias['alias'], 'alias_normalized' => $alias['alias_normalized'], ]; } return $normalizedAliases; } } __halt_compiler();----SIGNATURE:----f6+fM9leeY2zgXp5uzGppCvUUF7sYgSVAwxjDSDKWvlVdv2SsjG9YtaXL98+QGiJQ6B8ltEP0vf7rm8kI8GMkNiqe3H1x8sX0+9t62iCA1KZlL4EosGv9p/qev/9HKCe/HmdfTLafev6GJpPwJ+sGUpa631mQcXB/RlhZ3WW/DK339s8WxXx6yJOFDoQjeC3jw12wJi0KBrWCnQHkZ3jMJx1D7JcdYfKgD0Mkz5TRBQ2bb4Tlin/yx5KzmrFl3BOo039ThnJYVLgVc7xse/vK21Y8z2PewkNhOjz+RxU/zPS+O+Ms0v2WkDWW7x00JlVum/H2leYk2sdQevtyvT5iLX092hxqrgkvjjC1T9ZT+gtk6qPZr8ul6B5+pefsiaqCcFjcXmQy7hjx9nEnh0gl9pweiT51bNZv2MGmLrKCsWVDhL06+w6UoaNmhXRUNhJDFr7Qax9jD6BSA/mFfoI4tXZy9IPZ2G2QDT7eMTHN5elGvI9L3KaFSBXtBbcWkWYycEPX5Xv4goWOvUvoCNzdTopwRlJPo1mGFkKoGVMjIztpibKRGEXHQEUlsotS8cafvoIHdN2u2sQ3e8oBgK+0xiWdspjVWwfFCkF++lieA3RnkAjkZAZhsDcdie9OJADL4iV4gk/pIbg1iWr9QSt/rVeO29+J8aqe+CbTFYVq/Y=----ATTACHMENT:----NDIzNjgxNDQ4OTk0MTgxNCA3ODI5NTYzODEzOTAyNjQwIDIwMDkwMDIxNjQyNDQ4Mzk=