1: <?php
2:
3: 4: 5: 6: 7: 8:
9:
10: namespace rsanchez\Deep\Collection;
11:
12: 13: 14: 15: 16:
17: trait FilterableTrait
18: {
19: 20: 21: 22:
23: public function createClone()
24: {
25: return clone $this;
26: }
27:
28: 29: 30: 31: 32: 33: 34: 35: 36:
37: public function filterByAttributeContains($attribute, array $values, $and = false, $not = false)
38: {
39: $this->items = array_filter($this->items, function ($model) use ($attribute, $and, $not, $values) {
40: $isMatch = false;
41:
42: foreach ($values as $value) {
43: if ($value) {
44: if (preg_match('#^(.+)\\\W$#', $value, $match)) {
45: $regex = '#\b'.preg_quote($match[1]).'\b#';
46: } else {
47: $regex = '#'.preg_quote($value).'#';
48: }
49:
50: $isValueMatch = (bool) preg_match($regex, $model->$attribute);
51: } else {
52: $isValueMatch = empty($model->$attribute);
53: }
54:
55: $isMatch = $not ? ! $isValueMatch : $isValueMatch;
56:
57: if ($and && ! $isValueMatch) {
58: break;
59: } elseif (! $and && $isValueMatch) {
60: break;
61: }
62: }
63:
64: return $isMatch;
65: });
66: }
67:
68: 69: 70: 71: 72: 73: 74:
75: public function filterByAttributeInString($attribute, $filter)
76: {
77: $not = strncmp('not ', $filter, 4) === 0;
78:
79: if ($not) {
80: $filter = substr($filter, 4);
81: }
82:
83: return $this->filterByAttributeIn($attribute, explode('|', $filter), $not);
84: }
85:
86: 87: 88: 89: 90: 91: 92: 93:
94: public function filterByAttributeIn($attribute, array $values, $not = false)
95: {
96: $this->items = array_filter($this->items, function ($model) use ($attribute, $not, $values) {
97: return $not ? ! in_array($model->$attribute, $values) : in_array($model->$attribute, $values);
98: });
99: }
100:
101: 102: 103: 104: 105: 106: 107: 108:
109: public function filterByAttributeComparison($attribute, $value, $operator)
110: {
111: $this->items = array_filter($this->items, function ($model) use ($value, $attribute, $operator) {
112: switch ($operator) {
113: case '>':
114: return $model->$attribute > $value;
115: case '>=':
116: return $model->$attribute >= $value;
117: case '<':
118: return $model->$attribute < $value;
119: case '<=':
120: return $model->$attribute <= $value;
121: }
122: });
123:
124: return $this;
125: }
126:
127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143:
144: public function filterByAttribute($attribute, $filter)
145: {
146:
147: if (preg_match('#^(>|>=|<|<=)(.+)$#', $filter, $match)) {
148: $operator = $match[1];
149:
150: $value = $match[2];
151:
152: return $this->filterByAttributeComparison($attribute, $value, $operator);
153: }
154:
155: if (strncmp($filter, '=', 1) === 0) {
156: $contains = false;
157: $filter = substr($filter, 1);
158: } else {
159: $contains = true;
160: }
161:
162: if (strncmp($filter, 'not ', 4) === 0) {
163: $not = true;
164: $filter = substr($filter, 4);
165: } else {
166: $not = false;
167: }
168:
169: $and = $contains && strpos($filter, '&&') !== false;
170:
171: $separator = $and ? '&&' : '|';
172:
173: $filter = str_replace('IS_EMPTY', '', $filter);
174:
175: $values = explode($separator, $filter);
176:
177: if ($contains) {
178: return $this->filterByAttributeContains($attribute, $values, $and, $not);
179: }
180:
181: return $this->filterByAttributeIn($attribute, $values, $not);
182: }
183:
184: 185: 186: 187: 188: 189:
190: public function filterById($id)
191: {
192: $ids = is_array($id) ? $id : array($id);
193:
194: $this->items = array_filter($this->items, function ($model) use ($ids) {
195: return in_array($model->getKey(), $ids);
196: });
197:
198: return $this;
199: }
200:
201: 202: 203: 204: 205: 206: 207:
208: public function limit($limit, $offset = 0)
209: {
210: $this->items = array_slice($this->items, $offset, $limit);
211:
212: return $this;
213: }
214:
215: 216: 217: 218: 219: 220: 221:
222: public function offset($offset, $limit = null)
223: {
224: $this->items = array_slice($this->items, $offset, $limit);
225:
226: return $this;
227: }
228:
229: 230: 231: 232: 233: 234: 235:
236: public function sortByAttribute($attribute, $sort = 'asc')
237: {
238:
239: $attributes = is_array($attribute) ? $attribute : array($attribute);
240:
241: $sort = is_array($sort) ? $sort : array($sort);
242:
243: $sort = array_pad($sort, count($attributes), 'asc');
244:
245: $comparison = array();
246:
247: foreach ($this->items as $i => $model) {
248: foreach ($attributes as $attribute) {
249: $comparison[$attribute][$i] = $model->$attribute;
250: }
251: }
252:
253: $args = array();
254:
255: foreach ($attributes as $i => $attribute) {
256: $args[] = $comparison[$attribute];
257: $args[] = $sort[$i] === 'asc' ? SORT_ASC : SORT_DESC;
258: }
259:
260: $args[] =& $this->items;
261:
262: call_user_func_array('array_multisort', $args);
263:
264: return $this;
265: }
266:
267: 268: 269: 270: 271: 272:
273: public function sortByFixedOrder($id)
274: {
275: $ids = is_array($id) ? $id : func_get_args();
276:
277: $this->filterById($ids);
278:
279: usort($this->items, function ($modelA, $modelB) use ($ids) {
280: return array_search($modelA->getKey(), $ids) - array_search($modelB->getKey(), $ids);
281: });
282:
283: return $this;
284: }
285:
286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300:
301: public function tagparams(array $params)
302: {
303: if (! $this->items) {
304: return $this;
305: }
306:
307: $collection = $this->createClone();
308:
309: $ignore = array('fixed_order', 'orderby', 'sort', 'offset', 'limit', 'var_prefix', 'backspace');
310:
311: $filters = array_diff_key($params, array_flip($ignore));
312:
313: $searches = array_filter(array_keys($params), function ($key) {
314: return;
315: });
316:
317: foreach ($filters as $attribute => $filter) {
318: if (! $filter) {
319: continue;
320: }
321:
322: $method = 'filterBy'.ucfirst(camel_case($attribute));
323:
324: if (method_exists($collection, $method)) {
325: $collection->$method($filter);
326: continue;
327: }
328:
329: if (strncmp($attribute, 'search:', 7) === 0) {
330: $attribute = substr($attribute, 7);
331: } elseif (strncmp($filter, '=', 1) !== 0) {
332: $filter = '='.$filter;
333: }
334:
335: $collection->filterByAttribute($attribute, $filter);
336: }
337:
338: if (isset($params['fixed_order'])) {
339: $ids = explode('|', $params['fixed_order']);
340:
341: $collection->sortByFixedOrder($ids);
342: } elseif (isset($params['orderby'])) {
343: $attributes = explode('|', $params['orderby']);
344:
345: $sort = isset($params['sort']) ? explode('|', $params['sort']) : array();
346:
347: $collection->sortByAttribute($attributes, $sort);
348: }
349:
350: if (isset($params['offset']) || isset($params['limit'])) {
351: $offset = isset($params['offset']) ? $params['offset'] : 0;
352: $limit = isset($params['limit']) ? $params['limit'] : null;
353:
354: $collection->limit($limit, $offset);
355: }
356:
357: return $collection;
358: }
359:
360: 361: 362: 363: 364:
365: public function __get($name)
366: {
367: $model = $this->first();
368:
369: return $model ? $model->$name : null;
370: }
371:
372: 373: 374: 375: 376: 377:
378: public function __invoke(array $params)
379: {
380: return $this->tagparams($params);
381: }
382: }
383: