Passed
Pull Request — main (#5)
by
unknown
13:48
created

Criteriable::scopeSearchByCriteria()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 36
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 2
Metric Value
cc 7
eloc 17
c 3
b 1
f 2
nc 2
nop 2
dl 0
loc 36
rs 8.8333
1
<?php
2
3
namespace Shamaseen\Repository\Utility\Models;
4
5
use Illuminate\Database\Eloquent\Builder;
6
7
/**
8
 * @method static Builder filterByCriteria(array $criteria)
9
 * @method static Builder searchByCriteria(array $criteria)
10
 * @method static Builder orderByCriteria(array $criteria)
11
 * @method static Builder setSearchables(array $searchables)
12
 * @method static Builder appendSearchables(array $searchables)
13
 * @method static Builder setFilterables(array $filterables)
14
 * @method static Builder appendFilterables(array $filterables)
15
 * @method static Builder setSortables(array $sortables)
16
 * @method static Builder appendSortables(array $sortables)
17
 */
18
trait Criteriable
19
{
20
    protected ?array $searchables = null;
21
    protected ?array $filterables = null;
22
    protected ?array $sortables = null;
23
		protected string $fullTextSearchMode = '';
24
25
    /**
26
     * @var array<array<string>>
27
     */
28
    protected ?array $fulltextSearch = [];
29
30
    public function scopeFilterByCriteria($query, array $criteria): Builder
31
    {
32
        foreach ($this->getFilterables() as $method => $columns) {
33
            // if this is associative then it is a relation
34
            if ('string' === gettype($method)) {
35
                if (method_exists($this, $method) && array_key_exists($method, $criteria)) {
36
                    $query->whereHas($method, function ($query) use ($criteria, $columns, $method) {
37
                        /* @var $query Builder */
38
                        $query->where(function ($query2) use ($criteria, $columns, $method) {
39
                            /* @var $query2 Builder */
40
                            foreach ((array) $columns as $column) {
41
                                $query2->where($column, $criteria[$method]);
42
                            }
43
                        });
44
                    });
45
                }
46
            } elseif (array_key_exists($columns, $criteria)) {
47
                $query->where($columns, $criteria[$columns]);
48
            }
49
        }
50
51
        return $query;
52
    }
53
54
		private function buildMatchAgainst($query, array $columns, $search) {
55
			return $query->whereRaw("MATCH(".implode(',', $columns).") AGAINST (? ".$this->fullTextSearchMode.")", $search);
56
		}
57
58
		public function scopeSearchByCriteria($query, array $criteria): Builder
59
		{
60
				if (isset($criteria['search'])) {
61
						$query->where(function ($q) use ($criteria) {
62
								foreach ($this->fulltextSearch as $method => $columns) {
63
										if (method_exists($this, $method)) {
64
												$q->orWhereHas($method, function($query) use ($criteria, $columns) {
65
													$this->buildMatchAgainst($query, $columns, $criteria['search']);
66
												});
67
										} else {
68
												$this->buildMatchAgainst($q, $columns, $criteria['search']);
69
										}
70
								}
71
72
                /*
73
                 * @var Builder $q
74
                 */
75
                foreach ($this->getSearchables() as $method => $columns) {
76
                    if (method_exists($this, $method)) {
77
                        $q->orWhereHas($method, function ($query) use ($criteria, $columns) {
78
                            /* @var $query Builder */
79
                            $query->where(function ($query2) use ($criteria, $columns) {
80
                                /* @var $query2 Builder */
81
                                foreach ((array) $columns as $column) {
82
                                    $query2->orWhere($column, 'like', $criteria['search'].'%');
83
                                }
84
                            });
85
                        });
86
                    } else {
87
                        $q->orWhere($columns, 'like', $criteria['search'].'%');
88
                    }
89
                }
90
            });
91
        }
92
93
        return $query;
94
    }
95
96
    public function scopeOrderByCriteria($query, array $criteria): Builder
97
    {
98
        if (isset($criteria['order']) && in_array($criteria['order'], $this->getSortables())) {
99
            $query->orderBy($criteria['order'], $criteria['direction'] ?? 'desc');
100
        }
101
102
        return $query;
103
    }
104
105
    /**
106
     * By default, all fillables and not hidden are searchables, if you want to override that explicitly set an array of searchables.
107
     * For a relation this is the syntax [ relationName => [columns in the relation] ].
108
     */
109
    public function getSearchables(): array
110
    {
111
        if (null !== $this->searchables) {
112
            return $this->searchables;
113
        }
114
115
        return array_diff($this->getFillable(), $this->getHidden());
0 ignored issues
show
Bug introduced by
It seems like getHidden() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

115
        return array_diff($this->getFillable(), $this->/** @scrutinizer ignore-call */ getHidden());
Loading history...
Bug introduced by
The method getFillable() does not exist on Shamaseen\Repository\Utility\Models\Criteriable. Did you maybe mean getFilterables()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

115
        return array_diff($this->/** @scrutinizer ignore-call */ getFillable(), $this->getHidden());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
116
    }
117
118
    public function scopeAppendSearchables($query, array $searchables): Builder
119
    {
120
        $this->searchables = collect($this->searchables)->merge($searchables)->unique()->toArray();
121
122
        return $query;
123
    }
124
125
    public function scopeSetSearchables($query, array $searchables): Builder
126
    {
127
        $this->searchables = $searchables;
128
129
        return $query;
130
    }
131
132
    /**
133
     * By default, all fillables and not hidden are sortables, if you want to override that explicitly set an array of sortables.
134
     */
135
    public function getSortables(): array
136
    {
137
        if (null !== $this->sortables) {
138
            return $this->sortables;
139
        }
140
141
        return array_diff($this->getFillable(), $this->getHidden());
142
    }
143
144
    public function scopeAppendSortables($query, array $sortables): Builder
145
    {
146
        $this->sortables = collect($this->sortables)->merge($sortables)->unique()->toArray();
147
148
        return $query;
149
    }
150
151
    public function scopeSetSortables($query, array $sortables): Builder
152
    {
153
        $this->sortables = $sortables;
154
155
        return $query;
156
    }
157
158
    /**
159
     * By default, all fillables and not hidden are filterables, if you want to override that explicitly set an array of searchables.
160
     * For a relation this is the syntax [ relationName => [columns in the relation] ].
161
     */
162
    public function getFilterables(): array
163
    {
164
        if (null !== $this->filterables) {
165
            return $this->filterables;
166
        }
167
168
        return array_diff($this->getFillable(), $this->getHidden());
169
    }
170
171
    public function scopeAppendFilterables($query, array $filterables): Builder
172
    {
173
        $this->filterables = collect($this->filterables)->merge($filterables)->unique()->toArray();
174
175
        return $query;
176
    }
177
178
    public function scopeSetFilterables($query, array $filterables): Builder
179
    {
180
        $this->filterables = $filterables;
181
182
        return $query;
183
    }
184
}
185