1: <?php
2:
3: namespace Charcoal\Cms\Service\Manager;
4:
5:
6: use Charcoal\Model\Collection;
7: use Charcoal\Model\Model;
8:
9:
10: use Charcoal\Object\CategoryInterface;
11: use Charcoal\Object\CategoryTrait;
12:
13:
14: use Charcoal\Cms\EventCategory;
15: use Charcoal\Cms\Config\CmsConfig;
16: use Charcoal\Cms\EventInterface;
17: use Charcoal\Cms\Service\Loader\EventLoader;
18:
19:
20: use DateTime;
21: use DateTimeInterface;
22: use Exception;
23:
24: 25: 26:
27: class EventManager extends AbstractManager
28: {
29: use CategoryTrait;
30:
31:
32: private $currentEvent;
33:
34:
35: private $currentPage;
36:
37:
38: private $numPerPage = 0;
39:
40:
41: private $numPage;
42:
43:
44: private $entryCycle = false;
45:
46:
47: private $nextEvent;
48:
49:
50: private $prevEvent;
51:
52:
53: private $page = 0;
54:
55:
56: private $category = 0;
57:
58:
59: private $all = [];
60:
61:
62: private $entries = [];
63:
64:
65: private $archive = [];
66:
67:
68: private $entry;
69:
70:
71: private $objType;
72:
73:
74: private $featIdent;
75:
76:
77: private $featList = [];
78:
79:
80: private $loader;
81:
82:
83: private $mapEvents = [];
84:
85:
86: private $date;
87:
88:
89: private $year;
90:
91:
92: private $month;
93:
94:
95: private $day;
96:
97: 98: 99: 100: 101:
102: public function __construct(array $data)
103: {
104: parent::__construct($data);
105:
106: if (!isset($data['event/loader'])) {
107: throw new Exception('Event Loader must be defined in the EventManager constructor.');
108: }
109:
110: $this->setLoader($data['event/loader']);
111:
112:
113: $eventConfig = $this->adminConfig()->eventConfig();
114:
115:
116: $this->setNumPerPage($eventConfig->get('numPerPage'));
117: $this->setEntryCycle($eventConfig->get('entryCycle'));
118: $this->setObjType($eventConfig->get('objType'));
119: $this->setCategoryItemType($eventConfig->get('category'));
120: $this->setFeatIdent($eventConfig->get('configFeatIdent'));
121: }
122:
123: 124: 125: 126:
127: public function entries()
128: {
129:
130: $loader = $this->loader()->upcoming();
131:
132:
133: $page = $this->page();
134:
135:
136: $cat = $this->category();
137: $date = $this->date();
138: $year = $this->year();
139: $month = $this->month();
140: $day = $this->day();
141:
142:
143: if ($year && $month && $day && !$date) {
144: $date = new DateTime($year.'-'.$month.'-'.$day);
145: }
146:
147:
148: $extraSql = '';
149: if ($cat) {
150: $extraSql = '
151: AND
152: \''.$cat.'\' IN (category)';
153: }
154:
155:
156: if ($date) {
157: $loader = $this->loader()->all();
158: $proto = $this->loader()->proto();
159: $table = $proto->source()->table();
160: $q = 'SELECT * FROM '.$table.'
161: WHERE
162: \''.$date->format('Y-m-d').'\'
163: BETWEEN
164: DATE(start_date) AND DATE(end_date)
165: AND
166: active = 1'.$extraSql;
167:
168: $collection = $loader->loadFromQuery($q);
169:
170: return $collection;
171: }
172:
173:
174: if ($year && !$month) {
175: $loader = $this->loader()->all();
176: $proto = $this->loader()->proto();
177: $table = $proto->source()->table();
178: $q = 'SELECT * FROM '.$table.'
179: WHERE
180: \''.$this->year().'\' = YEAR(start_date)
181: OR
182: \''.$this->year().'\' = YEAR(end_date)
183: AND
184: active = 1'.$extraSql;
185:
186: $collection = $loader->loadFromQuery($q);
187:
188: return $collection;
189: }
190:
191:
192: if ($year && $month) {
193: $between = new DateTime($year.'-'.$month.'-01');
194: $loader = $this->loader()->all();
195: $proto = $this->loader()->proto();
196: $table = $proto->source()->table();
197: $q = 'SELECT * FROM '.$table.'
198: WHERE
199: \''.$between->format('Y-m-d H:i:s').'\'
200: BETWEEN
201: CAST(CONCAT(YEAR(start_date), \'-\', MONTH(start_date), \'-\', 01) AS DATETIME)
202: AND
203: CAST(CONCAT(YEAR(end_date), \'-\', MONTH(end_date), \'-\', 01) AS DATETIME)
204: AND
205: active = 1'.$extraSql;
206:
207: $collection = $loader->loadFromQuery($q);
208:
209: return $collection;
210: }
211:
212: if (isset($this->entries[$cat])) {
213: if (isset($this->entries[$cat][$page])) {
214: return $this->entries[$cat][$page];
215: }
216: }
217:
218: if ($this->category()) {
219: $loader->addFilter('category', $this->category(), [ 'operator' => 'in' ]);
220: }
221:
222: if ($this->numPerPage()) {
223: $loader->setPage($page);
224: $loader->setNumPerPage($this->numPerPage());
225: }
226: $this->entries[$cat][$page] = $loader->load();
227:
228: return $this->entries[$cat][$page];
229: }
230:
231: 232: 233: 234:
235: public function entry($id = null)
236: {
237: if (!$id) {
238: return $this->currentEvent();
239: }
240:
241: if (!isset($this->entry[$id])) {
242:
243: $model = $this->modelFactory();
244:
245: $entry = $model->get($this->objType())->loadfrom('id', $id);
246: $this->entry[$id] = $entry->id() ? $entry : $this->currentEvent();
247: }
248:
249: return $this->entry[$id];
250: }
251:
252: 253: 254: 255:
256: public function all()
257: {
258: if ($this->all) {
259: return $this->all;
260: }
261:
262: $this->all = $this->loader()->all()
263: ->addOrder('start_date', 'asc')->load();
264:
265: return $this->all;
266: }
267:
268: 269: 270:
271: public function loadCategoryItems()
272: {
273:
274: $model = $this->modelFactory();
275: $proto = $model->get($this->categoryItemType());
276: $loader = $this->collectionLoader()->setModel($proto);
277: $loader->addFilter('active', true);
278:
279: return $loader->load();
280: }
281:
282: 283: 284: 285:
286: public function categoryItem($id)
287: {
288: $category = $this->modelFactory()->get($this->categoryItemType());
289:
290: return $category->load($id);
291: }
292:
293: 294: 295: 296: 297: 298:
299: public function featList(array $options = [])
300: {
301: if ($this->featList) {
302: return $this->featList;
303: }
304:
305: $loader = $this->loader()->published();
306: $ident = $this->featIdent();
307: $config = $this->adminConfig();
308:
309: if (!$ident || !method_exists($config, $ident)) {
310: throw new Exception(sprintf(
311: 'The featured news ident "%s" doesn\'t exist the class "%s"',
312: $ident,
313: get_class($config)
314: ));
315: }
316: $ids = $config->{$ident}();
317:
318: if (!$ids) {
319: return null;
320: }
321:
322: $ids = explode(',', $ids);
323:
324: $loader->addFilter('id', $ids, [ 'operator' => 'in' ])
325: ->addOrder('id', 'values', [ 'values' => $ids ]);
326:
327: if (count($options) > 0) {
328: foreach ($options as $key => $option) {
329: switch ($key) {
330: case 'filters':
331: $filters = $option;
332: foreach ($filters as $f) {
333: $filter[] = $f['property'] ?: '';
334: $filter[] = $f['val'] ?: '';
335: $filter[] = $f['options'] ?: '';
336: $filter = join(',', $filter);
337:
338: $loader->addFilter($filter);
339: }
340: break;
341: case 'page':
342: $loader->setPage($option);
343: break;
344: case 'numPerPage':
345: $loader->setNumPerPage($option);
346: break;
347: }
348: }
349: }
350:
351: $this->featList = $loader->load();
352:
353: return $this->featList;
354: }
355:
356: 357: 358:
359: public function archive()
360: {
361: $page = $this->page();
362: $cat = $this->category();
363: if (isset($this->archive[$cat])) {
364: if (isset($this->archive[$cat][$page])) {
365: return $this->archive[$cat][$page];
366: }
367: }
368:
369: $loader = $this->loader()->archive();
370:
371: if ($this->category()) {
372: $loader->addFilter('category', $this->category(), [ 'operator' => 'in' ]);
373: }
374: if ($this->numPerPage()) {
375: $loader->setPage($this->page());
376: $loader->setNumPerPage($this->numPerPage());
377: }
378:
379: $this->archive[$cat][$page] = $loader->load();
380:
381: return $this->archive[$cat][$page];
382: }
383:
384: 385: 386: 387:
388: public function latest()
389: {
390: $entries = $this->entries();
391:
392: if (isset($entries[0])) {
393: return $entries[0];
394: } else {
395:
396: return [];
397: }
398: }
399:
400: 401: 402:
403: public function prev()
404: {
405: if ($this->prevEvent) {
406: return $this->prevEvent;
407: } else {
408: return $this->setPrevNext()->prevEvent;
409: }
410: }
411:
412: 413: 414:
415: public function next()
416: {
417: if ($this->nextEvent) {
418: return $this->nextEvent;
419: } else {
420: return $this->setPrevNext()->nextEvent;
421: }
422: }
423:
424: 425: 426:
427: public function currentPage()
428: {
429: if ($this->currentPage) {
430: return $this->currentPage;
431: }
432: if (!$this->currentEvent() || !$this->currentEvent()['id']) {
433: $this->currentPage = 1;
434:
435: return 1;
436: }
437: $all = $this->all();
438: $i = 0;
439: foreach ($all as $event) {
440: $i++;
441: if ($event->id() == $this->currentEvent()['id']) {
442: break;
443: }
444: }
445:
446: $this->currentPage = $this->numPerPage() ? ceil($i / $this->numPerPage()) : 1;
447:
448: return $this->currentPage;
449: }
450:
451: 452: 453: 454:
455: public function getEventsByDate($date)
456: {
457: if (!($date instanceof DateTimeInterface)) {
458: $date = new DateTime($date);
459: }
460:
461: $map = $this->mapEvents();
462: $year = $date->format('Y');
463: $month = $date->format('m');
464: $day = $date->format('d');
465:
466: if (isset($map[$year][$month][$day])) {
467: return $map[$year][$month][$day];
468: }
469:
470: return [];
471: }
472:
473:
474:
475:
476:
477: 478: 479:
480: public function currentEvent()
481: {
482: if (!$this->currentEvent) {
483: $this->currentEvent = $this->latest();
484: }
485:
486: return $this->currentEvent;
487: }
488:
489: 490: 491:
492: public function numPerPage()
493: {
494: return $this->numPerPage;
495: }
496:
497: 498: 499:
500: public function entryCycle()
501: {
502: return $this->entryCycle;
503: }
504:
505: 506: 507: 508:
509: public function numEvent()
510: {
511: return !!(count($this->entries()));
512: }
513:
514: 515: 516: 517:
518: public function numPages()
519: {
520: if ($this->numPage) {
521: $this->numPage;
522: };
523:
524: $entries = $this->entries();
525: $count = count($entries);
526:
527: if ($this->numPerPage()) {
528: $this->numPage = ceil($count / $this->numPerPage());
529: } else {
530: $this->numPage = 1;
531: }
532:
533: return $this->numPage;
534: }
535:
536: 537: 538: 539:
540: public function hasPager()
541: {
542: return ($this->numPages() > 1);
543: }
544:
545: 546: 547:
548: public function page()
549: {
550: return $this->page;
551: }
552:
553: 554: 555:
556: public function category()
557: {
558: return $this->category;
559: }
560:
561: 562: 563:
564: public function objType()
565: {
566: return $this->objType;
567: }
568:
569: 570: 571:
572: public function featIdent()
573: {
574: return $this->featIdent;
575: }
576:
577: 578: 579:
580: public function loader()
581: {
582: return $this->loader;
583: }
584:
585: 586: 587: 588:
589: public function date()
590: {
591: return $this->date;
592: }
593:
594: 595: 596: 597:
598: public function year()
599: {
600: return $this->year;
601: }
602:
603: 604: 605: 606:
607: public function month()
608: {
609: return $this->month;
610: }
611:
612: 613: 614: 615:
616: public function day()
617: {
618: return $this->day;
619: }
620:
621:
622:
623:
624:
625: 626: 627: 628:
629: public function setCurrentEvent($currentEvent)
630: {
631: $this->currentEvent = $currentEvent;
632:
633: return $this;
634: }
635:
636: 637: 638: 639:
640: public function setNumPerPage($numPerPage)
641: {
642: $this->numPerPage = $numPerPage;
643:
644: return $this;
645: }
646:
647: 648: 649: 650:
651: public function setEntryCycle($entryCycle)
652: {
653: $this->entryCycle = $entryCycle;
654:
655: return $this;
656: }
657:
658: 659: 660: 661:
662: public function setPage($page)
663: {
664: $this->page = $page;
665:
666: return $this;
667: }
668:
669: 670: 671: 672:
673: public function setCategory($category)
674: {
675: $this->category = $category;
676:
677: return $this;
678: }
679:
680: 681: 682: 683:
684: public function setObjType($objType)
685: {
686: $this->objType = $objType;
687:
688: return $this;
689: }
690:
691: 692: 693: 694:
695: public function setFeatIdent($featIdent)
696: {
697: $this->featIdent = $featIdent;
698:
699: return $this;
700: }
701:
702: 703: 704: 705:
706: public function setLoader($loader)
707: {
708: $this->loader = $loader;
709:
710: return $this;
711: }
712:
713: 714: 715: 716: 717:
718: public function setDate(DateTime $date)
719: {
720: $this->date = $date;
721:
722: return $this;
723: }
724:
725: 726: 727: 728: 729: 730:
731: public function setYear($year)
732: {
733: if (!is_scalar($year)) {
734: throw new Exception('Year must be a string or an integer in EventManager setYear method.');
735: }
736: $this->year = $year;
737:
738: return $this->year;
739: }
740:
741: 742: 743: 744: 745: 746:
747: public function setMonth($month)
748: {
749: if (!is_scalar($month)) {
750: throw new Exception('Month must be a string or an integer in EventManager setMonth method.');
751: }
752: $this->month = $month;
753:
754: return $this;
755: }
756:
757: 758: 759: 760: 761: 762:
763: public function setDay($day)
764: {
765: if (!is_scalar($day)) {
766: throw new Exception('Day must be a string or an integer in EventManager setDay method.');
767: }
768: $this->day = $day;
769:
770: return $this;
771: }
772:
773:
774:
775:
776:
777: 778: 779: 780:
781: public function setPrevNext()
782: {
783: if ($this->prevEvent && $this->nextEvent) {
784: return $this;
785: }
786: $entries = $this->entries();
787:
788: $isPrev = false;
789: $isNext = false;
790: $firstEvent = false;
791: $lastEvent = false;
792:
793: foreach ($entries as $event) {
794:
795: if (!$firstEvent) {
796: $firstEvent = $event;
797: }
798: $lastEvent = $event;
799:
800: if ($event->id() == $this->currentEvent()['id']) {
801: $isNext = true;
802: $isPrev = true;
803:
804: continue;
805: }
806: if (!$isPrev) {
807: $this->prevEvent = $event;
808: }
809:
810: if ($isNext) {
811: $this->nextEvent = $event;
812:
813: $isNext = false;
814: }
815: }
816:
817: if ($this->entryCycle()) {
818: if (!$this->nextEvent) {
819: $this->nextEvent = $firstEvent;
820: }
821:
822: if (!$this->prevEvent) {
823: $this->prevEvent = $lastEvent;
824: }
825: }
826:
827: return $this;
828: }
829:
830: 831: 832: 833:
834: public function mapEvents()
835: {
836: if ($this->mapEvents) {
837: return $this->mapEvents;
838: }
839:
840: $events = $this->all();
841:
842: $out = [];
843: foreach ($events as $ev) {
844: $firstDate = $ev->startDate();
845: $lastDate = $ev->endDate();
846:
847: $current = new DateTime();
848: $current->setTimestamp($firstDate->getTimestamp());
849:
850: while ($current <= $lastDate) {
851: $year = $current->format('Y');
852: $month = $current->format('m');
853: $day = $current->format('d');
854:
855: if (!isset($out[$year])) {
856: $out[$year] = [];
857: }
858:
859: if (!isset($out[$year][$month])) {
860: $out[$year][$month] = [];
861: }
862:
863: if (!isset($out[$year][$month][$day])) {
864: $out[$year][$month][$day] = [];
865: }
866:
867: $out[$year][$month][$day][] = $ev;
868:
869: $current->modify('+1 day');
870: }
871: }
872:
873: $this->mapEvents = $out;
874:
875: return $this->mapEvents;
876: }
877: }
878: