annotate vendor/composer/semver/src/Constraint/Constraint.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of composer/semver.
Chris@0 5 *
Chris@0 6 * (c) Composer <https://github.com/composer>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view
Chris@0 9 * the LICENSE file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Composer\Semver\Constraint;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * Defines a constraint.
Chris@0 16 */
Chris@0 17 class Constraint implements ConstraintInterface
Chris@0 18 {
Chris@0 19 /* operator integer values */
Chris@0 20 const OP_EQ = 0;
Chris@0 21 const OP_LT = 1;
Chris@0 22 const OP_LE = 2;
Chris@0 23 const OP_GT = 3;
Chris@0 24 const OP_GE = 4;
Chris@0 25 const OP_NE = 5;
Chris@0 26
Chris@0 27 /**
Chris@0 28 * Operator to integer translation table.
Chris@0 29 *
Chris@0 30 * @var array
Chris@0 31 */
Chris@0 32 private static $transOpStr = array(
Chris@0 33 '=' => self::OP_EQ,
Chris@0 34 '==' => self::OP_EQ,
Chris@0 35 '<' => self::OP_LT,
Chris@0 36 '<=' => self::OP_LE,
Chris@0 37 '>' => self::OP_GT,
Chris@0 38 '>=' => self::OP_GE,
Chris@0 39 '<>' => self::OP_NE,
Chris@0 40 '!=' => self::OP_NE,
Chris@0 41 );
Chris@0 42
Chris@0 43 /**
Chris@0 44 * Integer to operator translation table.
Chris@0 45 *
Chris@0 46 * @var array
Chris@0 47 */
Chris@0 48 private static $transOpInt = array(
Chris@0 49 self::OP_EQ => '==',
Chris@0 50 self::OP_LT => '<',
Chris@0 51 self::OP_LE => '<=',
Chris@0 52 self::OP_GT => '>',
Chris@0 53 self::OP_GE => '>=',
Chris@0 54 self::OP_NE => '!=',
Chris@0 55 );
Chris@0 56
Chris@0 57 /** @var string */
Chris@0 58 protected $operator;
Chris@0 59
Chris@0 60 /** @var string */
Chris@0 61 protected $version;
Chris@0 62
Chris@0 63 /** @var string */
Chris@0 64 protected $prettyString;
Chris@0 65
Chris@0 66 /**
Chris@0 67 * @param ConstraintInterface $provider
Chris@0 68 *
Chris@0 69 * @return bool
Chris@0 70 */
Chris@0 71 public function matches(ConstraintInterface $provider)
Chris@0 72 {
Chris@0 73 if ($provider instanceof $this) {
Chris@0 74 return $this->matchSpecific($provider);
Chris@0 75 }
Chris@0 76
Chris@0 77 // turn matching around to find a match
Chris@0 78 return $provider->matches($this);
Chris@0 79 }
Chris@0 80
Chris@0 81 /**
Chris@0 82 * @param string $prettyString
Chris@0 83 */
Chris@0 84 public function setPrettyString($prettyString)
Chris@0 85 {
Chris@0 86 $this->prettyString = $prettyString;
Chris@0 87 }
Chris@0 88
Chris@0 89 /**
Chris@0 90 * @return string
Chris@0 91 */
Chris@0 92 public function getPrettyString()
Chris@0 93 {
Chris@0 94 if ($this->prettyString) {
Chris@0 95 return $this->prettyString;
Chris@0 96 }
Chris@0 97
Chris@0 98 return $this->__toString();
Chris@0 99 }
Chris@0 100
Chris@0 101 /**
Chris@0 102 * Get all supported comparison operators.
Chris@0 103 *
Chris@0 104 * @return array
Chris@0 105 */
Chris@0 106 public static function getSupportedOperators()
Chris@0 107 {
Chris@0 108 return array_keys(self::$transOpStr);
Chris@0 109 }
Chris@0 110
Chris@0 111 /**
Chris@0 112 * Sets operator and version to compare with.
Chris@0 113 *
Chris@0 114 * @param string $operator
Chris@0 115 * @param string $version
Chris@0 116 *
Chris@0 117 * @throws \InvalidArgumentException if invalid operator is given.
Chris@0 118 */
Chris@0 119 public function __construct($operator, $version)
Chris@0 120 {
Chris@0 121 if (!isset(self::$transOpStr[$operator])) {
Chris@0 122 throw new \InvalidArgumentException(sprintf(
Chris@0 123 'Invalid operator "%s" given, expected one of: %s',
Chris@0 124 $operator,
Chris@0 125 implode(', ', self::getSupportedOperators())
Chris@0 126 ));
Chris@0 127 }
Chris@0 128
Chris@0 129 $this->operator = self::$transOpStr[$operator];
Chris@0 130 $this->version = $version;
Chris@0 131 }
Chris@0 132
Chris@0 133 /**
Chris@0 134 * @param string $a
Chris@0 135 * @param string $b
Chris@0 136 * @param string $operator
Chris@0 137 * @param bool $compareBranches
Chris@0 138 *
Chris@0 139 * @throws \InvalidArgumentException if invalid operator is given.
Chris@0 140 *
Chris@0 141 * @return bool
Chris@0 142 */
Chris@0 143 public function versionCompare($a, $b, $operator, $compareBranches = false)
Chris@0 144 {
Chris@0 145 if (!isset(self::$transOpStr[$operator])) {
Chris@0 146 throw new \InvalidArgumentException(sprintf(
Chris@0 147 'Invalid operator "%s" given, expected one of: %s',
Chris@0 148 $operator,
Chris@0 149 implode(', ', self::getSupportedOperators())
Chris@0 150 ));
Chris@0 151 }
Chris@0 152
Chris@0 153 $aIsBranch = 'dev-' === substr($a, 0, 4);
Chris@0 154 $bIsBranch = 'dev-' === substr($b, 0, 4);
Chris@0 155
Chris@0 156 if ($aIsBranch && $bIsBranch) {
Chris@0 157 return $operator === '==' && $a === $b;
Chris@0 158 }
Chris@0 159
Chris@0 160 // when branches are not comparable, we make sure dev branches never match anything
Chris@0 161 if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
Chris@0 162 return false;
Chris@0 163 }
Chris@0 164
Chris@0 165 return version_compare($a, $b, $operator);
Chris@0 166 }
Chris@0 167
Chris@0 168 /**
Chris@0 169 * @param Constraint $provider
Chris@0 170 * @param bool $compareBranches
Chris@0 171 *
Chris@0 172 * @return bool
Chris@0 173 */
Chris@0 174 public function matchSpecific(Constraint $provider, $compareBranches = false)
Chris@0 175 {
Chris@0 176 $noEqualOp = str_replace('=', '', self::$transOpInt[$this->operator]);
Chris@0 177 $providerNoEqualOp = str_replace('=', '', self::$transOpInt[$provider->operator]);
Chris@0 178
Chris@0 179 $isEqualOp = self::OP_EQ === $this->operator;
Chris@0 180 $isNonEqualOp = self::OP_NE === $this->operator;
Chris@0 181 $isProviderEqualOp = self::OP_EQ === $provider->operator;
Chris@0 182 $isProviderNonEqualOp = self::OP_NE === $provider->operator;
Chris@0 183
Chris@0 184 // '!=' operator is match when other operator is not '==' operator or version is not match
Chris@0 185 // these kinds of comparisons always have a solution
Chris@0 186 if ($isNonEqualOp || $isProviderNonEqualOp) {
Chris@0 187 return !$isEqualOp && !$isProviderEqualOp
Chris@0 188 || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
Chris@0 189 }
Chris@0 190
Chris@0 191 // an example for the condition is <= 2.0 & < 1.0
Chris@0 192 // these kinds of comparisons always have a solution
Chris@0 193 if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
Chris@0 194 return true;
Chris@0 195 }
Chris@0 196
Chris@0 197 if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
Chris@0 198 // special case, e.g. require >= 1.0 and provide < 1.0
Chris@0 199 // 1.0 >= 1.0 but 1.0 is outside of the provided interval
Chris@0 200 if ($provider->version === $this->version
Chris@0 201 && self::$transOpInt[$provider->operator] === $providerNoEqualOp
Chris@0 202 && self::$transOpInt[$this->operator] !== $noEqualOp) {
Chris@0 203 return false;
Chris@0 204 }
Chris@0 205
Chris@0 206 return true;
Chris@0 207 }
Chris@0 208
Chris@0 209 return false;
Chris@0 210 }
Chris@0 211
Chris@0 212 /**
Chris@0 213 * @return string
Chris@0 214 */
Chris@0 215 public function __toString()
Chris@0 216 {
Chris@0 217 return self::$transOpInt[$this->operator] . ' ' . $this->version;
Chris@0 218 }
Chris@0 219 }