Completed
Push — master ( eb8200...210d5d )
by Freek
01:23
created

ModelSearchAspect::canBeUsedBy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Spatie\Searchable;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Foundation\Auth\User;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Contracts\Auth\Access\Gate;
10
use Spatie\Searchable\Exceptions\InvalidSearchableModel;
11
use Spatie\Searchable\Exceptions\InvalidModelSearchAspect;
12
13
class ModelSearchAspect extends SearchAspect
14
{
15
    /** @var \Illuminate\Database\Eloquent\Model */
16
    protected $model;
17
18
    /** @var array */
19
    protected $attributes = [];
20
21
    public static function forModel(string $model, ...$attributes): self
22
    {
23
        return new self($model, $attributes);
24
    }
25
26
    /**
27
     * @param string $model
28
     * @param array|\Closure $attributes
29
     *
30
     * @throws \Spatie\Searchable\Exceptions\InvalidSearchableModel
31
     */
32
    public function __construct(string $model, $attributes = [])
33
    {
34
        if (!is_subclass_of($model, Model::class)) {
35
            throw InvalidSearchableModel::notAModel($model);
36
        }
37
38
        if (!is_subclass_of($model, Searchable::class)) {
39
            throw InvalidSearchableModel::modelDoesNotImplementSearchable($model);
40
        }
41
42
        $this->model = $model;
0 ignored issues
show
Documentation Bug introduced by
It seems like $model of type string is incompatible with the declared type object<Illuminate\Database\Eloquent\Model> of property $model.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
43
44
        if (is_array($attributes)) {
45
            $this->attributes = SearchableAttribute::createMany($attributes);
46
        }
47
48
        if (is_callable($attributes)) {
49
            $callable = $attributes;
50
51
            $callable($this);
52
        }
53
    }
54
55
56
    public function addSearchableAttribute(string $attribute, bool $partial = true): self
57
    {
58
        $this->attributes[] = SearchableAttribute::create($attribute, $partial);
59
60
        return $this;
61
    }
62
63
    public function addExactSearchableAttribute(string $attribute): self
64
    {
65
        $this->attributes[] = SearchableAttribute::createExact($attribute);
66
67
        return $this;
68
    }
69
70
    public function getType(): string
71
    {
72
        $model = new $this->model();
73
74
        if (property_exists($model, 'searchableType')) {
75
            return $model->searchableType;
76
        }
77
78
        return $model->getTable();
79
    }
80
81
    public function getResults(string $term, User $user = null): Collection
82
    {
83
        if (empty($this->attributes)) {
84
            throw InvalidModelSearchAspect::noSearchableAttributes($this->model);
85
        }
86
87
        $query = ($this->model)::query();
88
89
        $this->addSearchConditions($query, $term);
90
91
        return $query->get();
92
    }
93
94
    protected function addSearchConditions(Builder $query, string $term)
95
    {
96
        foreach ($this->attributes as $attribute) {
97
            $sql = "LOWER({$attribute->getAttribute()}) LIKE ?";
98
99
            $term = mb_strtolower($term, 'UTF8');
100
101
            $attribute->isPartial()
102
                ? $query->orWhereRaw($sql, ["%{$term}%"])
103
                : $query->orWhere($attribute->getAttribute(), $term);
104
        }
105
    }
106
}
107