Passed
Push — master ( 7057c8...c1bd78 )
by Jesús
01:56
created

EloquentRepository::updateBy()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 2
nop 3
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
namespace OkayBueno\Repositories\src;
4
5
use OkayBueno\Repositories\Criteria\CriteriaInterface;
6
use OkayBueno\Repositories\RepositoryInterface;
7
use Illuminate\Database\Eloquent\Model;
8
9
/**
10
 * Class EloquentRepository
11
 * @package OkayBueno\Repositories\src
12
 */
13
abstract class EloquentRepository implements RepositoryInterface
14
{
15
    
16
    protected $model;
17
    protected $with;
18
    protected $skipCriteria;
19
    protected $criteria;
20
    private $modelClassName;
21
    
22
    /**
23
     * @param Model $model
24
     */
25
    public function __construct( Model $model )
26
    {
27
        $this->model = $model;
28
        
29
        // A clean copy of the model is needed when the scope needs to be reset.
30
        $reflex = new \ReflectionClass( $model );
31
        $this->modelClassName = $reflex->getName();
32
        
33
        $this->skipCriteria = FALSE;
34
        $this->criteria = [];
35
    }
36
    
37
    /**
38
     * @param $value
39
     * @param string $field
40
     * @param array $columns
41
     * @return mixed
42
     */
43
    public function findOneBy($value = NULL, $field = 'id', array $columns = ['*'])
44
    {
45
        $this->eagerLoadRelations();
46
        $this->applyCriteria();
47
        
48
        if ( !is_null( $value ) ) $this->model = $this->model->where( $field, $value );
49
        
50
        $result = $this->model->first( $columns );
51
        
52
        $this->resetScope();
53
        
54
        return $result;
55
    }
56
    
57
    /**
58
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $field is correct as it would always require null to be passed?
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
59
     * @param null $field
60
     * @param array $columns
61
     * @return mixed
62
     */
63
    public function findAllBy($value = NULL, $field = NULL, array $columns = ['*'])
64
    {
65
        $this->eagerLoadRelations();
66
        $this->applyCriteria();
67
        
68
        if ( !is_null( $value ) && !is_null( $field ) ) $this->model = $this->model->where( $field, $value );
69
        
70
        $result = $this->model->get( $columns );
71
        
72
        $this->resetScope();
73
        
74
        return $result;
75
    }
76
    
77
    /**
78
     * @param array $value
79
     * @param string $field
80
     * @param array $columns
81
     * @return mixed
82
     */
83 View Code Duplication
    public function findAllWhereIn(array $value, $field, array $columns = ['*'])
84
    {
85
        $this->eagerLoadRelations();
86
        $this->applyCriteria();
87
        $result = $this->model->whereIn( $field, $value )->get( $columns );
88
        
89
        $this->resetScope();
90
        
91
        return $result;
92
    }
93
    
94
    /**
95
     * @param array $columns
96
     * @return \Illuminate\Database\Eloquent\Collection|static[]
97
     */
98
    public function findAll( array $columns = ['*'] )
99
    {
100
        $this->eagerLoadRelations();
101
        $result = $this->model->all( $columns );
102
        
103
        $this->resetScope();
104
        
105
        return $result;
106
    }
107
    
108
    /**
109
     * @param array|string $relations
110
     * @return $this
111
     */
112
    public function with( $relations )
113
    {
114
        if ( is_string( $relations ) ) $relations = func_get_args();
115
        
116
        $this->with = $relations;
117
        
118
        return $this;
119
    }
120
    
121
    
122
    /**
123
     * @param CriteriaInterface $criteria
124
     * @return $this
125
     */
126
    public function addCriteria( CriteriaInterface $criteria)
127
    {
128
        $this->criteria[] = $criteria;
129
        
130
        return $this;
131
    }
132
    
133
    
134
    /**
135
     * @param bool $status
136
     * @return $this
137
     */
138
    public function skipCriteria( $status = TRUE )
139
    {
140
        $this->skipCriteria = $status;
141
        return $this;
142
    }
143
    
144
    
145
    /**
146
     * @param int $perPage
147
     * @param array $columns
148
     * @return mixed
149
     */
150 View Code Duplication
    public function paginate($perPage, array $columns = ['*'])
151
    {
152
        $this->eagerLoadRelations();
153
        $this->applyCriteria();
154
        $result = $this->model->paginate( $perPage, $columns );
155
        
156
        $this->resetScope();
157
        
158
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
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.
    }
}
Loading history...
159
    }
160
    
161
    
162
    /**
163
     * @param int $currentPage
164
     * @return $this
165
     */
166
    public function setCurrentPage( $currentPage )
