Chris@18: =8.x-5.x'. Chris@18: * Chris@18: * @var string Chris@18: */ Chris@18: protected $constraint; Chris@18: Chris@18: /** Chris@18: * A list of associative arrays representing the constraint. Chris@18: * Chris@18: * Each containing the keys: Chris@18: * - 'op': can be one of: '=', '==', '!=', '<>', '<', '<=', '>', or '>='. Chris@18: * - 'version': A complete version, e.g. '4.5-beta3'. Chris@18: * Chris@18: * @var array[] Chris@18: */ Chris@18: protected $constraintArray = []; Chris@18: Chris@18: /** Chris@18: * Constraint constructor. Chris@18: * Chris@18: * @param string $constraint Chris@18: * The constraint string to create the object from. For example, '>8.x-1.1'. Chris@18: * @param string $core_compatibility Chris@18: * Core compatibility declared for the current version of Drupal core. Chris@18: * Normally this is set to \Drupal::CORE_COMPATIBILITY by the caller. Chris@18: */ Chris@18: public function __construct($constraint, $core_compatibility) { Chris@18: $this->constraint = $constraint; Chris@18: $this->parseConstraint($constraint, $core_compatibility); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Gets the constraint as a string. Chris@18: * Chris@18: * Can be used in the UI for reporting incompatibilities. Chris@18: * Chris@18: * @return string Chris@18: * The constraint as a string. Chris@18: */ Chris@18: public function __toString() { Chris@18: return $this->constraint; Chris@18: } Chris@18: Chris@18: /** Chris@18: * A list of associative arrays representing the constraint. Chris@18: * Chris@18: * Each containing the keys: Chris@18: * - 'op': can be one of: '=', '==', '!=', '<>', '<', '<=', '>', or '>='. Chris@18: * - 'version': A complete version, e.g. '4.5-beta3'. Chris@18: * Chris@18: * @return array[] Chris@18: * The constraint represented as an array. Chris@18: * Chris@18: * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Chris@18: * Only exists to provide a backwards compatibility layer. Chris@18: * Chris@18: * @see https://www.drupal.org/node/2756875 Chris@18: */ Chris@18: public function toArray() { Chris@18: @trigger_error(sprintf('%s() only exists to provide a backwards compatibility layer. See https://www.drupal.org/node/2756875', __METHOD__), E_USER_DEPRECATED); Chris@18: return $this->constraintArray; Chris@18: } Chris@18: Chris@18: /** Chris@18: * Determines if the provided version is satisfied by this constraint. Chris@18: * Chris@18: * @param string $version Chris@18: * The version to check, for example '4.2'. Chris@18: * Chris@18: * @return bool Chris@18: * TRUE if the provided version is satisfied by this constraint, FALSE if Chris@18: * not. Chris@18: */ Chris@18: public function isCompatible($version) { Chris@18: foreach ($this->constraintArray as $constraint) { Chris@18: if (!version_compare($version, $constraint['version'], $constraint['op'])) { Chris@18: return FALSE; Chris@18: } Chris@18: } Chris@18: return TRUE; Chris@18: } Chris@18: Chris@18: /** Chris@18: * Parses a constraint string. Chris@18: * Chris@18: * @param string $constraint_string Chris@18: * The constraint string to parse. Chris@18: * @param string $core_compatibility Chris@18: * Core compatibility declared for the current version of Drupal core. Chris@18: * Normally this is set to \Drupal::CORE_COMPATIBILITY by the caller. Chris@18: */ Chris@18: private function parseConstraint($constraint_string, $core_compatibility) { Chris@18: // We use named subpatterns and support every op that version_compare Chris@18: // supports. Also, op is optional and defaults to equals. Chris@18: $p_op = '(?!=|==|=|<|<=|>|>=|<>)?'; Chris@18: // Core version is always optional: 8.x-2.x and 2.x is treated the same. Chris@18: $p_core = '(?:' . preg_quote($core_compatibility) . '-)?'; Chris@18: $p_major = '(?\d+)'; Chris@18: // By setting the minor version to x, branches can be matched. Chris@18: $p_minor = '(?(?:\d+|x)(?:-[A-Za-z]+\d+)?)'; Chris@18: foreach (explode(',', $constraint_string) as $constraint) { Chris@18: if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $constraint, $matches)) { Chris@18: $op = !empty($matches['operation']) ? $matches['operation'] : '='; Chris@18: if ($matches['minor'] == 'x') { Chris@18: // Drupal considers "2.x" to mean any version that begins with Chris@18: // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(), Chris@18: // on the other hand, treats "x" as a string; so to Chris@18: // version_compare(), "2.x" is considered less than 2.0. This Chris@18: // means that >=2.x and <2.x are handled by version_compare() Chris@18: // as we need, but > and <= are not. Chris@18: if ($op == '>' || $op == '<=') { Chris@18: $matches['major']++; Chris@18: } Chris@18: // Equivalence can be checked by adding two restrictions. Chris@18: if ($op == '=' || $op == '==') { Chris@18: $this->constraintArray[] = ['op' => '<', 'version' => ($matches['major'] + 1) . '.x']; Chris@18: $op = '>='; Chris@18: } Chris@18: } Chris@18: $this->constraintArray[] = ['op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']]; Chris@18: } Chris@18: } Chris@18: } Chris@18: Chris@18: }