Passed
Push — master ( 554c45...e72651 )
by Zing
04:36
created

QueryBuilder::addFilters()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 24
rs 8.8333
cc 7
nc 2
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: zing
5
 * Date: 2018/12/26
6
 * Time: 7:14 PM.
7
 */
8
9
namespace Zing\QueryBuilder;
10
11
use Illuminate\Database\Eloquent\Builder;
12
use Illuminate\Http\Request;
13
use Illuminate\Support\Arr;
14
use Illuminate\Support\Collection;
15
use Illuminate\Support\Str;
16
use Zing\QueryBuilder\Concerns\Castable;
17
18
class QueryBuilder extends Builder
19
{
20
    use Castable;
21
22
    public const CAST_INTEGER = 'integer';
23
24
    public const CAST_ARRAY = 'array';
25
26
    public const CAST_BOOLEAN = 'boolean';
27
28
    /** @var \Illuminate\Http\Request */
29
    protected $request;
30
31
    public function __construct(Builder $builder, $request)
32
    {
33
        parent::__construct($builder->getQuery());
34
        $this->setModel($builder->getModel());
35
        $this->scopes = $builder->scopes;
36
        $this->request = $request;
37
    }
38
39
    /**
40
     * @param Builder|string $baseQuery
41
     * @param \Illuminate\Http\Request $request
42
     *
43
     * @return \Zing\QueryBuilder\QueryBuilder
44
     */
45
    public static function for($baseQuery, Request $request)
46
    {
47
        if (is_string($baseQuery)) {
48
            $baseQuery = $baseQuery::query();
49
        }
50
51
        return new static($baseQuery, $request);
52
    }
53
54
    /**
55
     * 排序逻辑.
56
     *
57
     * @param array $inputs
58
     * @param array $sorts
59
     *
60
     * @return mixed
61
     */
62
    protected function applySort($inputs, $sorts)
63
    {
64
        foreach (['desc', 'asc'] as $direction) {
65
            $this->when(
66
                data_get($inputs, $direction),
67
                function (Builder $query, $descAttribute) use ($sorts, $direction) {
68
                    if (array_key_exists($descAttribute, $sorts)) {
69
                        $descAttribute = Arr::get($sorts, $descAttribute);
70
                    }
71
72
                    return $query->orderBy($descAttribute, $direction);
73
                }
74
            );
75
        }
76
77
        return $this;
78
    }
79
80
    /**
81
     * @param string $field
82
     * @param array $results
83
     *
84
     * @return array
85
     */
86
    private function addNestedRelation($field, array $results)
87
    {
88
        [$relation, $property] = collect(explode('.', $field))
89
            ->pipe(function (Collection $parts) {
90
                return [
91
                    $parts->except(count($parts) - 1)->map([Str::class, 'camel'])->implode('.'),
92
                    $parts->last(),
93
                ];
94
            });
95
96
        $results[$relation][] = $property;
97
98
        return $results;
99
    }
100
101
    protected function castAttribute($key, $value)
102
    {
103
        switch ($this->getCastType($key)) {
104
            case self::CAST_INTEGER:
105
                return (int) $value;
106
            case self::CAST_ARRAY:
107
                if (Str::contains($value, ',')) {
108
                    return explode(',', $value);
109
                }
110
111
                return $value;
112
            case self::CAST_BOOLEAN:
113
                return (bool) $value;
114
        }
115
116
        return $value;
117
    }
118
119
    /**
120
     * 自定义过滤器逻辑.
121
     *
122
     * @param \Zing\QueryBuilder\Filter[]|mixed $filters
123
     *
124
     * @return $this
125
     */
126
    public function addFilters($filters): self
127
    {
128
        $filters = is_array($filters) ? $filters : func_get_args();
129
        $filters = collect($filters)->map(function ($filter) {
130
            if ($filter instanceof Filter) {
131
                return $filter;
132
            }
133
134
            return Filter::exact($filter);
135
        });
136
        $filters->each(function (Filter $filter) {
137
            $value = data_get($this->request->input(), $filter->getProperty());
138
            if ($value !== null && $value !== '') {
139
                if ($this->hasCast($filter->getProperty())) {
140
                    $value = $this->castAttribute($filter->getProperty(), $value);
141
                } elseif (Str::contains($value, ',')) {
142
                    $value = explode(',', $value);
143
                }
144
145
                $filter->filter($this, $value);
146
            }
147
        });
148
149
        return $this;
150
    }
151
152
    public function searchable($searchable)
153
    {
154
        $searchable = is_array($searchable) ? $searchable : func_get_args();
155
        $search = $this->request->input('search');
156
        if ($search) {
157
            $this->where(
158
                function (Builder $query) use ($search, $searchable) {
159
                    $results = [];
160
                    foreach ($searchable as $field) {
161
                        if (Str::contains($field, '.')) {
162
                            $results = $this->addNestedRelation($field, $results);
163
                        } else {
164
                            $results[] = $field;
165
                        }
166
                    }
167
                    foreach ($results as $key => $value) {
168
                        if (is_numeric($key)) {
169
                            $query->orWhere($value, 'like', "%{$search}%");
170
                        } else {
171
                            $query->orWhereHas(
172
                                $key,
173
                                function ($query) use ($value, $search) {
174
                                    /** @var \Illuminate\Database\Query\Builder $query */
175
                                    $query->where(
176
                                        function (Builder $query) use ($value, $search) {
177
                                            foreach ($value as $field) {
178
                                                $query->orWhere($field, 'like', "%{$search}%");
179
                                            }
180
                                        }
181
                                    );
182
                                }
183
                            );
184
                        }
185
                    }
186
                }
187
            );
188
        }//end if
189
        return $this;
190
    }
191
}
192