Completed
Push — 5.1 ( af1a7b...f5b0b1 )
by Rémi
03:26
created

EntityCollection   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 386
Duplicated Lines 15.28 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 16
Bugs 7 Features 1
Metric Value
wmc 40
c 16
b 7
f 1
lcom 1
cbo 6
dl 59
loc 386
rs 8.2608

25 Methods

Rating   Name   Duplication   Size   Complexity  
A push() 0 4 1
A put() 0 4 1
A getEntityKeys() 0 4 1
A pluck() 0 4 1
A lists() 0 4 1
A remove() 0 6 1
A offsetSet() 0 8 2
A getEntityKey() 0 8 1
A __construct() 0 6 1
A find() 0 10 2
A add() 0 6 1
A contains() 0 4 1
A fetch() 0 4 1
A getEntityHashes() 13 13 1
A getSubsetByHashes() 0 18 3
A merge() 0 10 2
A diff() 14 14 3
A intersect() 14 14 3
A only() 0 6 1
A except() 0 6 1
A getDictionary() 0 12 3
A max() 9 9 3
A min() 9 9 3
A unique() 0 6 1
A toBase() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EntityCollection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntityCollection, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Analogue\ORM;
4
5
use Analogue\ORM\Exceptions\MappingException;
6
use Analogue\ORM\System\Manager;
7
use Analogue\ORM\System\Wrappers\Factory;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Arr;
10
11
class EntityCollection extends Collection
12
{
13
    /**
14
     * Wrapper Factory
15
     *
16
     * @var \Analogue\ORM\System\Wrappers\Factory
17
     */
18
    protected $factory;
19
20
    /**
21
     * EntityCollection constructor.
22
     * @param array|null $entities
23
     */
24
    public function __construct(array $entities = null)
25
    {
26
        $this->factory = new Factory;
27
28
        parent::__construct($entities);
29
    }
30
31
    /**
32
     * Find an entity in the collection by key.
33
     *
34
     * @param  mixed $key
35
     * @param  mixed $default
36
     * @throws MappingException
37
     * @return \Analogue\ORM\Entity
38
     */
39
    public function find($key, $default = null)
40
    {
41
        if ($key instanceof Mappable) {
42
            $key = $this->getEntityKey($key);
43
        }
44
45
        return array_first($this->items, function ($itemKey, $entity) use ($key) {
46
            return $this->getEntityKey($entity) == $key;
47
        }, $default);
48
    }
49
50
    /**
51
     * Add an entity to the collection.
52
     *
53
     * @param  Mappable $entity
54
     * @return $this
55
     */
56
    public function add($entity)
57
    {
58
        $this->push($entity);
59
60
        return $this;
61
    }
62
63
    /**
64
     * Remove an entity from the collection
65
     *
66
     * @param $entity
67
     * @throws MappingException
68
     * @return mixed
69
     */
70
    public function remove($entity)
71
    {
72
        $key = $this->getEntityKey($entity);
73
74
        return $this->pull($key);
75
    }
76
77
    /**
78
     * Push an item onto the end of the collection.
79
     *
80
     * @param  mixed $value
81
     * @return void
82
     */
83
    public function push($value)
84
    {
85
        $this->offsetSet(null, $value);
86
    }
87
88
    /**
89
     * Put an item in the collection by key.
90
     *
91
     * @param  mixed $key
92
     * @param  mixed $value
93
     * @return void
94
     */
95
    public function put($key, $value)
96
    {
97
        $this->offsetSet($key, $value);
98
    }
99
100
    /**
101
     * Set the item at a given offset.
102
     *
103
     * @param  mixed $key
104
     * @param  mixed $value
105
     * @return void
106
     */
107
    public function offsetSet($key, $value)
108
    {
109
        if (is_null($key)) {
110
            $this->items[] = $value;
111
        } else {
112
            $this->items[$key] = $value;
113
        }
114
    }
115
116
    /**
117
     * Determine if a key exists in the collection.
118
     *
119
     * @param  mixed      $key
120
     * @param  mixed|null $value
121
     * @return bool
122
     */
123
    public function contains($key, $value = null)
124
    {
125
        return !is_null($this->find($key));
126
    }
127
128
    /**
129
     * Fetch a nested element of the collection.
130
     *
131
     * @param  string $key
132
     * @return self
133
     */
134
    public function fetch($key)
135
    {
136
        return new static(array_fetch($this->toArray(), $key));
137
    }
138
139
    /**
140
     * Generic function for returning class.key value pairs
141
     *
142
     * @throws MappingException
143
     * @return string
144
     */
145 View Code Duplication
    public function getEntityHashes()
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...
146
    {
147
        return array_map(function ($entity) {
148
            $class = get_class($entity);
149
150
            $mapper = Manager::getMapper($class);
151
            
152
            $keyName = $mapper->getEntityMap()->getKeyName();
153
            
154
            return $class . '.' . $entity->getEntityAttribute($keyName);
155
        },
156
        $this->items);
157
    }
158
159
    /**
160
     * Get a subset of the collection from entity hashes
161
     *
162
     * @param  array $hashes
163
     * @throws MappingException
164
     * @return array
165
     */
166
    public function getSubsetByHashes(array $hashes)
167
    {
168
        $subset = [];
169
170
        foreach ($this->items as $item) {
171
            $class = get_class($item);
172
173
            $mapper = Manager::getMapper($class);
174
            
175
            $keyName = $mapper->getEntityMap()->getKeyName();
176
177
            if (in_array($class . '.' . $item->$keyName, $hashes)) {
178
                $subset[] = $item;
179
            }
180
        }
181
182
        return $subset;
183
    }
184
185
    /**
186
     * Merge the collection with the given items.
187
     *
188
     * @param  array $items
189
     * @throws MappingException
190
     * @return self
191
     */
192
    public function merge($items)
193
    {
194
        $dictionary = $this->getDictionary();
195
196
        foreach ($items as $item) {
197
            $dictionary[$this->getEntityKey($item)] = $item;
198
        }
199
200
        return new static(array_values($dictionary));
201
    }
202
203
    /**
204
     * Diff the collection with the given items.
205
     *
206
     * @param  \ArrayAccess|array $items
207
     * @return self
208
     */
209 View Code Duplication
    public function diff($items)
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...
210
    {
211
        $diff = new static;
212
213
        $dictionary = $this->getDictionary($items);
214
215
        foreach ($this->items as $item) {
216
            if (!isset($dictionary[$this->getEntityKey($item)])) {
217
                $diff->add($item);
218
            }
219
        }
220
221
        return $diff;
222
    }
223
224
    /**
225
     * Intersect the collection with the given items.
226
     *
227
     * @param  \ArrayAccess|array $items
228
     * @throws MappingException
229
     * @return self
230
     */
231 View Code Duplication
    public function intersect($items)
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...
232
    {
233
        $intersect = new static;
234
235
        $dictionary = $this->getDictionary($items);
236
237
        foreach ($this->items as $item) {
238
            if (isset($dictionary[$this->getEntityKey($item)])) {
239
                $intersect->add($item);
240
            }
241
        }
242
243
        return $intersect;
244
    }
245
246
    /**
247
     * Returns only the models from the collection with the specified keys.
248
     *
249
     * @param  mixed $keys
250
     * @return self
251
     */
252
    public function only($keys)
253
    {
254
        $dictionary = array_only($this->getDictionary(), $keys);
255
256
        return new static(array_values($dictionary));
257
    }
258
259
    /**
260
     * Returns all models in the collection except the models with specified keys.
261
     *
262
     * @param  mixed $keys
263
     * @return self
264
     */
265
    public function except($keys)
266
    {
267
        $dictionary = array_except($this->getDictionary(), $keys);
268
269
        return new static(array_values($dictionary));
270
    }
271
272
    /**
273
     * Get a dictionary keyed by primary keys.
274
     *
275
     * @param  \ArrayAccess|array $items
276
     * @throws MappingException
277
     * @return array
278
     */
279
    public function getDictionary($items = null)
280
    {
281
        $items = is_null($items) ? $this->items : $items;
282
283
        $dictionary = [];
284
285
        foreach ($items as $value) {
286
            $dictionary[$this->getEntityKey($value)] = $value;
287
        }
288
289
        return $dictionary;
290
    }
291
292
    /**
293
     * @throws MappingException
294
     * @return array
295
     */
296
    public function getEntityKeys()
297
    {
298
        return array_keys($this->getDictionary());
299
    }
300
301
    /**
302
     * @param $entity
303
     * @throws MappingException
304
     * @return mixed
305
     */
306
    protected function getEntityKey($entity)
307
    {
308
        $keyName = Manager::getMapper($entity)->getEntityMap()->getKeyName();
309
        
310
        $wrapper = $this->factory->make($entity);
311
312
        return $wrapper->getEntityAttribute($keyName);
313
    }
314
315
    /**
316
     * Get the max value of a given key.
317
     *
318
     * @param  string|null $key
319
     * @throws MappingException
320
     * @return mixed
321
     */
322 View Code Duplication
    public function max($key = null)
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...
323
    {
324
        return $this->reduce(function ($result, $item) use ($key) {
325
            $wrapper = $this->factory->make($item);
326
327
            return (is_null($result) || $wrapper->getEntityAttribute($key) > $result) ?
328
                $wrapper->getEntityAttribute($key) : $result;
329
        });
330
    }
331
332
    /**
333
     * Get the min value of a given key.
334
     *
335
     * @param  string|null $key
336
     * @throws MappingException
337
     * @return mixed
338
     */
339 View Code Duplication
    public function min($key = null)
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...
340
    {
341
        return $this->reduce(function ($result, $item) use ($key) {
342
            $wrapper = $this->factory->make($item);
343
344
            return (is_null($result) || $wrapper->getEntityAttribute($key) < $result)
345
                ? $wrapper->getEntityAttribute($key) : $result;
346
        });
347
    }
348
349
    /**
350
     * Get an array with the values of a given key.
351
     *
352
     * @param  string $value
353
     * @param  string|null $key
354
     * @return self
355
     */
356
    public function pluck($value, $key = null)
357
    {
358
        return new Collection(Arr::pluck($this->items, $value, $key));
359
    }
360
361
    /**
362
     * Alias for the "pluck" method.
363
     *
364
     * @param  string $value
365
     * @param  string|null $key
366
     * @return self
367
     */
368
    public function lists($value, $key = null)
369
    {
370
        return $this->pluck($value, $key);
371
    }
372
373
    /**
374
     * Return only unique items from the collection.
375
     *
376
     * @param  string|null $key
377
     * @throws MappingException
378
     * @return self
379
     */
380
    public function unique($key = null)
381
    {
382
        $dictionary = $this->getDictionary();
383
384
        return new static(array_values($dictionary));
385
    }
386
387
    /**
388
     * Get a base Support collection instance from this collection.
389
     *
390
     * @return \Illuminate\Support\Collection
391
     */
392
    public function toBase()
393
    {
394
        return new Collection($this->items);
395
    }
396
}
397