ExtractTrait.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Collection;
  16. use Traversable;
  17. /**
  18. * Provides utility protected methods for extracting a property or column
  19. * from an array or object.
  20. */
  21. trait ExtractTrait
  22. {
  23. /**
  24. * Returns a callable that can be used to extract a property or column from
  25. * an array or object based on a dot separated path.
  26. *
  27. * @param string|callable $callback A dot separated path of column to follow
  28. * so that the final one can be returned or a callable that will take care
  29. * of doing that.
  30. * @return callable
  31. */
  32. protected function _propertyExtractor($callback)
  33. {
  34. if (!is_string($callback)) {
  35. return $callback;
  36. }
  37. $path = explode('.', $callback);
  38. if (strpos($callback, '{*}') !== false) {
  39. return function ($element) use ($path) {
  40. return $this->_extract($element, $path);
  41. };
  42. }
  43. return function ($element) use ($path) {
  44. return $this->_simpleExtract($element, $path);
  45. };
  46. }
  47. /**
  48. * Returns a column from $data that can be extracted
  49. * by iterating over the column names contained in $path.
  50. * It will return arrays for elements in represented with `{*}`
  51. *
  52. * @param array|\ArrayAccess $data Data.
  53. * @param array $path Path to extract from.
  54. * @return mixed
  55. */
  56. protected function _extract($data, $path)
  57. {
  58. $value = null;
  59. $collectionTransform = false;
  60. foreach ($path as $i => $column) {
  61. if ($column === '{*}') {
  62. $collectionTransform = true;
  63. continue;
  64. }
  65. if ($collectionTransform &&
  66. !($data instanceof Traversable || is_array($data))) {
  67. return null;
  68. }
  69. if ($collectionTransform) {
  70. $rest = implode('.', array_slice($path, $i));
  71. return (new Collection($data))->extract($rest);
  72. }
  73. if (!isset($data[$column])) {
  74. return null;
  75. }
  76. $value = $data[$column];
  77. $data = $value;
  78. }
  79. return $value;
  80. }
  81. /**
  82. * Returns a column from $data that can be extracted
  83. * by iterating over the column names contained in $path
  84. *
  85. * @param array|\ArrayAccess $data Data.
  86. * @param array $path Path to extract from.
  87. * @return mixed
  88. */
  89. protected function _simpleExtract($data, $path)
  90. {
  91. $value = null;
  92. foreach ($path as $column) {
  93. if (!isset($data[$column])) {
  94. return null;
  95. }
  96. $value = $data[$column];
  97. $data = $value;
  98. }
  99. return $value;
  100. }
  101. /**
  102. * Returns a callable that receives a value and will return whether or not
  103. * it matches certain condition.
  104. *
  105. * @param array $conditions A key-value list of conditions to match where the
  106. * key is the property path to get from the current item and the value is the
  107. * value to be compared the item with.
  108. * @return callable
  109. */
  110. protected function _createMatcherFilter(array $conditions)
  111. {
  112. $matchers = [];
  113. foreach ($conditions as $property => $value) {
  114. $extractor = $this->_propertyExtractor($property);
  115. $matchers[] = function ($v) use ($extractor, $value) {
  116. return $extractor($v) == $value;
  117. };
  118. }
  119. return function ($value) use ($matchers) {
  120. foreach ($matchers as $match) {
  121. if (!$match($value)) {
  122. return false;
  123. }
  124. }
  125. return true;
  126. };
  127. }
  128. }