123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- <?php
- /*
- * This file is part of composer/semver.
- *
- * (c) Composer <https://github.com/composer>
- *
- * For the full copyright and license information, please view
- * the LICENSE file that was distributed with this source code.
- */
- namespace Composer\Semver\Constraint;
- /**
- * Defines a constraint.
- */
- class Constraint implements ConstraintInterface
- {
- /* operator integer values */
- const OP_EQ = 0;
- const OP_LT = 1;
- const OP_LE = 2;
- const OP_GT = 3;
- const OP_GE = 4;
- const OP_NE = 5;
- /**
- * Operator to integer translation table.
- *
- * @var array
- */
- private static $transOpStr = array(
- '=' => self::OP_EQ,
- '==' => self::OP_EQ,
- '<' => self::OP_LT,
- '<=' => self::OP_LE,
- '>' => self::OP_GT,
- '>=' => self::OP_GE,
- '<>' => self::OP_NE,
- '!=' => self::OP_NE,
- );
- /**
- * Integer to operator translation table.
- *
- * @var array
- */
- private static $transOpInt = array(
- self::OP_EQ => '==',
- self::OP_LT => '<',
- self::OP_LE => '<=',
- self::OP_GT => '>',
- self::OP_GE => '>=',
- self::OP_NE => '!=',
- );
- /** @var string */
- protected $operator;
- /** @var string */
- protected $version;
- /** @var string */
- protected $prettyString;
- /**
- * @param ConstraintInterface $provider
- *
- * @return bool
- */
- public function matches(ConstraintInterface $provider)
- {
- if ($provider instanceof $this) {
- return $this->matchSpecific($provider);
- }
- // turn matching around to find a match
- return $provider->matches($this);
- }
- /**
- * @param string $prettyString
- */
- public function setPrettyString($prettyString)
- {
- $this->prettyString = $prettyString;
- }
- /**
- * @return string
- */
- public function getPrettyString()
- {
- if ($this->prettyString) {
- return $this->prettyString;
- }
- return $this->__toString();
- }
- /**
- * Get all supported comparison operators.
- *
- * @return array
- */
- public static function getSupportedOperators()
- {
- return array_keys(self::$transOpStr);
- }
- /**
- * Sets operator and version to compare with.
- *
- * @param string $operator
- * @param string $version
- *
- * @throws \InvalidArgumentException if invalid operator is given.
- */
- public function __construct($operator, $version)
- {
- if (!isset(self::$transOpStr[$operator])) {
- throw new \InvalidArgumentException(sprintf(
- 'Invalid operator "%s" given, expected one of: %s',
- $operator,
- implode(', ', self::getSupportedOperators())
- ));
- }
- $this->operator = self::$transOpStr[$operator];
- $this->version = $version;
- }
- /**
- * @param string $a
- * @param string $b
- * @param string $operator
- * @param bool $compareBranches
- *
- * @throws \InvalidArgumentException if invalid operator is given.
- *
- * @return bool
- */
- public function versionCompare($a, $b, $operator, $compareBranches = false)
- {
- if (!isset(self::$transOpStr[$operator])) {
- throw new \InvalidArgumentException(sprintf(
- 'Invalid operator "%s" given, expected one of: %s',
- $operator,
- implode(', ', self::getSupportedOperators())
- ));
- }
- $aIsBranch = 'dev-' === substr($a, 0, 4);
- $bIsBranch = 'dev-' === substr($b, 0, 4);
- if ($aIsBranch && $bIsBranch) {
- return $operator === '==' && $a === $b;
- }
- // when branches are not comparable, we make sure dev branches never match anything
- if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
- return false;
- }
- return version_compare($a, $b, $operator);
- }
- /**
- * @param Constraint $provider
- * @param bool $compareBranches
- *
- * @return bool
- */
- public function matchSpecific(Constraint $provider, $compareBranches = false)
- {
- $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
- $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
- $isEqualOp = self::OP_EQ === $this->operator;
- $isNonEqualOp = self::OP_NE === $this->operator;
- $isProviderEqualOp = self::OP_EQ === $provider->operator;
- $isProviderNonEqualOp = self::OP_NE === $provider->operator;
- // '!=' operator is match when other operator is not '==' operator or version is not match
- // these kinds of comparisons always have a solution
- if ($isNonEqualOp || $isProviderNonEqualOp) {
- return (!$isEqualOp && !$isProviderEqualOp)
- || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
- }
- // an example for the condition is <= 2.0 & < 1.0
- // these kinds of comparisons always have a solution
- if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
- return true;
- }
- if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
- // special case, e.g. require >= 1.0 and provide < 1.0
- // 1.0 >= 1.0 but 1.0 is outside of the provided interval
- return !($provider->version === $this->version
- && self::$transOpInt[$provider->operator] === $providerNoEqualOp
- && self::$transOpInt[$this->operator] !== $noEqualOp);
- }
- return false;
- }
- /**
- * @return string
- */
- public function __toString()
- {
- return self::$transOpInt[$this->operator] . ' ' . $this->version;
- }
- }
|