1: <?php
2:
3: 4: 5: 6: 7: 8:
9:
10: namespace rsanchez\Deep\Model;
11:
12: use Illuminate\Database\Eloquent\Model;
13: use Illuminate\Database\Eloquent\Builder;
14: use rsanchez\Deep\Collection\CategoryCollection;
15: use rsanchez\Deep\Repository\CategoryFieldRepository;
16: use rsanchez\Deep\Repository\ChannelRepository;
17: use rsanchez\Deep\Model\JoinableTrait;
18:
19: 20: 21:
22: class Category extends Model
23: {
24: use JoinableTrait;
25:
26: 27: 28: 29: 30:
31: protected $table = 'categories';
32:
33: 34: 35: 36: 37:
38: protected $primaryKey = 'cat_id';
39:
40: 41: 42: 43:
44: protected $nested = false;
45:
46: 47: 48: 49:
50: protected $childCategoryCollection;
51:
52: 53: 54: 55:
56: protected static $categoryFieldRepository;
57:
58: 59: 60: 61:
62: protected static $channelRepository;
63:
64: 65: 66: 67: 68:
69: public function getChildrenAttribute()
70: {
71: if (is_null($this->childCategoryCollection)) {
72: $this->childCategoryCollection = new CategoryCollection();
73: }
74:
75: return $this->childCategoryCollection;
76: }
77:
78: 79: 80: 81:
82: public function hasChildren()
83: {
84: return ! $this->children->isEmpty();
85: }
86:
87: 88: 89: 90: 91:
92: public static function setCategoryFieldRepository(CategoryFieldRepository $categoryFieldRepository)
93: {
94: self::$categoryFieldRepository = $categoryFieldRepository;
95: }
96:
97: 98: 99: 100: 101:
102: public static function setChannelRepository(ChannelRepository $channelRepository)
103: {
104: self::$channelRepository = $channelRepository;
105: }
106:
107: 108: 109: 110: 111: 112:
113: public function scopeWithFields(Builder $query)
114: {
115: return $this->requireTable($query, 'category_field_data');
116: }
117:
118: 119: 120:
121: protected static function joinTables()
122: {
123: return array(
124: 'category_field_data' => function ($query) {
125: $query->join('category_field_data', 'category_field_data.cat_id', '=', 'categories.cat_id');
126: },
127: );
128: }
129:
130: 131: 132: 133:
134: public function entries()
135: {
136: return $this->belongsToMany('\\rsanchez\\Deep\\Model\\Title', 'category_posts', 'entry_id', 'cat_id');
137: }
138:
139: 140: 141: 142: 143:
144: public function getAttribute($name)
145: {
146: if (! isset($this->attributes[$name]) && self::$categoryFieldRepository->hasField($name)) {
147: $name = 'field_id_'.self::$categoryFieldRepository->getFieldId($name);
148: }
149:
150: return parent::getAttribute($name);
151: }
152:
153: 154: 155:
156: public function attributesToArray()
157: {
158: $array = parent::attributesToArray();
159:
160: foreach ($array as $key => $value) {
161: if (strncmp($key, 'field_id_', 9) === 0) {
162: $id = substr($key, 9);
163:
164: if (self::$categoryFieldRepository->hasFieldId($id)) {
165: $array[self::$categoryFieldRepository->getFieldName($id)] = $value;
166: }
167:
168: unset($array[$key]);
169: }
170: }
171:
172: return $array;
173: }
174:
175: 176: 177: 178: 179: 180:
181: public function newCollection(array $models = array())
182: {
183: if ($this->nested) {
184: $collection = new CategoryCollection();
185:
186: $modelsByKey = array();
187: $childrenByParentId = array();
188:
189: foreach ($models as $model) {
190: $modelsByKey[$model->cat_id] = $model;
191:
192: if ($model->parent_id) {
193: if (isset($modelsByKey[$model->parent_id])) {
194: $modelsByKey[$model->parent_id]->children->push($model);
195: } else {
196: $childrenByParentId[$model->parent_id][] = $model;
197: }
198: } else {
199: if (isset($childrenByParentId[$model->cat_id])) {
200: foreach ($childrenByParentId[$model->cat_id] as $child) {
201: $model->children->push($child);
202: }
203:
204: unset($childrenByParentId[$model->cat_id]);
205: }
206:
207: $collection->push($model);
208: }
209: }
210:
211: $this->nested = false;
212:
213: return $collection;
214: }
215:
216: return new CategoryCollection($models);
217: }
218:
219: 220: 221: 222: 223: 224: 225:
226: public function scopeCategoryId(Builder $query, $categoryId)
227: {
228: $categoryIds = array_slice(func_get_args(), 1);
229:
230: return $query->whereIn('categories.cat_id', $categoryIds);
231: }
232:
233: 234: 235: 236: 237: 238: 239:
240: public function scopeNotCategoryId(Builder $query, $categoryId)
241: {
242: $categoryIds = array_slice(func_get_args(), 1);
243:
244: return $query->whereNotIn('categories.cat_id', $categoryIds);
245: }
246:
247: 248: 249: 250: 251: 252: 253:
254: public function scopeCategoryName(Builder $query, $categoryName)
255: {
256: $categoryNames = array_slice(func_get_args(), 1);
257:
258: return $query->whereIn('categories.cat_name', $categoryNames);
259: }
260:
261: 262: 263: 264: 265: 266: 267:
268: public function scopeNotCategoryName(Builder $query, $categoryName)
269: {
270: $categoryNames = array_slice(func_get_args(), 1);
271:
272: return $query->whereNotIn('categories.cat_name', $categoryNames);
273: }
274:
275: 276: 277: 278: 279: 280: 281:
282: public function scopeCategoryGroup(Builder $query, $groupId)
283: {
284: $groupIds = array_slice(func_get_args(), 1);
285:
286: return $query->whereIn('categories.group_id', $groupIds);
287: }
288:
289: 290: 291: 292: 293: 294: 295:
296: public function scopeNotCategoryGroup(Builder $query, $groupId)
297: {
298: $groupIds = array_slice(func_get_args(), 1);
299:
300: return $query->whereNotIn('categories.group_id', $groupIds);
301: }
302:
303: 304: 305: 306: 307: 308: 309:
310: public function scopeCategoryIdString(Builder $query, $string)
311: {
312: return $this->scopeArrayFromString($query, $string, 'CategoryId');
313: }
314:
315: 316: 317: 318: 319: 320: 321:
322: public function scopeCategoryGroupString(Builder $query, $string)
323: {
324: return $this->scopeArrayFromString($query, $string, 'CategoryGroup');
325: }
326:
327: 328: 329: 330: 331: 332: 333:
334: public function scopeCategoryNameString(Builder $query, $string)
335: {
336: return $this->scopeArrayFromString($query, $string, 'CategoryName');
337: }
338:
339: 340: 341: 342: 343: 344: 345:
346: public function scopeLimit(Builder $query, $limit)
347: {
348: return $query->take($limit);
349: }
350:
351: 352: 353: 354: 355: 356: 357:
358: public function scopeOffset(Builder $query, $offset)
359: {
360: return $query->skip($offset);
361: }
362:
363: 364: 365: 366: 367: 368: 369:
370: public function scopeParentOnly(Builder $query, $parentsOnly = true)
371: {
372: return $parentsOnly ? $query->where('parent_id', 0) : $query;
373: }
374:
375: 376: 377: 378: 379: 380: 381:
382: public function scopeParentOnlyString(Builder $query, $string)
383: {
384: return $this->scopeParentOnly($query, $string === 'yes');
385: }
386:
387: 388: 389: 390: 391: 392: 393:
394: public function scopeChannel(Builder $query, $channelName)
395: {
396: $channelNames = array_slice(func_get_args(), 1);
397:
398: $channels = self::$channelRepository->getChannelsByName($channelNames);
399:
400: $groupIds = array();
401:
402: $channels->each(function ($channel) use (&$groupIds) {
403: $groupIds += $channel->cat_group;
404: });
405:
406: if ($groupIds) {
407: array_unshift($groupIds, $query);
408:
409: call_user_func_array(array($this, 'scopeCategoryGroup'), $groupIds);
410: }
411:
412: return $query;
413: }
414:
415: 416: 417: 418: 419: 420: 421:
422: public function scopeNotChannel(Builder $query, $channelName)
423: {
424: $channelNames = array_slice(func_get_args(), 1);
425:
426: $channels = self::$channelRepository->getChannelsByName($channelNames);
427:
428: $groupIds = array();
429:
430: $channels->each(function ($channel) use (&$groupIds) {
431: $groupIds += $channel->cat_group;
432: });
433:
434: if ($groupIds) {
435: array_unshift($groupIds, $query);
436:
437: call_user_func_array(array($this, 'scopeNotCategoryGroup'), $groupIds);
438: }
439:
440: return $query;
441: }
442:
443: 444: 445: 446: 447: 448: 449:
450: public function scopeChannelString(Builder $query, $string)
451: {
452: return $this->scopeArrayFromString($query, $string, 'Channel');
453: }
454:
455: 456: 457: 458: 459: 460: 461:
462: public function scopeEntryChannel(Builder $query, $channelName)
463: {
464: $channelNames = array_slice(func_get_args(), 1);
465:
466: $channels = self::$channelRepository->getChannelsByName($channelNames);
467:
468: $channelIds = array();
469:
470: $channels->each(function ($channel) use (&$channelIds) {
471: $channelIds[] = $channel->channel_id;
472: });
473:
474: if ($channelIds) {
475: $query->whereHas('entries', function ($q) use ($channelIds) {
476: $q->whereIn('channel_titles.channel_id', $channelIds);
477: });
478: }
479:
480: return $query;
481: }
482:
483: 484: 485: 486: 487: 488: 489:
490: public function scopeNotEntryChannel(Builder $query, $channelName)
491: {
492: $channelNames = array_slice(func_get_args(), 1);
493:
494: $channels = self::$channelRepository->getChannelsByName($channelNames);
495:
496: $channelIds = array();
497:
498: $channels->each(function ($channel) use (&$channelIds) {
499: $channelIds[] = $channel->channel_id;
500: });
501:
502: if ($channelIds) {
503: $query->whereHas('entries', function ($q) use ($channelIds) {
504: $q->whereNotIn('channel_titles.channel_id', $channelIds);
505: });
506: }
507:
508: return $query;
509: }
510:
511: 512: 513: 514: 515: 516: 517:
518: public function scopeEntryChannelString(Builder $query, $string)
519: {
520: return $this->scopeArrayFromString($query, $string, 'EntryChannel');
521: }
522:
523: 524: 525: 526: 527: 528: 529:
530: public function scopeShowEmpty(Builder $query, $showEmpty = true)
531: {
532: return $showEmpty ? $query : $query->whereHas('entries');
533: }
534:
535: 536: 537: 538: 539: 540: 541:
542: public function scopeShowEmptyString(Builder $query, $string)
543: {
544: return $this->scopeShowEmpty($query, $string === 'yes');
545: }
546:
547: 548: 549: 550: 551: 552: 553:
554: public function scopeShowExpired(Builder $query, $showExpired = true)
555: {
556: if ($showExpired) {
557: return $query;
558: }
559:
560: $prefix = $query->getQuery()->getConnection()->getTablePrefix();
561:
562: return $query->whereHas('entries', function ($q) {
563: $q->whereRaw(
564: "(`{$prefix}channel_titles`.`expiration_date` = '' OR `{$prefix}channel_titles`.`expiration_date` > NOW())"
565: );
566: });
567: }
568:
569: 570: 571: 572: 573: 574: 575:
576: public function scopeShowExpiredString(Builder $query, $string)
577: {
578: return $this->scopeShowExpired($query, $string === 'yes');
579: }
580:
581: public function scopeShowFutureEntries(Builder $query, $showFutureEntries = true)
582: {
583: if ($showFutureEntries) {
584: return $query;
585: }
586:
587: $prefix = $query->getQuery()->getConnection()->getTablePrefix();
588:
589: return $query->whereHas('entries', function ($q) {
590: $q->whereRaw(
591: "(`{$prefix}channel_titles`.`expiration_date` = '' OR `{$prefix}channel_titles`.`expiration_date` > NOW())"
592: );
593: });
594: }
595:
596: 597: 598: 599: 600: 601: 602:
603: public function scopeShowFutureEntriesString(Builder $query, $string)
604: {
605: return $this->scopeShowFutureEntries($query, $string === 'yes');
606: }
607:
608: 609: 610: 611: 612: 613: 614:
615: public function scopeStatus(Builder $query, $status)
616: {
617: $statuses = array_slice(func_get_args(), 1);
618:
619: return $query->whereHas('entries', function ($q) use ($statuses) {
620: return $q->whereIn('status', $statuses);
621: });
622: }
623:
624: 625: 626: 627: 628: 629: 630:
631: public function scopeNotStatus(Builder $query, $status)
632: {
633: $statuses = array_slice(func_get_args(), 1);
634:
635: return $query->whereHas('entries', function ($q) use ($statuses) {
636: return $q->whereNotIn('status', $statuses);
637: });
638: }
639:
640: 641: 642: 643: 644: 645: 646:
647: public function scopeStatusString(Builder $query, $string)
648: {
649: return $this->scopeArrayFromString($query, $string, 'Status');
650: }
651:
652: 653: 654: 655: 656: 657: 658: 659:
660: public function scopeTagparam(Builder $query, $key, $value)
661: {
662: 663: 664: 665:
666: static $parameterMap = array(
667: 'show' => 'categoryIdString',
668: 'category_name' => 'categoryNameString',
669: 'category_group' => 'categoryGroupString',
670: 'channel' => 'channelString',
671: 'limit' => 'limit',
672: 'offset' => 'offset',
673: 'parent_only' => 'parentOnlyString',
674:
675: 'show_empty' => 'showEmptyString',
676: 'show_expired' => 'showExpiredString',
677: 'show_future_entries' => 'showFutureEntriesString',
678: 'status' => 'statusString',
679: 'style' => 'styleString',
680: );
681:
682: if (! array_key_exists($key, $parameterMap)) {
683: return $query;
684: }
685:
686: $method = 'scope'.ucfirst($parameterMap[$key]);
687:
688: return $this->$method($query, $value);
689: }
690:
691: 692: 693: 694: 695: 696: 697:
698: public function scopeTagparams(Builder $query, array $parameters)
699: {
700: $showEmpty = ! isset($parameters['show_empty']) || $parameters['show_empty'] === 'yes';
701: $restrictChannel = ! isset($parameters['restrict_channel']) || $parameters['restrict_channel'] === 'yes';
702:
703: if ($showEmpty) {
704: unset($parameters['status'], $parameters['show_expired'], $parameters['show_future_entries']);
705: } else {
706: if ($restrictChannel && isset($parameters['channel'])) {
707: $query->entryChannelString($parameters['channel']);
708: }
709: }
710:
711:
712: if (! empty($parameters['orderby'])) {
713: $directions = isset($parameters['sort']) ? explode('|', $parameters['sort']) : null;
714:
715: foreach (explode('|', $parameters['orderby']) as $i => $column) {
716: $direction = isset($directions[$i]) ? $directions[$i] : 'asc';
717: $query->orderBy($column, $direction);
718: }
719: }
720:
721: foreach ($parameters as $key => $value) {
722: $this->scopeTagparam($query, $key, $value);
723: }
724:
725: return $query;
726: }
727:
728: public function scopeStyleString(Builder $query, $string)
729: {
730: return $string === 'nested' ? $this->scopeNested($query) : $query;
731: }
732:
733: 734: 735: 736: 737: 738:
739: public function scopeNested(Builder $query)
740: {
741: $this->nested = true;
742:
743: return $query;
744: }
745:
746: 747: 748: 749: 750: 751: 752: 753: 754:
755: protected function scopeArrayFromString(Builder $query, $string, $scope)
756: {
757: if ($not = strncmp($string, 'not ', 4) === 0) {
758: $string = substr($string, 4);
759: }
760:
761: $args = explode('|', $string);
762:
763: $method = 'scope'.$scope;
764:
765: if ($not && method_exists($this, 'scopeNot'.$scope)) {
766: $method = 'scopeNot'.$scope;
767: }
768:
769: array_unshift($args, $query);
770:
771: return call_user_func_array(array($this, $method), $args);
772: }
773:
774: 775: 776: 777: 778:
779: public function getFields()
780: {
781: return self::$categoryFieldRepository->getFields();
782: }
783: }
784: