Passed
Push — master ( a646c6...54871e )
by Zing
07:14 queued 03:02
created

WithSearchable::resolveNestedSearchable()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zing\QueryBuilder\Concerns;
6
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Str;
10
11
trait WithSearchable
12
{
13 3
    public function searchable($searchable)
14
    {
15 3
        $searchable = is_array($searchable) ? $searchable : func_get_args();
16 3
        $search = $this->request->input('search');
17 3
        if ($search === null || (is_string($search) && trim($search) === '')) {
18 1
            return $this;
19
        }
20
21 2
        $searchable = $this->resolveNestedSearchable($searchable);
22
23 2
        return $this->applySearchable($search, $searchable);
24
    }
25
26 2
    protected function applySearchable($search, array $searchable = [])
27
    {
28 2
        return $this->where(
0 ignored issues
show
Bug introduced by
It seems like where() 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

28
        return $this->/** @scrutinizer ignore-call */ where(
Loading history...
29
            function (Builder $query) use ($search, $searchable): void {
30 2
                collect($searchable)->each(
31
                    function ($value, $key) use ($query, $search) {
32 2
                        if (is_numeric($key)) {
33 1
                            return $query->orWhere($value, 'like', "%{$search}%");
34
                        }
35
36 1
                        return $this->applyRelationSearchable($query, $key, $value, $search);
37 2
                    }
38
                );
39 2
            }
40
        );
41
    }
42
43 1
    protected function applyRelationSearchable($query, $relation, $fields, $search)
44
    {
45 1
        return $query->orWhereHas(
46 1
            $relation,
47
            function (Builder $query) use ($fields, $search): void {
48 1
                $query->where(
49
                    function (Builder $query) use ($fields, $search): void {
50 1
                        foreach ($fields as $field) {
51 1
                            $query->orWhere($field, 'like', "%{$search}%");
52
                        }
53 1
                    }
54
                );
55 1
            }
56
        );
57
    }
58
59
    /**
60
     * @param string $field
61
     * @param array $results
62
     *
63
     * @return array
64
     */
65 1
    private function addNestedRelation($field, array $results)
66
    {
67 1
        [$relation, $property] = collect(explode('.', $field))
68 1
            ->pipe(
69
                function (Collection $parts) {
70
                    return [
71 1
                        $parts->except(count($parts) - 1)->map([Str::class, 'camel'])->implode('.'),
72 1
                        $parts->last(),
73
                    ];
74 1
                }
75
            );
76
77 1
        $results[$relation][] = $property;
78
79 1
        return $results;
80
    }
81
82 2
    private function resolveNestedSearchable(array $searchable)
83
    {
84 2
        $results = [];
85 2
        foreach ($searchable as $field) {
86 2
            if (Str::contains($field, '.')) {
87 1
                $results = $this->addNestedRelation($field, $results);
88
            } else {
89 2
                $results[] = $field;
90
            }
91
        }
92
93 2
        return $results;
94
    }
95
}
96