Overview

Namespaces

  • rsanchez
    • Deep
      • App
        • EE
        • Laravel
          • Facade
      • Collection
      • Hydrator
      • Model
      • Plugin
      • Relations
      • Repository

Classes

  • AbstractFieldCollection
  • AbstractTitleCollection
  • AssetCollection
  • CategoryCollection
  • CategoryFieldCollection
  • ChannelCollection
  • EntryCollection
  • FieldCollection
  • FileCollection
  • GridColCollection
  • GridRowCollection
  • MatrixColCollection
  • MatrixRowCollection
  • MemberFieldCollection
  • PlayaCollection
  • RelationshipCollection
  • SiteCollection
  • TitleCollection
  • UploadPrefCollection

Interfaces

  • FilterableInterface

Traits

  • FilterableTrait
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * Deep
  5:  *
  6:  * @package      rsanchez\Deep
  7:  * @author       Rob Sanchez <info@robsanchez.com>
  8:  */
  9: 
 10: namespace rsanchez\Deep\Collection;
 11: 
 12: /**
 13:  * {@inheritdoc}
 14:  *
 15:  * A model collection that is sortable and filterable by common parameters
 16:  */
 17: trait FilterableTrait
 18: {
 19:     /**
 20:      * Create a copy of this Collection
 21:      * @return \Illuminate\Database\Eloquent\Collection
 22:      */
 23:     public function createClone()
 24:     {
 25:         return clone $this;
 26:     }
 27: 
 28:     /**
 29:      * Filter by model attribute contains
 30:      *
 31:      * @param  string                                   $attribute name of the attribute on which to filter
 32:      * @param  array                                    $values
 33:      * @param  bool                                     $and
 34:      * @param  bool                                     $not
 35:      * @return \Illuminate\Database\Eloquent\Collection
 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:      * Filter by model attribute in array string
 70:      *
 71:      * @param  string                                   $attribute name of the attribute on which to filter
 72:      * @param  string                                   $filter    pipe-delimited list of values, optionaly prefixed by not
 73:      * @return \Illuminate\Database\Eloquent\Collection
 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:      * Filter by model attribute in array
 88:      *
 89:      * @param  string                                   $attribute name of the attribute on which to filter
 90:      * @param  array                                    $values
 91:      * @param  bool                                     $not
 92:      * @return \Illuminate\Database\Eloquent\Collection
 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:      * Filter by model attribute numerical comparison
103:      *
104:      * @param  string                                   $attribute name of the attribute on which to filter
105:      * @param  mixed                                    $value
106:      * @param  string                                   $operator  >, >=, <, <=
107:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Filter by model attribute
129:      *
130:      * The filter should be one of the following formats:
131:      * - 'foo|bar'
132:      * - 'not foo|bar'
133:      * - '=foo|bar'
134:      * - '=not foo|bar'
135:      * - 'foo&&bar'
136:      * - 'not foo|bar'
137:      * - 'foo\W|bar'
138:      * - '>=3'
139:      *
140:      * @param  string                                   $attribute name of the attribute on which to filter
141:      * @param  string                                   $filter    a string describing the filter
142:      * @return \Illuminate\Database\Eloquent\Collection
143:      */
144:     public function filterByAttribute($attribute, $filter)
145:     {
146:         // numeric comparisons must be a a single value, not a pipe delimited list
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:      * Filter by model ID
186:      *
187:      * @param  int                                      $id,... one or more IDs
188:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Limit the collection
203:      *
204:      * @param  int                                      $limit
205:      * @param  int                                      $offset
206:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Offset the collection
217:      *
218:      * @param  int                                      $limit
219:      * @param  int                                      $offset
220:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Sort by one or more model attributes
231:      *
232:      * @param  array|int                                $id   one or more IDs
233:      * @param  array|string                             $sort sort direction
234:      * @return \Illuminate\Database\Eloquent\Collection
235:      */
236:     public function sortByAttribute($attribute, $sort = 'asc')
237:     {
238:         //multisort
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:      * Sort by model ID in the specified order
269:      *
270:      * @param  int                                      $id,... one or more IDs
271:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Sort and filter a clone of this collection according to the given array of params.
288:      *
289:      * The array may contain the following:
290:      * - limit
291:      * - offset
292:      * - search:your_field
293:      * - fixed_order
294:      * - orderby
295:      * - sort
296:      * - any model attribute (ex. row_id)
297:      *
298:      * @param  array                                    $params
299:      * @return \Illuminate\Database\Eloquent\Collection
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:      * Get the first Model's given attribute
362:      * @param  string     $name
363:      * @return mixed|null
364:      */
365:     public function __get($name)
366:     {
367:         $model = $this->first();
368: 
369:         return $model ? $model->$name : null;
370:     }
371: 
372:     /**
373:      * Alias to tagparams
374:      *
375:      * @param  array                                    $params
376:      * @return \Illuminate\Database\Eloquent\Collection
377:      */
378:     public function __invoke(array $params)
379:     {
380:         return $this->tagparams($params);
381:     }
382: }
383: 
API documentation generated by ApiGen 2.8.0