Completed
Push — main ( a50f31...994820 )
by Mohammad
14s queued 13s
created

Criteriable::buildMatchAgainst()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
cc 1
eloc 1
c 2
b 1
f 1
nc 1
nop 3
dl 0
loc 3
rs 10
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
    {
56
        return $query->whereRaw("MATCH(" . implode(',', $columns) . ") AGAINST (? " . $this->fullTextSearchMode . ")", $search);
57
    }
58
59
    public function scopeSearchByCriteria($query, array $criteria): Builder
60
    {
61
        if (isset($criteria['search'])) {
62
            $query->where(function ($q) use ($criteria) {
63
                foreach ($this->fulltextSearch as $method => $columns) {
64
                    if (method_exists($this, $method)) {
65
                        $q->orWhereHas($method, function ($query) use ($criteria, $columns) {
66
                            $this->buildMatchAgainst($query, $columns, $criteria['search']);
67
                        });
68
                    } else {
69
                        $this->buildMatchAgainst($q, $columns, $criteria['search']);
70
                    }
71
                }
72
73
                /*
74
                 * @var Builder $q
75
                 */
76
                foreach ($this->getSearchables() as $method => $columns) {
77
                    if (method_exists($this, $method)) {
78
                        $q->orWhereHas($method, function ($query) use ($criteria, $columns) {
79
                            /* @var $query Builder */
80
                            $query->where(function ($query2) use ($criteria, $columns) {
81
                                /* @var $query2 Builder */
82
                                foreach ((array) $columns as $column) {
83
                                    $query2->orWhere($column, 'like', $criteria['search'].'%');
84
                                }
85
                            });
86
                        });
87
                    } else {
88
                        $q->orWhere($columns, 'like', $criteria['search'].'%');
89
                    }
90
                }
91
            });
92
        }
93
94
        return $query;
95
    }
96
97
    public function scopeOrderByCriteria($query, array $criteria): Builder
98
    {
99
        if (isset($criteria['order']) && in_array($criteria['order'], $this->getSortables())) {
100
            $query->orderBy($criteria['order'], $criteria['direction'] ?? 'desc');
101
        }
102
103
        return $query;
104
    }
105
106
    /**
107
     * By default, all fillables and not hidden are searchables, if you want to override that explicitly set an array of searchables.
108
     * For a relation this is the syntax [ relationName => [columns in the relation] ].
109
     */
110
    public function getSearchables(): array
111
    {
112
        if (null !== $this->searchables) {
113
            return $this->searchables;
114
        }
115
116
        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

116
        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

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