Constraint.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. namespace Drupal\Component\Version;
  3. /**
  4. * A value object representing a Drupal version constraint.
  5. */
  6. class Constraint {
  7. /**
  8. * The constraint represented as a string. For example '>=8.x-5.x'.
  9. *
  10. * @var string
  11. */
  12. protected $constraint;
  13. /**
  14. * A list of associative arrays representing the constraint.
  15. *
  16. * Each containing the keys:
  17. * - 'op': can be one of: '=', '==', '!=', '<>', '<', '<=', '>', or '>='.
  18. * - 'version': A complete version, e.g. '4.5-beta3'.
  19. *
  20. * @var array[]
  21. */
  22. protected $constraintArray = [];
  23. /**
  24. * Constraint constructor.
  25. *
  26. * @param string $constraint
  27. * The constraint string to create the object from. For example, '>8.x-1.1'.
  28. * @param string $core_compatibility
  29. * Core compatibility declared for the current version of Drupal core.
  30. * Normally this is set to \Drupal::CORE_COMPATIBILITY by the caller.
  31. */
  32. public function __construct($constraint, $core_compatibility) {
  33. $this->constraint = $constraint;
  34. $this->parseConstraint($constraint, $core_compatibility);
  35. }
  36. /**
  37. * Gets the constraint as a string.
  38. *
  39. * Can be used in the UI for reporting incompatibilities.
  40. *
  41. * @return string
  42. * The constraint as a string.
  43. */
  44. public function __toString() {
  45. return $this->constraint;
  46. }
  47. /**
  48. * A list of associative arrays representing the constraint.
  49. *
  50. * Each containing the keys:
  51. * - 'op': can be one of: '=', '==', '!=', '<>', '<', '<=', '>', or '>='.
  52. * - 'version': A complete version, e.g. '4.5-beta3'.
  53. *
  54. * @return array[]
  55. * The constraint represented as an array.
  56. *
  57. * @deprecated in drupal:8.7.0 and is removed from drupal:9.0.0.
  58. * Only exists to provide a backwards compatibility layer.
  59. *
  60. * @see https://www.drupal.org/node/2756875
  61. */
  62. public function toArray() {
  63. @trigger_error(sprintf('%s() only exists to provide a backwards compatibility layer. See https://www.drupal.org/node/2756875', __METHOD__), E_USER_DEPRECATED);
  64. return $this->constraintArray;
  65. }
  66. /**
  67. * Determines if the provided version is satisfied by this constraint.
  68. *
  69. * @param string $version
  70. * The version to check, for example '4.2'.
  71. *
  72. * @return bool
  73. * TRUE if the provided version is satisfied by this constraint, FALSE if
  74. * not.
  75. */
  76. public function isCompatible($version) {
  77. foreach ($this->constraintArray as $constraint) {
  78. if (!version_compare($version, $constraint['version'], $constraint['op'])) {
  79. return FALSE;
  80. }
  81. }
  82. return TRUE;
  83. }
  84. /**
  85. * Parses a constraint string.
  86. *
  87. * @param string $constraint_string
  88. * The constraint string to parse.
  89. * @param string $core_compatibility
  90. * Core compatibility declared for the current version of Drupal core.
  91. * Normally this is set to \Drupal::CORE_COMPATIBILITY by the caller.
  92. */
  93. private function parseConstraint($constraint_string, $core_compatibility) {
  94. // We use named subpatterns and support every op that version_compare
  95. // supports. Also, op is optional and defaults to equals.
  96. $p_op = '(?<operation>!=|==|=|<|<=|>|>=|<>)?';
  97. // Core version is always optional: 8.x-2.x and 2.x is treated the same.
  98. $p_core = '(?:' . preg_quote($core_compatibility) . '-)?';
  99. $p_major = '(?<major>\d+)';
  100. // By setting the minor version to x, branches can be matched.
  101. $p_minor = '(?<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
  102. foreach (explode(',', $constraint_string) as $constraint) {
  103. if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $constraint, $matches)) {
  104. $op = !empty($matches['operation']) ? $matches['operation'] : '=';
  105. if ($matches['minor'] == 'x') {
  106. // Drupal considers "2.x" to mean any version that begins with
  107. // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(),
  108. // on the other hand, treats "x" as a string; so to
  109. // version_compare(), "2.x" is considered less than 2.0. This
  110. // means that >=2.x and <2.x are handled by version_compare()
  111. // as we need, but > and <= are not.
  112. if ($op == '>' || $op == '<=') {
  113. $matches['major']++;
  114. }
  115. // Equivalence can be checked by adding two restrictions.
  116. if ($op == '=' || $op == '==') {
  117. $this->constraintArray[] = ['op' => '<', 'version' => ($matches['major'] + 1) . '.x'];
  118. $op = '>=';
  119. }
  120. }
  121. $this->constraintArray[] = ['op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']];
  122. }
  123. }
  124. }
  125. }