/model/ArrayList.php

https://github.com/markjames/sapphire · PHP · 247 lines · 143 code · 37 blank · 67 comment · 15 complexity · 3ae7bc4d2b2705f94606fe974e541fb8 MD5 · raw file

  1. <?php
  2. /**
  3. * A list object that wraps around an array of objects or arrays.
  4. *
  5. * @package sapphire
  6. * @subpackage model
  7. */
  8. class ArrayList extends ViewableData implements SS_List {
  9. /**
  10. * @var array
  11. */
  12. protected $items;
  13. public function __construct(array $items = array()) {
  14. $this->items = $items;
  15. parent::__construct();
  16. }
  17. public function count() {
  18. return count($this->items);
  19. }
  20. public function exists() {
  21. return (bool) count($this);
  22. }
  23. public function getIterator() {
  24. return new ArrayIterator($this->items);
  25. }
  26. public function toArray() {
  27. return $this->items;
  28. }
  29. public function toNestedArray() {
  30. $result = array();
  31. foreach ($this->items as $item) {
  32. if (is_object($item)) {
  33. if (method_exists($item, 'toMap')) {
  34. $result[] = $item->toMap();
  35. } else {
  36. $result[] = (array) $item;
  37. }
  38. } else {
  39. $result[] = $item;
  40. }
  41. }
  42. return $result;
  43. }
  44. public function getRange($offset, $length) {
  45. return new ArrayList(array_slice($this->items, $offset, $length));
  46. }
  47. public function add($item) {
  48. $this->push($item);
  49. }
  50. public function remove($item) {
  51. foreach ($this->items as $key => $value) {
  52. if ($item === $value) unset($this->items[$key]);
  53. }
  54. }
  55. /**
  56. * Replaces an item in this list with another item.
  57. *
  58. * @param array|object $item
  59. * @param array|object $with
  60. * @return void;
  61. */
  62. public function replace($item, $with) {
  63. foreach ($this->items as $key => $candidate) {
  64. if ($candidate === $item) {
  65. $this->items[$key] = $with;
  66. return;
  67. }
  68. }
  69. }
  70. /**
  71. * Merges with another array or list by pushing all the items in it onto the
  72. * end of this list.
  73. *
  74. * @param array|object $with
  75. */
  76. public function merge($with) {
  77. foreach ($with as $item) $this->push($item);
  78. }
  79. /**
  80. * Removes items from this list which have a duplicate value for a certain
  81. * field. This is especially useful when combining lists.
  82. *
  83. * @param string $field
  84. */
  85. public function removeDuplicates($field = 'ID') {
  86. $seen = array();
  87. foreach ($this->items as $key => $item) {
  88. $value = $this->extractValue($item, $field);
  89. if (array_key_exists($value, $seen)) {
  90. unset($this->items[$key]);
  91. }
  92. $seen[$value] = true;
  93. }
  94. }
  95. /**
  96. * Pushes an item onto the end of this list.
  97. *
  98. * @param array|object $item
  99. */
  100. public function push($item) {
  101. $this->items[] = $item;
  102. }
  103. /**
  104. * Pops the last element off the end of the list and returns it.
  105. *
  106. * @return array|object
  107. */
  108. public function pop() {
  109. return array_pop($this->items);
  110. }
  111. /**
  112. * Unshifts an item onto the beginning of the list.
  113. *
  114. * @param array|object $item
  115. */
  116. public function unshift($item) {
  117. array_unshift($this->items, $item);
  118. }
  119. /**
  120. * Shifts the item off the beginning of the list and returns it.
  121. *
  122. * @return array|object
  123. */
  124. public function shift() {
  125. return array_shift($this->items);
  126. }
  127. public function first() {
  128. return reset($this->items);
  129. }
  130. public function last() {
  131. return end($this->items);
  132. }
  133. public function map($keyfield = 'ID', $titlefield = 'Title') {
  134. $map = array();
  135. foreach ($this->items as $item) {
  136. $map[$this->extractValue($item, $keyfield)] = $this->extractValue($item, $titlefield);
  137. }
  138. return $map;
  139. }
  140. public function find($key, $value) {
  141. foreach ($this->items as $item) {
  142. if ($this->extractValue($item, $key) == $value) return $item;
  143. }
  144. }
  145. public function column($field = 'ID') {
  146. $result = array();
  147. foreach ($this->items as $item) {
  148. $result[] = $this->extractValue($item, $field);
  149. }
  150. return $result;
  151. }
  152. public function canSortBy($by) {
  153. return true;
  154. }
  155. /**
  156. * Sorts this list by one or more fields. You can either pass in a single
  157. * field name and direction, or a map of field names to sort directions.
  158. *
  159. * @param string|array $by
  160. * @param string $sortDirection
  161. * @see SS_List::sort()
  162. * @link http://php.net/manual/en/function.array-multisort.php
  163. * @example $list->sort('Name', 'ASC');
  164. * @example $list->sort(array('Name'=>'ASC,'Age'=>'DESC');
  165. */
  166. public function sort($by, $sortDirection = 'ASC') {
  167. $sorts = array();
  168. if(!is_array($by)) {
  169. $by = array($by => $sortDirection);
  170. }
  171. foreach ($by as $field => $sortDirection) {
  172. $sortDirection = strtoupper($sortDirection) == 'DESC' ? SORT_DESC : SORT_ASC;
  173. $values = array();
  174. foreach($this->items as $item) {
  175. $values[] = $this->extractValue($item, $field);
  176. }
  177. $sorts[] = &$values;
  178. $sorts[] = &$sortDirection;
  179. }
  180. $sorts[] = &$this->items;
  181. call_user_func_array('array_multisort', $sorts);
  182. }
  183. public function offsetExists($offset) {
  184. return array_key_exists($offset, $this->items);
  185. }
  186. public function offsetGet($offset) {
  187. if ($this->offsetExists($offset)) return $this->items[$offset];
  188. }
  189. public function offsetSet($offset, $value) {
  190. $this->items[$offset] = $value;
  191. }
  192. public function offsetUnset($offset) {
  193. unset($this->items[$offset]);
  194. }
  195. /**
  196. * Extracts a value from an item in the list, where the item is either an
  197. * object or array.
  198. *
  199. * @param array|object $item
  200. * @param string $key
  201. * @return mixed
  202. */
  203. protected function extractValue($item, $key) {
  204. if (is_object($item)) {
  205. return $item->$key;
  206. } else {
  207. if (array_key_exists($key, $item)) return $item[$key];
  208. }
  209. }
  210. }