1 | <?php |
||||
2 | |||||
3 | namespace OkayBueno\Repositories\src; |
||||
4 | |||||
5 | use OkayBueno\Repositories\Criteria\CriteriaInterface; |
||||
6 | use OkayBueno\Repositories\Criteria\Eloquent\With; |
||||
7 | use OkayBueno\Repositories\RepositoryInterface; |
||||
8 | use Illuminate\Database\Eloquent\Model; |
||||
9 | |||||
10 | /** |
||||
11 | * Class EloquentRepository |
||||
12 | * @package OkayBueno\Repositories\src |
||||
13 | */ |
||||
14 | abstract class EloquentRepository implements RepositoryInterface |
||||
15 | { |
||||
16 | |||||
17 | protected $model; |
||||
18 | protected $with; |
||||
19 | protected $skipCriteria; |
||||
20 | protected $criteria; |
||||
21 | private $modelClassName; |
||||
22 | |||||
23 | /** |
||||
24 | * EloquentRepository constructor. |
||||
25 | * @param Model $model |
||||
26 | * @throws \ReflectionException |
||||
27 | */ |
||||
28 | public function __construct( Model $model ) |
||||
29 | { |
||||
30 | $this->model = $model; |
||||
31 | |||||
32 | // A clean copy of the model is needed when the scope needs to be reset. |
||||
33 | $reflex = new \ReflectionClass( $model ); |
||||
34 | $this->modelClassName = $reflex->getName(); |
||||
35 | |||||
36 | $this->skipCriteria = FALSE; |
||||
37 | $this->criteria = []; |
||||
38 | } |
||||
39 | |||||
40 | /** |
||||
41 | * @param $value |
||||
42 | * @param string $field |
||||
43 | * @param array $columns |
||||
44 | * @return mixed |
||||
45 | */ |
||||
46 | public function findOneBy($value = NULL, $field = 'id', array $columns = ['*']) |
||||
47 | { |
||||
48 | $this->eagerLoadRelations(); |
||||
49 | $this->applyCriteria(); |
||||
50 | |||||
51 | if ( !is_null( $value ) ) $this->model = $this->model->where( $field, $value ); |
||||
52 | |||||
53 | $result = $this->model->first( $columns ); |
||||
54 | |||||
55 | $this->resetScope(); |
||||
56 | |||||
57 | return $result; |
||||
58 | } |
||||
59 | |||||
60 | /** |
||||
61 | * @param null $value |
||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||||
62 | * @param null $field |
||||
0 ignored issues
–
show
|
|||||
63 | * @param array $columns |
||||
64 | * @return mixed |
||||
65 | */ |
||||
66 | public function findAllBy($value = NULL, $field = NULL, array $columns = ['*']) |
||||
67 | { |
||||
68 | $this->eagerLoadRelations(); |
||||
69 | $this->applyCriteria(); |
||||
70 | |||||
71 | if ( !is_null( $value ) && !is_null( $field ) ) $this->model = $this->model->where( $field, $value ); |
||||
0 ignored issues
–
show
|
|||||
72 | |||||
73 | $result = $this->model->get( $columns ); |
||||
74 | |||||
75 | $this->resetScope(); |
||||
76 | |||||
77 | return $result; |
||||
78 | } |
||||
79 | |||||
80 | /** |
||||
81 | * @param array $value |
||||
82 | * @param string $field |
||||
83 | * @param array $columns |
||||
84 | * @return mixed |
||||
85 | */ |
||||
86 | public function findAllWhereIn(array $value, $field, array $columns = ['*']) |
||||
87 | { |
||||
88 | $this->eagerLoadRelations(); |
||||
89 | $this->applyCriteria(); |
||||
90 | $result = $this->model->whereIn( $field, $value )->get( $columns ); |
||||
91 | |||||
92 | $this->resetScope(); |
||||
93 | |||||
94 | return $result; |
||||
95 | } |
||||
96 | |||||
97 | /** |
||||
98 | * @param array $columns |
||||
99 | * @return \Illuminate\Database\Eloquent\Collection|static[] |
||||
100 | */ |
||||
101 | public function findAll( array $columns = ['*'] ) |
||||
102 | { |
||||
103 | $this->eagerLoadRelations(); |
||||
104 | $this->applyCriteria(); |
||||
105 | $result = $this->model->all( $columns ); |
||||
106 | |||||
107 | $this->resetScope(); |
||||
108 | |||||
109 | return $result; |
||||
110 | } |
||||
111 | |||||
112 | /** |
||||
113 | * @param array|string $relations |
||||
114 | * @return $this |
||||
115 | */ |
||||
116 | public function with( $relations ) |
||||
117 | { |
||||
118 | if ( is_string( $relations ) ) $relations = func_get_args(); |
||||
119 | |||||
120 | $this->with = $relations; |
||||
121 | |||||
122 | return $this; |
||||
123 | } |
||||
124 | |||||
125 | |||||
126 | /** |
||||
127 | * @param CriteriaInterface $criteria |
||||
128 | * @return $this |
||||
129 | */ |
||||
130 | public function addCriteria( CriteriaInterface $criteria) |
||||
131 | { |
||||
132 | $this->criteria[] = $criteria; |
||||
133 | |||||
134 | return $this; |
||||
135 | } |
||||
136 | |||||
137 | |||||
138 | /** |
||||
139 | * @param bool $status |
||||
140 | * @return $this |
||||
141 | */ |
||||
142 | public function skipCriteria( $status = TRUE ) |
||||
143 | { |
||||
144 | $this->skipCriteria = $status; |
||||
145 | return $this; |
||||
146 | } |
||||
147 | |||||
148 | |||||
149 | /** |
||||
150 | * @param int $perPage |
||||
151 | * @param array $columns |
||||
152 | * @return mixed |
||||
153 | */ |
||||
154 | public function paginate($perPage, array $columns = ['*']) |
||||
155 | { |
||||
156 | $this->eagerLoadRelations(); |
||||
157 | $this->applyCriteria(); |
||||
158 | $result = $this->model->paginate( $perPage, $columns ); |
||||
159 | |||||
160 | $this->resetScope(); |
||||
161 | |||||
162 | return $result; |
||||
0 ignored issues
–
show
The expression
return $result returns the type Illuminate\Pagination\LengthAwarePaginator which is incompatible with the return type mandated by OkayBueno\Repositories\R...ryInterface::paginate() of OkayBueno\Repositories\Paginator .
In the issue above, the returned value is violating the contract defined by the mentioned interface. Let's take a look at an example: interface HasName {
/** @return string */
public function getName();
}
class Name {
public $name;
}
class User implements HasName {
/** @return string|Name */
public function getName() {
return new Name('foo'); // This is a violation of the ``HasName`` interface
// which only allows a string value to be returned.
}
}
![]() |
|||||
163 | } |
||||
164 | |||||
165 | |||||
166 | /** |
||||
167 | * @param int $currentPage |
||||
168 | * @return $this |
||||
169 | */ |
||||
170 | public function setCurrentPage( $currentPage ) |
||||
171 | { |
||||
172 | \Illuminate\Pagination\Paginator::currentPageResolver(function() use ( $currentPage ) |
||||
173 | { |
||||
174 | return $currentPage; |
||||
175 | }); |
||||
176 | |||||
177 | return $this; |
||||
178 | } |
||||
179 | |||||
180 | |||||
181 | /** |
||||
182 | * @param array $data |
||||
183 | * @return mixed |
||||
184 | */ |
||||
185 | public function create(array $data) |
||||
186 | { |
||||
187 | $cleanFields = $this->cleanUnfillableFields( $data ); |
||||
188 | |||||
189 | $createdObject = $this->model->create( $cleanFields ); |
||||
190 | |||||
191 | $this->resetScope(); |
||||
192 | |||||
193 | return $createdObject; |
||||
194 | } |
||||
195 | |||||
196 | /** |
||||
197 | * @param array $data |
||||
198 | * @param $value |
||||
199 | * @param string $field |
||||
200 | * @return mixed |
||||
201 | */ |
||||
202 | public function updateBy(array $data, $value = NULL, $field = 'id') |
||||
203 | { |
||||
204 | $cleanFields = $this->cleanUnfillableFields( $data ); |
||||
205 | |||||
206 | if ( !is_null( $value ) ) |
||||
207 | { |
||||
208 | // Single update. |
||||
209 | $this->model->where( $field, $value)->update( $cleanFields ); |
||||
210 | |||||
211 | foreach( $cleanFields as $F => $V ) $this->model->{$F} = $V; |
||||
212 | |||||
213 | $returnedVal = $this->model; |
||||
214 | } else |
||||
215 | { |
||||
216 | // Mass update. |
||||
217 | $this->applyCriteria(); |
||||
218 | |||||
219 | $returnedVal = $this->model->update( $cleanFields ); |
||||
220 | } |
||||
221 | |||||
222 | $this->resetScope(); |
||||
223 | |||||
224 | return $returnedVal; |
||||
225 | } |
||||
226 | |||||
227 | /** |
||||
228 | * @param null $value |
||||
0 ignored issues
–
show
|
|||||
229 | * @param string $field |
||||
230 | * @return bool |
||||
231 | * @throws \Exception |
||||
232 | */ |
||||
233 | public function delete( $value = null, $field = 'id' ) |
||||
234 | { |
||||
235 | $this->applyCriteria(); |
||||
236 | |||||
237 | if ( !is_null( $value ) ) $result = $this->model->where( $field, $value )->delete(); |
||||
0 ignored issues
–
show
|
|||||
238 | else |
||||
239 | { |
||||
240 | if ( !empty( $this->criteria ) ) $result = $this->model->delete(); |
||||
241 | else $result = FALSE; |
||||
242 | } |
||||
243 | |||||
244 | $this->resetScope(); |
||||
245 | |||||
246 | return (bool)$result; |
||||
247 | } |
||||
248 | |||||
249 | /** |
||||
250 | * @return mixed |
||||
251 | */ |
||||
252 | public function count() |
||||
253 | { |
||||
254 | $this->applyCriteria(); |
||||
255 | $result = $this->model->count(); |
||||
256 | |||||
257 | $this->resetScope(); |
||||
258 | |||||
259 | return $result; |
||||
0 ignored issues
–
show
|
|||||
260 | } |
||||
261 | |||||
262 | /** |
||||
263 | * @return $this |
||||
264 | */ |
||||
265 | public function resetScope() |
||||
266 | { |
||||
267 | $this->criteria = []; |
||||
268 | $this->skipCriteria( FALSE ); |
||||
269 | $this->model = new $this->modelClassName(); |
||||
270 | return $this; |
||||
271 | } |
||||
272 | |||||
273 | /** |
||||
274 | * @param null $value |
||||
0 ignored issues
–
show
|
|||||
275 | * @param string $field |
||||
276 | * @return mixed |
||||
277 | */ |
||||
278 | public function destroy($value = null, $field = 'id') |
||||
279 | { |
||||
280 | $this->applyCriteria(); |
||||
281 | |||||
282 | if ( !is_null( $value ) ) $result = $this->model->where( $field, $value )->forceDelete(); |
||||
0 ignored issues
–
show
|
|||||
283 | else |
||||
284 | { |
||||
285 | if ( !empty( $this->criteria ) ) $result = $this->model->forceDelete(); |
||||
286 | else $result = FALSE; |
||||
287 | } |
||||
288 | |||||
289 | $this->resetScope(); |
||||
290 | |||||
291 | return (bool)$result; |
||||
292 | } |
||||
293 | |||||
294 | |||||
295 | /******************************************************************************************************************* |
||||
296 | ******************************************************************************************************************* |
||||
297 | *******************************************************************************************************************/ |
||||
298 | /** |
||||
299 | * |
||||
300 | */ |
||||
301 | protected function eagerLoadRelations() |
||||
302 | { |
||||
303 | if ( is_array( $this->with ) ) |
||||
304 | { |
||||
305 | $with = new With( $this->with ); |
||||
306 | $this->addCriteria( $with ); |
||||
307 | } |
||||
308 | } |
||||
309 | |||||
310 | |||||
311 | /** |
||||
312 | * @param array $data |
||||
313 | * @return array |
||||
314 | */ |
||||
315 | protected function cleanUnfillableFields( array $data ) |
||||
316 | { |
||||
317 | return array_filter($data, function ($key) { |
||||
318 | return $this->model->isFillable($key); |
||||
319 | }, ARRAY_FILTER_USE_KEY); |
||||
320 | } |
||||
321 | |||||
322 | /** |
||||
323 | * @return $this |
||||
324 | */ |
||||
325 | protected function applyCriteria() |
||||
326 | { |
||||
327 | if( !$this->skipCriteria ) |
||||
328 | { |
||||
329 | foreach( $this->criteria as $criteria ) |
||||
330 | { |
||||
331 | if( $criteria instanceof CriteriaInterface ) $this->model = $criteria->apply( $this->model, $this ); |
||||
0 ignored issues
–
show
The call to
OkayBueno\Repositories\C...teriaInterface::apply() has too many arguments starting with $this .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
332 | } |
||||
333 | } |
||||
334 | |||||
335 | return $this; |
||||
336 | } |
||||
337 | } |
||||
338 |