Passed
Branch master (1144ec)
by Zing
04:29
created

QueryBuilder::castAttribute()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 8.8142

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 24
ccs 10
cts 15
cp 0.6667
rs 8.8333
cc 7
nc 7
nop 2
crap 8.8142
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\WithCasts;
17
18
class QueryBuilder extends Builder
19
{
20
    use WithCasts;
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 11
    public function __construct(Builder $builder, $request)
32
    {
33 11
        parent::__construct($builder->getQuery());
34 11
        $this->setModel($builder->getModel());
35 11
        $this->scopes = $builder->scopes;
36 11
        $this->request = $request;
37 11
    }
38
39
    /**
40
     * @param Builder|string $baseQuery
41
     * @param \Illuminate\Http\Request $request
42
     *
43
     * @return \Zing\QueryBuilder\QueryBuilder
44
     */
45 11
    public static function for($baseQuery, Request $request)
46
    {
47 11
        if (is_string($baseQuery)) {
48 11
            $baseQuery = $baseQuery::query();
49
        }
50
51 11
        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 1
    private function addNestedRelation($field, array $results)
87
    {
88 1
        [$relation, $property] = collect(explode('.', $field))
89
            ->pipe(function (Collection $parts) {
90
                return [
91 1
                    $parts->except(count($parts) - 1)->map([Str::class, 'camel'])->implode('.'),
92 1
                    $parts->last(),
93
                ];
94 1
            });
95
96 1
        $results[$relation][] = $property;
97
98 1
        return $results;
99
    }
100
101 1
    protected function castAttribute($key, $value)
102
    {
103 1
        switch ($this->getCastType($key)) {
104 1
            case self::CAST_INTEGER:
105
                return (int) $value;
106 1
            case self::CAST_ARRAY:
107
                if (Str::contains($value, ',')) {
108
                    return explode(',', $value);
109
                }
110
111
                return $value;
112 1
            case self::CAST_BOOLEAN:
113 1
                if ($value === 'true') {
114 1
                    return true;
115
                }
116
117 1
                if ($value === 'false') {
118 1
                    return false;
119
                }
120
121 1
                return (bool) $value;
122
        }
123
124
        return $value;
125
    }
126
127
    /**
128
     * 自定义过滤器逻辑.
129
     *
130
     * @param \Zing\QueryBuilder\Filter[]|mixed $filters
131
     *
132
     * @return $this
133
     */
134 10
    public function addFilters($filters): self
135
    {
136 10
        $filters = is_array($filters) ? $filters : func_get_args();
137
        $filters = collect($filters)->map(function ($filter) {
138 10
            if ($filter instanceof Filter) {
139 9
                return $filter;
140
            }
141
142 1
            return Filter::exact($filter);
143 10
        });
144
        $filters->each(function (Filter $filter) {
145 10
            $value = data_get($this->request->input(), $filter->getProperty());
146 10
            if ($value !== null && $value !== '') {
147 9
                if ($this->hasCast($filter->getProperty())) {
148 1
                    $value = $this->castAttribute($filter->getProperty(), $value);
149 8
                } elseif (Str::contains($value, ',')) {
150 2
                    $value = explode(',', $value);
151
                }
152
153 9
                $filter->filter($this, $value);
154
            }
155 10
        });
156
157 10
        return $this;
158
    }
159
160 2
    public function searchable($searchable)
161
    {
162 2
        $searchable = is_array($searchable) ? $searchable : func_get_args();
163 2
        $search = $this->request->input('search');
164 2
        if ($search) {
165 2
            $this->where(
166
                function (Builder $query) use ($search, $searchable) {
167 2
                    $results = [];
168 2
                    foreach ($searchable as $field) {
169 2
                        if (Str::contains($field, '.')) {
170 1
                            $results = $this->addNestedRelation($field, $results);
171
                        } else {
172 2
                            $results[] = $field;
173
                        }
174
                    }
175 2
                    foreach ($results as $key => $value) {
176 2
                        if (is_numeric($key)) {
177 1
                            $query->orWhere($value, 'like', "%{$search}%");
178
                        } else {
179 1
                            $query->orWhereHas(
180 1
                                $key,
181
                                function ($query) use ($value, $search) {
182
                                    /** @var \Illuminate\Database\Query\Builder $query */
183 1
                                    $query->where(
184
                                        function (Builder $query) use ($value, $search) {
185 1
                                            foreach ($value as $field) {
186 1
                                                $query->orWhere($field, 'like', "%{$search}%");
187
                                            }
188 1
                                        }
189
                                    );
190 2
                                }
191
                            );
192
                        }
193
                    }
194 2
                }
195
            );
196
        }//end if
197 2
        return $this;
198
    }
199
}
200