ObjectExpressionVisitor.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * @package Grav\Framework\Object
  4. *
  5. * @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Framework\Object\Collection;
  9. use Doctrine\Common\Collections\Expr\ClosureExpressionVisitor;
  10. use Doctrine\Common\Collections\Expr\Comparison;
  11. class ObjectExpressionVisitor extends ClosureExpressionVisitor
  12. {
  13. /**
  14. * Accesses the field of a given object.
  15. *
  16. * @param object $object
  17. * @param string $field
  18. *
  19. * @return mixed
  20. */
  21. public static function getObjectFieldValue($object, $field)
  22. {
  23. $op = $value = null;
  24. $pos = strpos($field, '(');
  25. if (false !== $pos) {
  26. list ($op, $field) = explode('(', $field, 2);
  27. $field = rtrim($field, ')');
  28. }
  29. if (isset($object[$field])) {
  30. $value = $object[$field];
  31. } else {
  32. $accessors = array('', 'get', 'is');
  33. foreach ($accessors as $accessor) {
  34. $accessor .= $field;
  35. if (!method_exists($object, $accessor)) {
  36. continue;
  37. }
  38. $value = $object->{$accessor}();
  39. break;
  40. }
  41. }
  42. if ($op) {
  43. $function = 'filter' . ucfirst(strtolower($op));
  44. if (method_exists(static::class, $function)) {
  45. $value = static::$function($value);
  46. }
  47. }
  48. return $value;
  49. }
  50. public static function filterLower($str)
  51. {
  52. return mb_strtolower($str);
  53. }
  54. public static function filterUpper($str)
  55. {
  56. return mb_strtoupper($str);
  57. }
  58. public static function filterLength($str)
  59. {
  60. return mb_strlen($str);
  61. }
  62. public static function filterLtrim($str)
  63. {
  64. return ltrim($str);
  65. }
  66. public static function filterRtrim($str)
  67. {
  68. return rtrim($str);
  69. }
  70. public static function filterTrim($str)
  71. {
  72. return trim($str);
  73. }
  74. /**
  75. * Helper for sorting arrays of objects based on multiple fields + orientations.
  76. *
  77. * @param string $name
  78. * @param int $orientation
  79. * @param \Closure $next
  80. *
  81. * @return \Closure
  82. */
  83. public static function sortByField($name, $orientation = 1, \Closure $next = null)
  84. {
  85. if (!$next) {
  86. $next = function() {
  87. return 0;
  88. };
  89. }
  90. return function ($a, $b) use ($name, $next, $orientation) {
  91. $aValue = static::getObjectFieldValue($a, $name);
  92. $bValue = static::getObjectFieldValue($b, $name);
  93. if ($aValue === $bValue) {
  94. return $next($a, $b);
  95. }
  96. return (($aValue > $bValue) ? 1 : -1) * $orientation;
  97. };
  98. }
  99. /**
  100. * {@inheritDoc}
  101. */
  102. public function walkComparison(Comparison $comparison)
  103. {
  104. $field = $comparison->getField();
  105. $value = $comparison->getValue()->getValue(); // shortcut for walkValue()
  106. switch ($comparison->getOperator()) {
  107. case Comparison::EQ:
  108. return function ($object) use ($field, $value) {
  109. return static::getObjectFieldValue($object, $field) === $value;
  110. };
  111. case Comparison::NEQ:
  112. return function ($object) use ($field, $value) {
  113. return static::getObjectFieldValue($object, $field) !== $value;
  114. };
  115. case Comparison::LT:
  116. return function ($object) use ($field, $value) {
  117. return static::getObjectFieldValue($object, $field) < $value;
  118. };
  119. case Comparison::LTE:
  120. return function ($object) use ($field, $value) {
  121. return static::getObjectFieldValue($object, $field) <= $value;
  122. };
  123. case Comparison::GT:
  124. return function ($object) use ($field, $value) {
  125. return static::getObjectFieldValue($object, $field) > $value;
  126. };
  127. case Comparison::GTE:
  128. return function ($object) use ($field, $value) {
  129. return static::getObjectFieldValue($object, $field) >= $value;
  130. };
  131. case Comparison::IN:
  132. return function ($object) use ($field, $value) {
  133. return \in_array(static::getObjectFieldValue($object, $field), $value, true);
  134. };
  135. case Comparison::NIN:
  136. return function ($object) use ($field, $value) {
  137. return !\in_array(static::getObjectFieldValue($object, $field), $value, true);
  138. };
  139. case Comparison::CONTAINS:
  140. return function ($object) use ($field, $value) {
  141. return false !== strpos(static::getObjectFieldValue($object, $field), $value);
  142. };
  143. case Comparison::MEMBER_OF:
  144. return function ($object) use ($field, $value) {
  145. $fieldValues = static::getObjectFieldValue($object, $field);
  146. if (!is_array($fieldValues)) {
  147. $fieldValues = iterator_to_array($fieldValues);
  148. }
  149. return \in_array($value, $fieldValues, true);
  150. };
  151. case Comparison::STARTS_WITH:
  152. return function ($object) use ($field, $value) {
  153. return 0 === strpos(static::getObjectFieldValue($object, $field), $value);
  154. };
  155. case Comparison::ENDS_WITH:
  156. return function ($object) use ($field, $value) {
  157. return $value === substr(static::getObjectFieldValue($object, $field), -strlen($value));
  158. };
  159. default:
  160. throw new \RuntimeException("Unknown comparison operator: " . $comparison->getOperator());
  161. }
  162. }
  163. }