Completed
Push — master ( 5f2437...e2e272 )
by Michael
01:12
created

Repository::modelQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Mblarsen\LaravelRepository;
4
5
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Model;
8
use InvalidArgumentException;
9
use Mblarsen\LaravelRepository\Traits\Filters;
10
use Mblarsen\LaravelRepository\Traits\IncludesRelations;
11
use Mblarsen\LaravelRepository\Traits\Sorts;
12
13
class Repository
14
{
15
    use Filters;
16
    use IncludesRelations;
17
    use Sorts;
18
19
    const WITH_ALLOW_ALL = ['*'];
20
    const WITH_ALLOW_NONE = [];
21
22
    /** @var string */
23
    protected $model;
24
25
    /** @var ResourceContext $resource_context */
26
    protected $resource_context;
27
28
    /** @var array $allowed_with */
29
    protected $allowed_with = self::WITH_ALLOW_NONE;
30
31
    /** @var array $default_with */
32
    protected $default_with = [];
33
34
    /** @var string $default_sort_by */
35
    protected $default_sort_by;
36
37
    /** @var string $default_sort_order */
38
    protected $default_sort_order = 'asc';
39
40
    public function __construct(ResourceContext $resource_context)
41
    {
42
        $this->resource_context = $resource_context;
43
    }
44
45
    /**
46
     * Creates a new repository for a model.
47
     */
48
    public static function for(string $model, ResourceContext $context = null): self
49
    {
50
        $repository = resolve(static::class);
51
        $repository->setModel($model);
52
        if ($context) {
53
            $repository->setContext($context);
54
        }
55
        return $repository;
56
    }
57
58
    /**
59
     * Get the currenct resource context
60
     */
61
    public function getContext(): ResourceContext
62
    {
63
        return $this->resource_context;
64
    }
65
66
    /**
67
     * Set or replace the resource context
68
     */
69
    public function setContext(ResourceContext $resource_context)
70
    {
71
        $this->resource_context = $resource_context;
72
73
        return $this;
74
    }
75
76
    /**
77
     * Set the model
78
     */
79
    public function setModel(string $model)
80
    {
81
        $this->model = $model;
82
83
        return $this;
84
    }
85
86
    /**
87
     * Return all models based on resource context and query
88
     *
89
     * The ResourceContext determines if the result is a Collection or a
90
     * Paginator.
91
     *
92
     * @return LengthAwarePaginator|Collection
93
     */
94
    public function all($query = null)
95
    {
96
        $query = $this->modelQuery($query);
97
98
        return $this
99
            ->validateQurey($query)
100
            ->applyWith($query)
101
            ->applySort($query)
102
            ->applyFilters($query)
103
            ->paginate($query);
104
    }
105
106
    /**
107
     * Produces a result suitable for selects, lists, and autocomplete. All
108
     * entries that has a 'value' and a 'label' key.
109
     *
110
     * Note: if a callable is used the mapping is performed in memory, while a
111
     * string is done in the database layer.
112
     *
113
     * @param callable|string $column
114
     * @param Builder $query
115
     * @return Collection
116
     */
117
    public function list($column = null, $query = null)
118
    {
119
        $query = $this->modelQuery($query);
120
121
        if (is_string($column)) {
122
            $query->select([$query->getModel()->getKeyName() . " AS value", "$column AS label"]);
123
            return $this->all($query);
124
        }
125
126
        if (is_callable($column)) {
127
            return $this->all($query)
0 ignored issues
show
Bug introduced by
The method map() does not seem to exist on object<Illuminate\Contra...n\LengthAwarePaginator>.

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...
128
                ->map(function (Model $model) use ($column) {
129
                    return [
130
                        'value' => $model->getKey(),
131
                        'label' => $column($model)
132
                    ];
133
                });
134
        }
135
136
        throw new InvalidArgumentException("'column' should be a string or callable");
137
    }
138
139
    public function find($id, $query = null): Model
140
    {
141
        $query = $this->modelQuery($query);
142
143
        $this
144
            ->validateQurey($query)
145
            ->applyWith($query);
146
147
        $query->whereId($id);
148
149
        return $query->firstOrFail();
150
    }
151
152
    public function create(array $data): Model
153
    {
154
        return $this->model::create($data);
0 ignored issues
show
Bug introduced by
The method create cannot be called on $this->model (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
155
    }
156
157
    public function update(Model $model, array $data): Model
158
    {
159
        $model->update($data);
160
        return $model;
161
    }
162
163
    public function destroy(Model $model)
164
    {
165
        $model->delete();
166
    }
167
168
    protected function modelQuery($query = null)
169
    {
170
        return $query ?? $this->model::query();
0 ignored issues
show
Bug introduced by
The method query cannot be called on $this->model (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
171
    }
172
173
    protected function validateQurey(Builder $query)
174
    {
175
        $model = $this->model;
176
        $query_model = get_class($query->getModel());
177
178
        if ($model !== $query_model) {
179
            throw new InvalidArgumentException("The input query and model does not match");
180
        }
181
182
        return $this;
183
    }
184
185
    /**
186
     * @param Builder $query
187
     * @return LengthAwarePaginator|Collection
188
     */
189
    private function paginate($query)
190
    {
191
        $page = $this->resource_context->page();
192
        $per_page = $this->resource_context->perPage();
193
        $should_paginate = $this->resource_context->paginate();
194
195
        return $should_paginate
196
            ? $query->paginate($per_page, ['*'], 'page', $page)
197
            : $query->get();
198
    }
199
}
200