167
    {
168
        \Illuminate\Pagination\Paginator::currentPageResolver(function() use ( $currentPage )
169
        {
170
            return $currentPage;
171
        });
172
        
173
        return $this;
174
    }
175
    
176
    
177
    /**
178
     * @param array $data
179
     * @return mixed
180
     */
181
    public function create(array $data)
182
    {
183
        $cleanFields = $this->cleanUnfillableFields( $data );
184
        
185
        $createdObject = $this->model->create( $cleanFields );
186
        
187
        $this->resetScope();
188
        
189
        return $createdObject;
190
    }
191
    
192
    /**
193
     * @param array $data
194
     * @param $value
195
     * @param string $field
196
     * @return mixed
197
     */
198
    public function updateBy(array $data, $value = NULL, $field = 'id')
199
    {
200
        $cleanFields = $this->cleanUnfillableFields( $data );
201
        
202
        if ( !is_null( $value ) )
203
        {
204
            // Single update.
205
            $this->model->where( $field, $value)->update( $cleanFields );
206
            
207
            foreach( $cleanFields as $F => $V ) $this->model->{$F} = $V;
208
            
209
            $returnedVal = $this->model;
210
        } else
211
        {
212
            // Mass update.
213
            $this->applyCriteria();
214
            
215
            $returnedVal = $this->model->update( $cleanFields );
216
        }
217
        
218
        $this->resetScope();
219
        
220
        return $returnedVal;
221
    }
222
    
223
    /**
224
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
225
     * @param string $field
226
     * @return bool
227
     */
228 View Code Duplication
    public function delete( $value = null, $field = 'id' )
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
    {
230
        $this->applyCriteria();
231
        
232
        if ( !is_null( $value ) ) $result = $this->model->where( $field, $value )->delete();
233
        else
234
        {
235
            if ( !empty( $this->criteria ) ) $result = $this->model->delete();
236
            else $result = FALSE;
237
        }
238
        
239
        $this->resetScope();
240
        
241
        return (bool)$result;
242
    }
243
    
244
    /**
245
     * @return mixed
246
     */
247
    public function count()
248
    {
249
        $this->applyCriteria();
250
        $result = $this->model->count();
251
        
252
        $this->resetScope();
253
        
254
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the return type mandated by OkayBueno\Repositories\R...itoryInterface::count() of integer.
Loading history...
255
    }
256
    
257
    /**
258
     * @return $this
259
     */
260
    public function resetScope()
261
    {
262
        $this->criteria = [];
263
        $this->skipCriteria( FALSE );
264
        $this->model = new $this->modelClassName();
265
        return $this;
266
    }
267
    
268
    /**
269
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
270
     * @param string $field
271
     * @return mixed
272
     */
273 View Code Duplication
    public function destroy($value = null, $field = 'id')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
274
    {
275
        $this->applyCriteria();
276
        
277
        if ( !is_null( $value ) ) $result = $this->model->where( $field, $value )->forceDelete();
278
        else
279
        {
280
            if ( !empty( $this->criteria ) ) $result = $this->model->forceDelete();
281
            else $result = FALSE;
282
        }
283
        
284
        $this->resetScope();
285
        
286
        return (bool)$result;
287
    }
288
    
289
    
290
    /*******************************************************************************************************************
291
     *******************************************************************************************************************
292
     *******************************************************************************************************************/
293
    
294
    /**
295
     *
296
     */
297
    protected function eagerLoadRelations()
298
    {
299
        if ( is_array( $this->with ) ) $this->model->with( $this->with );
300
    }
301
    
302
    
303
    /**
304
     * @param array $data
305
     * @return array
306
     */
307
    private function cleanUnfillableFields( array $data )
308
    {
309
        $fillableFields = $this->model->getFillable();
310
        
311
        foreach( $data as $key => $value )
312
        {
313
            if ( !in_array( $key, $fillableFields ) ) unset( $data[ $key ] );
314
        }
315
        
316
        return $data;
317
    }
318
    
319
    /**
320
     * @return $this
321
     */
322
    private function applyCriteria()
323
    {
324
        if( !$this->skipCriteria )
325
        {
326
            foreach( $this->criteria as $criteria )
327
            {
328
                if( $criteria instanceof CriteriaInterface ) $this->model = $criteria->apply( $this->model, $this );
0 ignored issues
show
Unused Code introduced by
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 ignore-call  annotation

328
                if( $criteria instanceof CriteriaInterface ) $this->model = /** @scrutinizer ignore-call */ $criteria->apply( $this->model, $this );

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.

Loading history...
329
            }
330
        }
331
        
332
        return $this;
333
    }
334
    
335
    
336
}