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\Model\Channel;
15: use rsanchez\Deep\Collection\EntryCollection;
16: use rsanchez\Deep\Repository\FieldRepository;
17: use Carbon\Carbon;
18:
19: 20: 21:
22: class Entry extends Title
23: {
24: 25: 26: 27:
28: protected $collectionClass = '\\rsanchez\\Deep\\Collection\\EntryCollection';
29:
30: 31: 32: 33:
34: public static $fieldRepository;
35:
36: 37: 38: 39: 40:
41: public static function setFieldRepository(FieldRepository $fieldRepository)
42: {
43: self::$fieldRepository = $fieldRepository;
44: }
45:
46: 47: 48: 49: 50: 51: 52: 53:
54: public function newQuery($excludeDeleted = true)
55: {
56: $query = parent::newQuery($excludeDeleted);
57:
58: $query->join('channel_data', 'channel_titles.entry_id', '=', 'channel_data.entry_id');
59:
60: return $query;
61: }
62:
63: 64: 65:
66: public function newCollection(array $models = array())
67: {
68: $method = "{$this->collectionClass}::createWithFields";
69:
70: $collection = call_user_func($method, $models, self::$channelRepository, self::$fieldRepository);
71:
72: if ($models) {
73: $this->hydrateCollection($collection);
74: }
75:
76: return $collection;
77: }
78:
79: 80: 81: 82: 83:
84: protected function getArrayableAttributes()
85: {
86: $attributes = $this->attributes;
87:
88: foreach ($attributes as $key => $value) {
89: if ($attributes[$key] instanceof Carbon) {
90: $attributes[$key] = (string) $attributes[$key];
91: }
92: }
93:
94: return $this->getArrayableItems($attributes);
95: }
96:
97: 98: 99:
100: public function toArray()
101: {
102: $array = parent::toArray();
103:
104:
105: foreach ($this->attributes as $key => $value) {
106: if (preg_match('#^field_(id|dt|ft)_#', $key)) {
107: unset($array[$key]);
108: }
109: }
110:
111: $this->channel->fields->each(function ($field) use (&$array) {
112: if (isset($array[$field->field_name]) && method_exists($array[$field->field_name], 'toArray')) {
113: $array[$field->field_name] = $array[$field->field_name]->toArray();
114: }
115: });
116:
117: return $array;
118: }
119:
120: 121: 122: 123: 124: 125: 126: 127:
128: public function scopeSearch(Builder $query, $fieldName, $value)
129: {
130: $values = array_slice(func_get_args(), 2);
131:
132: $model = $this;
133:
134: $query->where(function ($subquery) use ($model, $fieldName, $values) {
135: foreach ($values as $value) {
136: call_user_func(array($model, 'scopeOrWhereFieldContains'), $subquery, $fieldName, $value);
137: }
138: });
139:
140: return $query;
141: }
142:
143: 144: 145: 146: 147: 148: 149: 150:
151: public function scopeSearchString(Builder $query, $fieldName, $string)
152: {
153: if (! $string) {
154: return $query;
155: }
156:
157: if (! self::$fieldRepository->hasField($fieldName)) {
158: return $query;
159: }
160:
161: if (preg_match('#^(>|>=|<|<=)(.+)$#', $string, $match)) {
162: $comparison = true;
163: $operator = $match[1];
164: $string = $match[1];
165: } else {
166: $comparison = false;
167: }
168:
169:
170: if ($comparison) {
171: return $this->scopeWhereField($query, $fieldName, $operator, $string);
172: }
173:
174: if (strncmp($string, '=', 1) === 0) {
175: $contains = false;
176: $string = substr($string, 1);
177: } else {
178: $contains = true;
179: }
180:
181: if (strncmp($string, 'not ', 4) === 0) {
182: $not = true;
183: $string = substr($string, 4);
184: } else {
185: $not = false;
186: }
187:
188: $and = $contains && strpos($string, '&&') !== false;
189:
190: $separator = $and ? '&&' : '|';
191:
192: $values = explode($separator, str_replace('IS_EMPTY', '', $string));
193:
194: if (! $contains) {
195: $method = $not ? 'scopeWhereFieldNotIn' : 'scopeWhereFieldIn';
196:
197: return call_user_func_array(array($this, $method), array($query, $fieldName, $values));
198: }
199:
200: if ($and) {
201: $method = $not ? 'scopeWhereFieldDoesNotContain' : 'scopeWhereFieldContains';
202: } else {
203: $method = $not ? 'scopeOrWhereFieldDoesNotContain' : 'scopeOrWhereFieldContains';
204: }
205:
206: $model = $this;
207:
208: return $query->where(function ($subquery) use ($model, $fieldName, $method, $values) {
209: foreach ($values as $value) {
210: $suffix = '';
211:
212: if (preg_match('#^(.+)\\\W$#', $value, $match)) {
213: $value = $match[1];
214: $suffix = 'WholeWord';
215: }
216:
217: call_user_func(array($model, $method.$suffix), $subquery, $fieldName, $value);
218: }
219: });
220: }
221:
222: 223: 224:
225: public function scopeTagparams(Builder $query, array $parameters, array $request = array())
226: {
227: if (! empty($parameters['orderby'])) {
228: $directions = isset($parameters['sort']) ? explode('|', $parameters['sort']) : null;
229:
230: foreach (explode('|', $parameters['orderby']) as $i => $column) {
231: $direction = isset($directions[$i]) ? $directions[$i] : 'asc';
232:
233: if (self::$fieldRepository->hasField($column)) {
234: $column = 'channel_data.field_id_'.self::$fieldRepository->getFieldId($column);
235:
236: $query->orderBy($column, $direction);
237: } else {
238: $query->orderBy($column, $direction);
239: }
240: }
241:
242: unset($parameters['orderby']);
243: }
244:
245: return parent::scopeTagparams($query, $parameters, $request);
246: }
247:
248: 249: 250:
251: public function scopeTagparam(Builder $query, $key, $value)
252: {
253: if (strncmp($key, 'search:', 7) === 0) {
254: return $this->scopeSearchString($query, substr($key, 7), $value);
255: }
256:
257: return parent::scopeTagparam($query, $key, $value);
258: }
259:
260: 261: 262: 263: 264: 265: 266: 267:
268: protected function scopeWhereFieldHandler(Builder $query, $method, array $args)
269: {
270: $fieldName = array_shift($args);
271:
272: if (self::$fieldRepository->hasField($fieldName)) {
273: $column = 'channel_data.field_id_'.self::$fieldRepository->getFieldId($fieldName);
274:
275: array_unshift($args, $column);
276:
277: call_user_func_array(array($query, $method), $args);
278: }
279:
280: return $query;
281: }
282:
283: 284: 285: 286: 287: 288: 289: 290:
291: public function scopeOrderByField(Builder $query, $fieldName, $direction = 'asc')
292: {
293: if (self::$fieldRepository->hasField($fieldName)) {
294: $column = 'channel_data.field_id_'.self::$fieldRepository->getFieldId($fieldName);
295:
296: $query->orderBy($column, $direction);
297: }
298:
299: return $query;
300: }
301:
302: 303: 304: 305: 306: 307: 308: 309: 310: 311:
312: public function scopeWhereField(Builder $query)
313: {
314: return $this->scopeWhereFieldHandler($query, 'where', array_slice(func_get_args(), 1));
315: }
316:
317: 318: 319: 320: 321: 322: 323: 324: 325:
326: public function scopeOrWhereField(Builder $query)
327: {
328: return $this->scopeWhereFieldHandler($query, 'orWhere', array_slice(func_get_args(), 1));
329: }
330:
331: 332: 333: 334: 335: 336: 337: 338: 339: 340:
341: public function scopeWhereFieldBetween(Builder $query)
342: {
343: return $this->scopeWhereFieldHandler($query, 'whereBetween', array_slice(func_get_args(), 1));
344: }
345:
346: 347: 348: 349: 350: 351: 352: 353: 354:
355: public function scopeOrWhereFieldBetween(Builder $query)
356: {
357: return $this->scopeWhereFieldHandler($query, 'orWhereBetween', array_slice(func_get_args(), 1));
358: }
359:
360: 361: 362: 363: 364: 365: 366: 367: 368:
369: public function scopeWhereFieldNotBetween(Builder $query)
370: {
371: return $this->scopeWhereFieldHandler($query, 'whereNotBetween', array_slice(func_get_args(), 1));
372: }
373:
374: 375: 376: 377: 378: 379: 380: 381:
382: public function scopeOrWhereFieldNotBetween(Builder $query)
383: {
384: return $this->scopeWhereFieldHandler($query, 'orWhereNotBetween', array_slice(func_get_args(), 1));
385: }
386:
387: 388: 389: 390: 391: 392: 393: 394: 395: 396:
397: public function scopeWhereFieldIn(Builder $query)
398: {
399: return $this->scopeWhereFieldHandler($query, 'whereIn', array_slice(func_get_args(), 1));
400: }
401:
402: 403: 404: 405: 406: 407: 408: 409:
410: public function scopeOrWhereFieldIn(Builder $query)
411: {
412: return $this->scopeWhereFieldHandler($query, 'orWhereIn', array_slice(func_get_args(), 1));
413: }
414:
415: 416: 417: 418: 419: 420: 421: 422: 423:
424: public function scopeWhereFieldNotIn(Builder $query)
425: {
426: return $this->scopeWhereFieldHandler($query, 'whereNotIn', array_slice(func_get_args(), 1));
427: }
428:
429: 430: 431: 432: 433: 434: 435: 436:
437: public function scopeOrWhereFieldNotIn(Builder $query)
438: {
439: return $this->scopeWhereFieldHandler($query, 'orWhereNotIn', array_slice(func_get_args(), 1));
440: }
441:
442: 443: 444: 445: 446: 447: 448: 449: 450:
451: public function scopeWhereFieldNull(Builder $query)
452: {
453: return $this->scopeWhereFieldHandler($query, 'whereNull', array_slice(func_get_args(), 1));
454: }
455:
456: 457: 458: 459: 460: 461: 462:
463: public function scopeOrWhereFieldNull(Builder $query)
464: {
465: return $this->scopeWhereFieldHandler($query, 'orWhereNull', array_slice(func_get_args(), 1));
466: }
467:
468: 469: 470: 471: 472: 473: 474: 475:
476: public function scopeWhereFieldNotNull(Builder $query)
477: {
478: return $this->scopeWhereFieldHandler($query, 'whereNotNull', array_slice(func_get_args(), 1));
479: }
480:
481: 482: 483: 484: 485: 486: 487:
488: public function scopeOrWhereFieldNotNull(Builder $query)
489: {
490: return $this->scopeWhereFieldHandler($query, 'orWhereNotNull', array_slice(func_get_args(), 1));
491: }
492:
493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503:
504: protected function scopeWhereFieldContainsHandler(
505: Builder $query,
506: $fieldName,
507: $value,
508: $boolean = 'and',
509: $not = false,
510: $wholeWord = false
511: ) {
512: if ($value) {
513: $operator = $not ? 'not ' : '';
514:
515: if ($wholeWord) {
516: $operator .= 'regexp';
517:
518: $value = '([[:<:]]|^)'.preg_quote($value).'([[:>:]]|$)';
519:
520: if (self::$fieldRepository->hasField($fieldName)) {
521: $column = 'field_id_'.self::$fieldRepository->getFieldId($fieldName);
522:
523: $method = $boolean === 'and' ? 'whereRaw' : 'orWhereRaw';
524:
525: $tablePrefix = $query->getQuery()->getConnection()->getTablePrefix();
526:
527: $query->$method("`{$tablePrefix}channel_data`.`{$column}` {$operator} '{$value}'");
528: }
529: } else {
530: $operator .= 'like';
531:
532: $value = '%'.$value.'%';
533:
534: $this->scopeWhereFieldHandler($query, 'where', array($fieldName, $operator, $value, $boolean));
535: }
536: } else {
537: $operator = $not ? '!=' : '=';
538:
539: $this->scopeWhereField($query, $fieldName, $operator, $value, $boolean);
540: }
541:
542: return $query;
543: }
544:
545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555:
556: protected function scopeWhereFieldContainsManyHandler(
557: Builder $query,
558: $fieldName,
559: array $values,
560: $boolean = 'and',
561: $not = false,
562: $wholeWord = false
563: ) {
564: if (count($values) === 1) {
565: return $this->scopeWhereFieldContainsHandler(
566: $query,
567: $fieldName,
568: current($values),
569: $boolean,
570: $not,
571: $wholeWord
572: );
573: }
574:
575: $model = $this;
576:
577: return $query->where(function ($subquery) use ($model, $fieldName, $values, $boolean, $not, $wholeWord) {
578: call_user_func(
579: array($model, 'scopeWhereFieldContainsHandler'),
580: $subquery,
581: $fieldName,
582: $value,
583: $boolean,
584: $not,
585: $wholeWord
586: );
587: });
588: }
589:
590: 591: 592: 593: 594: 595: 596: 597:
598: public function scopeWhereFieldContains(Builder $query, $fieldName, $value)
599: {
600: return $this->scopeWhereFieldContainsManyHandler($query, $fieldName, array_slice(func_get_args(), 2));
601: }
602:
603: 604: 605: 606: 607: 608: 609: 610:
611: public function scopeWhereFieldDoesNotContain(Builder $query, $fieldName, $value)
612: {
613: return $this->scopeWhereFieldContainsManyHandler(
614: $query,
615: $fieldName,
616: array_slice(func_get_args(), 2),
617: 'and',
618: true
619: );
620: }
621:
622: 623: 624: 625: 626: 627: 628: 629:
630: public function scopeOrWhereFieldContains(Builder $query, $fieldName, $value)
631: {
632: return $this->scopeWhereFieldContainsManyHandler($query, $fieldName, array_slice(func_get_args(), 2), 'or');
633: }
634:
635: 636: 637: 638: 639: 640: 641: 642:
643: public function scopeOrWhereFieldDoesNotContain(Builder $query, $fieldName, $value)
644: {
645: return $this->scopeWhereFieldContainsManyHandler(
646: $query,
647: $fieldName,
648: array_slice(func_get_args(), 2),
649: 'or',
650: true
651: );
652: }
653:
654: 655: 656: 657: 658: 659: 660: 661:
662: public function scopeWhereFieldContainsWholeWord(Builder $query, $fieldName, $value)
663: {
664: return $this->scopeWhereFieldContainsManyHandler(
665: $query,
666: $fieldName,
667: array_slice(func_get_args(), 2),
668: 'and',
669: false,
670: true
671: );
672: }
673:
674: 675: 676: 677: 678: 679: 680: 681:
682: public function scopeWhereFieldDoesNotContainWholeWord(Builder $query, $fieldName, $value)
683: {
684: return $this->scopeWhereFieldContainsManyHandler(
685: $query,
686: $fieldName,
687: array_slice(func_get_args(), 2),
688: 'and',
689: true,
690: true
691: );
692: }
693:
694: 695: 696: 697: 698: 699: 700: 701:
702: public function scopeOrWhereFieldContainsWholeWord(Builder $query, $fieldName, $value)
703: {
704: return $this->scopeWhereFieldContainsManyHandler(
705: $query,
706: $fieldName,
707: array_slice(func_get_args(), 2),
708: 'or',
709: false,
710: true
711: );
712: }
713:
714: 715: 716: 717: 718: 719: 720: 721:
722: public function scopeOrWhereFieldDoesNotContainWholeWord(Builder $query, $fieldName, $value)
723: {
724: return $this->scopeWhereFieldContainsManyHandler(
725: $query,
726: $fieldName,
727: array_slice(func_get_args(), 2),
728: 'or',
729: true,
730: true
731: );
732: }
733: }
734: