Completed
Branch 5.6 (cd95fb)
by Rémi
10:17
created
src/Plugins/AnaloguePlugin.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -6,20 +6,20 @@
 block discarded – undo
6 6
 
7 7
 abstract class AnaloguePlugin implements AnaloguePluginInterface
8 8
 {
9
-    /**
10
-     * Manager instance.
11
-     *
12
-     * @var Manager
13
-     */
14
-    protected $manager;
9
+	/**
10
+	 * Manager instance.
11
+	 *
12
+	 * @var Manager
13
+	 */
14
+	protected $manager;
15 15
 
16
-    /**
17
-     * AnaloguePlugin constructor.
18
-     *
19
-     * @param Manager $manager
20
-     */
21
-    public function __construct(Manager $manager)
22
-    {
23
-        $this->manager = $manager;
24
-    }
16
+	/**
17
+	 * AnaloguePlugin constructor.
18
+	 *
19
+	 * @param Manager $manager
20
+	 */
21
+	public function __construct(Manager $manager)
22
+	{
23
+		$this->manager = $manager;
24
+	}
25 25
 }
Please login to merge, or discard this patch.
src/Plugins/AnaloguePluginInterface.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -4,17 +4,17 @@
 block discarded – undo
4 4
 
5 5
 interface AnaloguePluginInterface
6 6
 {
7
-    /**
8
-     * Boot the plugin.
9
-     *
10
-     * @return void
11
-     */
12
-    public function register();
7
+	/**
8
+	 * Boot the plugin.
9
+	 *
10
+	 * @return void
11
+	 */
12
+	public function register();
13 13
 
14
-    /**
15
-     * Get custom events provided by the plugin.
16
-     *
17
-     * @return array
18
-     */
19
-    public function getCustomEvents(): array;
14
+	/**
15
+	 * Get custom events provided by the plugin.
16
+	 *
17
+	 * @return array
18
+	 */
19
+	public function getCustomEvents(): array;
20 20
 }
Please login to merge, or discard this patch.
src/EntityCollection.php 2 patches
Indentation   +478 added lines, -478 removed lines patch added patch discarded remove patch
@@ -10,482 +10,482 @@
 block discarded – undo
10 10
 
11 11
 class EntityCollection extends Collection
12 12
 {
13
-    /**
14
-     * Wrapper Factory.
15
-     *
16
-     * @var \Analogue\ORM\System\Wrappers\Factory
17
-     */
18
-    protected $factory;
19
-
20
-    /**
21
-     * EntityCollection constructor.
22
-     *
23
-     * @param array|null $entities
24
-     */
25
-    public function __construct(array $entities = null)
26
-    {
27
-        $this->factory = new Factory();
28
-
29
-        parent::__construct($entities);
30
-    }
31
-
32
-    /**
33
-     * Find an entity in the collection by key.
34
-     *
35
-     * @param mixed $key
36
-     * @param mixed $default
37
-     *
38
-     * @throws MappingException
39
-     *
40
-     * @return \Analogue\ORM\Entity
41
-     */
42
-    public function find($key, $default = null)
43
-    {
44
-        if ($key instanceof Mappable) {
45
-            $key = $this->getEntityKey($key);
46
-        }
47
-
48
-        return array_first($this->items, function ($entity, $itemKey) use ($key) {
49
-            return $this->getEntityKey($entity) == $key;
50
-        }, $default);
51
-    }
52
-
53
-    /**
54
-     * Add an entity to the collection.
55
-     *
56
-     * @param Mappable $entity
57
-     *
58
-     * @return $this
59
-     */
60
-    public function add($entity)
61
-    {
62
-        $this->push($entity);
63
-
64
-        return $this;
65
-    }
66
-
67
-    /**
68
-     * Remove an entity from the collection.
69
-     *
70
-     * @param $entity
71
-     *
72
-     * @throws MappingException
73
-     *
74
-     * @return mixed
75
-     */
76
-    public function remove($entity)
77
-    {
78
-        $key = $this->getEntityKey($entity);
79
-
80
-        return $this->pull($key);
81
-    }
82
-
83
-    /**
84
-     * Get and remove an item from the collection.
85
-     *
86
-     * @param mixed $key
87
-     * @param mixed $default
88
-     *
89
-     * @return mixed
90
-     */
91
-    public function pull($key, $default = null)
92
-    {
93
-        $this->items = array_filter($this->items, function ($item) use ($key) {
94
-            $primaryKey = $this->getEntityKey($item);
95
-
96
-            return $primaryKey !== $key;
97
-        });
98
-    }
99
-
100
-    /**
101
-     * Push an item onto the end of the collection.
102
-     *
103
-     * @param mixed $value
104
-     *
105
-     * @return void
106
-     */
107
-    public function push($value)
108
-    {
109
-        $this->offsetSet(null, $value);
110
-    }
111
-
112
-    /**
113
-     * Put an item in the collection by key.
114
-     *
115
-     * @param mixed $key
116
-     * @param mixed $value
117
-     *
118
-     * @return void
119
-     */
120
-    public function put($key, $value)
121
-    {
122
-        $this->offsetSet($key, $value);
123
-    }
124
-
125
-    /**
126
-     * Set the item at a given offset.
127
-     *
128
-     * @param mixed $key
129
-     * @param mixed $value
130
-     *
131
-     * @return void
132
-     */
133
-    public function offsetSet($key, $value)
134
-    {
135
-        if (is_null($key)) {
136
-            $this->items[] = $value;
137
-        } else {
138
-            $this->items[$key] = $value;
139
-        }
140
-    }
141
-
142
-    /**
143
-     * Determine if a key exists in the collection.
144
-     *
145
-     * @param mixed      $key
146
-     * @param mixed|null $value
147
-     *
148
-     * @return bool
149
-     */
150
-    // public function contains($key, $value = null)
151
-    // {
152
-    //     if (func_num_args() == 2) {
153
-    //         return !$this->where($key, $value)->isEmpty();
154
-    //     }
155
-
156
-    //     if ($this->useAsCallable($key)) {
157
-    //         return !is_null($this->first($key));
158
-    //     }
159
-
160
-    //     return !is_null($this->find($key));
161
-    // }
162
-
163
-    /**
164
-     * Fetch a nested element of the collection.
165
-     *
166
-     * @param string $key
167
-     *
168
-     * @return self
169
-     */
170
-    public function fetch($key)
171
-    {
172
-        return new static(array_fetch($this->toArray(), $key));
173
-    }
174
-
175
-    /**
176
-     * Generic function for returning class.key value pairs.
177
-     *
178
-     * @throws MappingException
179
-     *
180
-     * @return string
181
-     */
182
-    public function getEntityHashes()
183
-    {
184
-        return array_map(function ($entity) {
185
-            $class = get_class($entity);
186
-
187
-            $mapper = Manager::getMapper($class);
188
-
189
-            $keyName = $mapper->getEntityMap()->getKeyName();
190
-
191
-            return $class.'.'.$entity->getEntityAttribute($keyName);
192
-        },
193
-        $this->items);
194
-    }
195
-
196
-    /**
197
-     * Get a subset of the collection from entity hashes.
198
-     *
199
-     * @param array $hashes
200
-     *
201
-     * @throws MappingException
202
-     *
203
-     * @return array
204
-     */
205
-    public function getSubsetByHashes(array $hashes)
206
-    {
207
-        $subset = [];
208
-
209
-        foreach ($this->items as $item) {
210
-            $class = get_class($item);
211
-
212
-            $mapper = Manager::getMapper($class);
213
-
214
-            $keyName = $mapper->getEntityMap()->getKeyName();
215
-
216
-            if (in_array($class.'.'.$item->$keyName, $hashes)) {
217
-                $subset[] = $item;
218
-            }
219
-        }
220
-
221
-        return $subset;
222
-    }
223
-
224
-    /**
225
-     * Merge the collection with the given items.
226
-     *
227
-     * @param array $items
228
-     *
229
-     * @throws MappingException
230
-     *
231
-     * @return self
232
-     */
233
-    public function merge($items)
234
-    {
235
-        $dictionary = $this->getDictionary();
236
-
237
-        foreach ($items as $item) {
238
-            $dictionary[$this->getEntityKey($item)] = $item;
239
-        }
240
-
241
-        return new static(array_values($dictionary));
242
-    }
243
-
244
-    /**
245
-     * Diff the collection with the given items.
246
-     *
247
-     * @param \ArrayAccess|array $items
248
-     *
249
-     * @return self
250
-     */
251
-    public function diff($items)
252
-    {
253
-        $diff = new static();
254
-
255
-        $dictionary = $this->getDictionary($items);
256
-
257
-        foreach ($this->items as $item) {
258
-            if (!isset($dictionary[$this->getEntityKey($item)])) {
259
-                $diff->add($item);
260
-            }
261
-        }
262
-
263
-        return $diff;
264
-    }
265
-
266
-    /**
267
-     * Intersect the collection with the given items.
268
-     *
269
-     * @param \ArrayAccess|array $items
270
-     *
271
-     * @throws MappingException
272
-     *
273
-     * @return self
274
-     */
275
-    public function intersect($items)
276
-    {
277
-        $intersect = new static();
278
-
279
-        $dictionary = $this->getDictionary($items);
280
-
281
-        foreach ($this->items as $item) {
282
-            if (isset($dictionary[$this->getEntityKey($item)])) {
283
-                $intersect->add($item);
284
-            }
285
-        }
286
-
287
-        return $intersect;
288
-    }
289
-
290
-    /**
291
-     * Returns only the models from the collection with the specified keys.
292
-     *
293
-     * @param mixed $keys
294
-     *
295
-     * @return self
296
-     */
297
-    public function only($keys)
298
-    {
299
-        $dictionary = array_only($this->getDictionary(), $keys);
300
-
301
-        return new static(array_values($dictionary));
302
-    }
303
-
304
-    /**
305
-     * Returns all models in the collection except the models with specified keys.
306
-     *
307
-     * @param mixed $keys
308
-     *
309
-     * @return self
310
-     */
311
-    public function except($keys)
312
-    {
313
-        $dictionary = array_except($this->getDictionary(), $keys);
314
-
315
-        return new static(array_values($dictionary));
316
-    }
317
-
318
-    /**
319
-     * Get a dictionary keyed by primary keys.
320
-     *
321
-     * @param \ArrayAccess|array $items
322
-     *
323
-     * @throws MappingException
324
-     *
325
-     * @return array
326
-     */
327
-    public function getDictionary($items = null)
328
-    {
329
-        $items = is_null($items) ? $this->items : $items;
330
-
331
-        $dictionary = [];
332
-
333
-        foreach ($items as $value) {
334
-            $dictionary[$this->getEntityKey($value)] = $value;
335
-        }
336
-
337
-        return $dictionary;
338
-    }
339
-
340
-    /**
341
-     * @throws MappingException
342
-     *
343
-     * @return array
344
-     */
345
-    public function getEntityKeys()
346
-    {
347
-        return array_keys($this->getDictionary());
348
-    }
349
-
350
-    /**
351
-     * @param $entity
352
-     *
353
-     * @throws MappingException
354
-     *
355
-     * @return mixed
356
-     */
357
-    protected function getEntityKey($entity)
358
-    {
359
-        $keyName = Manager::getMapper($entity)->getEntityMap()->getKeyName();
360
-
361
-        $wrapper = $this->factory->make($entity);
362
-
363
-        return $wrapper->getEntityAttribute($keyName);
364
-    }
365
-
366
-    /**
367
-     * Get the max value of a given key.
368
-     *
369
-     * @param string|null $key
370
-     *
371
-     * @throws MappingException
372
-     *
373
-     * @return mixed
374
-     */
375
-    public function max($key = null)
376
-    {
377
-        return $this->reduce(function ($result, $item) use ($key) {
378
-            $wrapper = $this->factory->make($item);
379
-
380
-            return (is_null($result) || $wrapper->getEntityAttribute($key) > $result) ?
381
-                $wrapper->getEntityAttribute($key) : $result;
382
-        });
383
-    }
384
-
385
-    /**
386
-     * Get the min value of a given key.
387
-     *
388
-     * @param string|null $key
389
-     *
390
-     * @throws MappingException
391
-     *
392
-     * @return mixed
393
-     */
394
-    public function min($key = null)
395
-    {
396
-        return $this->reduce(function ($result, $item) use ($key) {
397
-            $wrapper = $this->factory->make($item);
398
-
399
-            return (is_null($result) || $wrapper->getEntityAttribute($key) < $result)
400
-                ? $wrapper->getEntityAttribute($key) : $result;
401
-        });
402
-    }
403
-
404
-    /**
405
-     * Get an array with the values of a given key.
406
-     *
407
-     * @param string      $value
408
-     * @param string|null $key
409
-     *
410
-     * @return \Illuminate\Support\Collection
411
-     */
412
-    public function pluck($value, $key = null)
413
-    {
414
-        return new Collection(Arr::pluck($this->items, $value, $key));
415
-    }
416
-
417
-    /**
418
-     * Alias for the "pluck" method.
419
-     *
420
-     * @param string      $value
421
-     * @param string|null $key
422
-     *
423
-     * @return \Illuminate\Support\Collection
424
-     */
425
-    public function lists($value, $key = null)
426
-    {
427
-        return $this->pluck($value, $key);
428
-    }
429
-
430
-    /**
431
-     * Return only unique items from the collection.
432
-     *
433
-     * @param string|null $key
434
-     * @param bool        $strict
435
-     *
436
-     * @throws MappingException
437
-     *
438
-     * @return self
439
-     */
440
-    public function unique($key = null, $strict = false)
441
-    {
442
-        $dictionary = $this->getDictionary();
443
-
444
-        return new static(array_values($dictionary));
445
-    }
446
-
447
-    /**
448
-     * Unset the item at a given offset.
449
-     *
450
-     * @param string $key
451
-     *
452
-     * @return void
453
-     */
454
-    public function offsetUnset($key)
455
-    {
456
-        $this->items = array_filter($this->items, function ($item) use ($key) {
457
-            $primaryKey = $this->getEntityKey($item);
458
-
459
-            return $primaryKey !== $key;
460
-        });
461
-    }
462
-
463
-    /**
464
-     * Get a base Support collection instance from this collection.
465
-     *
466
-     * @return \Illuminate\Support\Collection
467
-     */
468
-    public function toBase()
469
-    {
470
-        return new Collection($this->items);
471
-    }
472
-
473
-    public function toArray()
474
-    {
475
-        return array_values(parent::toArray());
476
-    }
477
-
478
-    /**
479
-     * Get the collection of items as JSON.
480
-     *
481
-     * @param int $options
482
-     *
483
-     * @return string
484
-     */
485
-    public function toJson($options = 0)
486
-    {
487
-        $collection = new Collection(array_values($this->items));
488
-
489
-        return $collection->toJson($options);
490
-    }
13
+	/**
14
+	 * Wrapper Factory.
15
+	 *
16
+	 * @var \Analogue\ORM\System\Wrappers\Factory
17
+	 */
18
+	protected $factory;
19
+
20
+	/**
21
+	 * EntityCollection constructor.
22
+	 *
23
+	 * @param array|null $entities
24
+	 */
25
+	public function __construct(array $entities = null)
26
+	{
27
+		$this->factory = new Factory();
28
+
29
+		parent::__construct($entities);
30
+	}
31
+
32
+	/**
33
+	 * Find an entity in the collection by key.
34
+	 *
35
+	 * @param mixed $key
36
+	 * @param mixed $default
37
+	 *
38
+	 * @throws MappingException
39
+	 *
40
+	 * @return \Analogue\ORM\Entity
41
+	 */
42
+	public function find($key, $default = null)
43
+	{
44
+		if ($key instanceof Mappable) {
45
+			$key = $this->getEntityKey($key);
46
+		}
47
+
48
+		return array_first($this->items, function ($entity, $itemKey) use ($key) {
49
+			return $this->getEntityKey($entity) == $key;
50
+		}, $default);
51
+	}
52
+
53
+	/**
54
+	 * Add an entity to the collection.
55
+	 *
56
+	 * @param Mappable $entity
57
+	 *
58
+	 * @return $this
59
+	 */
60
+	public function add($entity)
61
+	{
62
+		$this->push($entity);
63
+
64
+		return $this;
65
+	}
66
+
67
+	/**
68
+	 * Remove an entity from the collection.
69
+	 *
70
+	 * @param $entity
71
+	 *
72
+	 * @throws MappingException
73
+	 *
74
+	 * @return mixed
75
+	 */
76
+	public function remove($entity)
77
+	{
78
+		$key = $this->getEntityKey($entity);
79
+
80
+		return $this->pull($key);
81
+	}
82
+
83
+	/**
84
+	 * Get and remove an item from the collection.
85
+	 *
86
+	 * @param mixed $key
87
+	 * @param mixed $default
88
+	 *
89
+	 * @return mixed
90
+	 */
91
+	public function pull($key, $default = null)
92
+	{
93
+		$this->items = array_filter($this->items, function ($item) use ($key) {
94
+			$primaryKey = $this->getEntityKey($item);
95
+
96
+			return $primaryKey !== $key;
97
+		});
98
+	}
99
+
100
+	/**
101
+	 * Push an item onto the end of the collection.
102
+	 *
103
+	 * @param mixed $value
104
+	 *
105
+	 * @return void
106
+	 */
107
+	public function push($value)
108
+	{
109
+		$this->offsetSet(null, $value);
110
+	}
111
+
112
+	/**
113
+	 * Put an item in the collection by key.
114
+	 *
115
+	 * @param mixed $key
116
+	 * @param mixed $value
117
+	 *
118
+	 * @return void
119
+	 */
120
+	public function put($key, $value)
121
+	{
122
+		$this->offsetSet($key, $value);
123
+	}
124
+
125
+	/**
126
+	 * Set the item at a given offset.
127
+	 *
128
+	 * @param mixed $key
129
+	 * @param mixed $value
130
+	 *
131
+	 * @return void
132
+	 */
133
+	public function offsetSet($key, $value)
134
+	{
135
+		if (is_null($key)) {
136
+			$this->items[] = $value;
137
+		} else {
138
+			$this->items[$key] = $value;
139
+		}
140
+	}
141
+
142
+	/**
143
+	 * Determine if a key exists in the collection.
144
+	 *
145
+	 * @param mixed      $key
146
+	 * @param mixed|null $value
147
+	 *
148
+	 * @return bool
149
+	 */
150
+	// public function contains($key, $value = null)
151
+	// {
152
+	//     if (func_num_args() == 2) {
153
+	//         return !$this->where($key, $value)->isEmpty();
154
+	//     }
155
+
156
+	//     if ($this->useAsCallable($key)) {
157
+	//         return !is_null($this->first($key));
158
+	//     }
159
+
160
+	//     return !is_null($this->find($key));
161
+	// }
162
+
163
+	/**
164
+	 * Fetch a nested element of the collection.
165
+	 *
166
+	 * @param string $key
167
+	 *
168
+	 * @return self
169
+	 */
170
+	public function fetch($key)
171
+	{
172
+		return new static(array_fetch($this->toArray(), $key));
173
+	}
174
+
175
+	/**
176
+	 * Generic function for returning class.key value pairs.
177
+	 *
178
+	 * @throws MappingException
179
+	 *
180
+	 * @return string
181
+	 */
182
+	public function getEntityHashes()
183
+	{
184
+		return array_map(function ($entity) {
185
+			$class = get_class($entity);
186
+
187
+			$mapper = Manager::getMapper($class);
188
+
189
+			$keyName = $mapper->getEntityMap()->getKeyName();
190
+
191
+			return $class.'.'.$entity->getEntityAttribute($keyName);
192
+		},
193
+		$this->items);
194
+	}
195
+
196
+	/**
197
+	 * Get a subset of the collection from entity hashes.
198
+	 *
199
+	 * @param array $hashes
200
+	 *
201
+	 * @throws MappingException
202
+	 *
203
+	 * @return array
204
+	 */
205
+	public function getSubsetByHashes(array $hashes)
206
+	{
207
+		$subset = [];
208
+
209
+		foreach ($this->items as $item) {
210
+			$class = get_class($item);
211
+
212
+			$mapper = Manager::getMapper($class);
213
+
214
+			$keyName = $mapper->getEntityMap()->getKeyName();
215
+
216
+			if (in_array($class.'.'.$item->$keyName, $hashes)) {
217
+				$subset[] = $item;
218
+			}
219
+		}
220
+
221
+		return $subset;
222
+	}
223
+
224
+	/**
225
+	 * Merge the collection with the given items.
226
+	 *
227
+	 * @param array $items
228
+	 *
229
+	 * @throws MappingException
230
+	 *
231
+	 * @return self
232
+	 */
233
+	public function merge($items)
234
+	{
235
+		$dictionary = $this->getDictionary();
236
+
237
+		foreach ($items as $item) {
238
+			$dictionary[$this->getEntityKey($item)] = $item;
239
+		}
240
+
241
+		return new static(array_values($dictionary));
242
+	}
243
+
244
+	/**
245
+	 * Diff the collection with the given items.
246
+	 *
247
+	 * @param \ArrayAccess|array $items
248
+	 *
249
+	 * @return self
250
+	 */
251
+	public function diff($items)
252
+	{
253
+		$diff = new static();
254
+
255
+		$dictionary = $this->getDictionary($items);
256
+
257
+		foreach ($this->items as $item) {
258
+			if (!isset($dictionary[$this->getEntityKey($item)])) {
259
+				$diff->add($item);
260
+			}
261
+		}
262
+
263
+		return $diff;
264
+	}
265
+
266
+	/**
267
+	 * Intersect the collection with the given items.
268
+	 *
269
+	 * @param \ArrayAccess|array $items
270
+	 *
271
+	 * @throws MappingException
272
+	 *
273
+	 * @return self
274
+	 */
275
+	public function intersect($items)
276
+	{
277
+		$intersect = new static();
278
+
279
+		$dictionary = $this->getDictionary($items);
280
+
281
+		foreach ($this->items as $item) {
282
+			if (isset($dictionary[$this->getEntityKey($item)])) {
283
+				$intersect->add($item);
284
+			}
285
+		}
286
+
287
+		return $intersect;
288
+	}
289
+
290
+	/**
291
+	 * Returns only the models from the collection with the specified keys.
292
+	 *
293
+	 * @param mixed $keys
294
+	 *
295
+	 * @return self
296
+	 */
297
+	public function only($keys)
298
+	{
299
+		$dictionary = array_only($this->getDictionary(), $keys);
300
+
301
+		return new static(array_values($dictionary));
302
+	}
303
+
304
+	/**
305
+	 * Returns all models in the collection except the models with specified keys.
306
+	 *
307
+	 * @param mixed $keys
308
+	 *
309
+	 * @return self
310
+	 */
311
+	public function except($keys)
312
+	{
313
+		$dictionary = array_except($this->getDictionary(), $keys);
314
+
315
+		return new static(array_values($dictionary));
316
+	}
317
+
318
+	/**
319
+	 * Get a dictionary keyed by primary keys.
320
+	 *
321
+	 * @param \ArrayAccess|array $items
322
+	 *
323
+	 * @throws MappingException
324
+	 *
325
+	 * @return array
326
+	 */
327
+	public function getDictionary($items = null)
328
+	{
329
+		$items = is_null($items) ? $this->items : $items;
330
+
331
+		$dictionary = [];
332
+
333
+		foreach ($items as $value) {
334
+			$dictionary[$this->getEntityKey($value)] = $value;
335
+		}
336
+
337
+		return $dictionary;
338
+	}
339
+
340
+	/**
341
+	 * @throws MappingException
342
+	 *
343
+	 * @return array
344
+	 */
345
+	public function getEntityKeys()
346
+	{
347
+		return array_keys($this->getDictionary());
348
+	}
349
+
350
+	/**
351
+	 * @param $entity
352
+	 *
353
+	 * @throws MappingException
354
+	 *
355
+	 * @return mixed
356
+	 */
357
+	protected function getEntityKey($entity)
358
+	{
359
+		$keyName = Manager::getMapper($entity)->getEntityMap()->getKeyName();
360
+
361
+		$wrapper = $this->factory->make($entity);
362
+
363
+		return $wrapper->getEntityAttribute($keyName);
364
+	}
365
+
366
+	/**
367
+	 * Get the max value of a given key.
368
+	 *
369
+	 * @param string|null $key
370
+	 *
371
+	 * @throws MappingException
372
+	 *
373
+	 * @return mixed
374
+	 */
375
+	public function max($key = null)
376
+	{
377
+		return $this->reduce(function ($result, $item) use ($key) {
378
+			$wrapper = $this->factory->make($item);
379
+
380
+			return (is_null($result) || $wrapper->getEntityAttribute($key) > $result) ?
381
+				$wrapper->getEntityAttribute($key) : $result;
382
+		});
383
+	}
384
+
385
+	/**
386
+	 * Get the min value of a given key.
387
+	 *
388
+	 * @param string|null $key
389
+	 *
390
+	 * @throws MappingException
391
+	 *
392
+	 * @return mixed
393
+	 */
394
+	public function min($key = null)
395
+	{
396
+		return $this->reduce(function ($result, $item) use ($key) {
397
+			$wrapper = $this->factory->make($item);
398
+
399
+			return (is_null($result) || $wrapper->getEntityAttribute($key) < $result)
400
+				? $wrapper->getEntityAttribute($key) : $result;
401
+		});
402
+	}
403
+
404
+	/**
405
+	 * Get an array with the values of a given key.
406
+	 *
407
+	 * @param string      $value
408
+	 * @param string|null $key
409
+	 *
410
+	 * @return \Illuminate\Support\Collection
411
+	 */
412
+	public function pluck($value, $key = null)
413
+	{
414
+		return new Collection(Arr::pluck($this->items, $value, $key));
415
+	}
416
+
417
+	/**
418
+	 * Alias for the "pluck" method.
419
+	 *
420
+	 * @param string      $value
421
+	 * @param string|null $key
422
+	 *
423
+	 * @return \Illuminate\Support\Collection
424
+	 */
425
+	public function lists($value, $key = null)
426
+	{
427
+		return $this->pluck($value, $key);
428
+	}
429
+
430
+	/**
431
+	 * Return only unique items from the collection.
432
+	 *
433
+	 * @param string|null $key
434
+	 * @param bool        $strict
435
+	 *
436
+	 * @throws MappingException
437
+	 *
438
+	 * @return self
439
+	 */
440
+	public function unique($key = null, $strict = false)
441
+	{
442
+		$dictionary = $this->getDictionary();
443
+
444
+		return new static(array_values($dictionary));
445
+	}
446
+
447
+	/**
448
+	 * Unset the item at a given offset.
449
+	 *
450
+	 * @param string $key
451
+	 *
452
+	 * @return void
453
+	 */
454
+	public function offsetUnset($key)
455
+	{
456
+		$this->items = array_filter($this->items, function ($item) use ($key) {
457
+			$primaryKey = $this->getEntityKey($item);
458
+
459
+			return $primaryKey !== $key;
460
+		});
461
+	}
462
+
463
+	/**
464
+	 * Get a base Support collection instance from this collection.
465
+	 *
466
+	 * @return \Illuminate\Support\Collection
467
+	 */
468
+	public function toBase()
469
+	{
470
+		return new Collection($this->items);
471
+	}
472
+
473
+	public function toArray()
474
+	{
475
+		return array_values(parent::toArray());
476
+	}
477
+
478
+	/**
479
+	 * Get the collection of items as JSON.
480
+	 *
481
+	 * @param int $options
482
+	 *
483
+	 * @return string
484
+	 */
485
+	public function toJson($options = 0)
486
+	{
487
+		$collection = new Collection(array_values($this->items));
488
+
489
+		return $collection->toJson($options);
490
+	}
491 491
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -45,7 +45,7 @@  discard block
 block discarded – undo
45 45
             $key = $this->getEntityKey($key);
46 46
         }
47 47
 
48
-        return array_first($this->items, function ($entity, $itemKey) use ($key) {
48
+        return array_first($this->items, function($entity, $itemKey) use ($key) {
49 49
             return $this->getEntityKey($entity) == $key;
50 50
         }, $default);
51 51
     }
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
      */
91 91
     public function pull($key, $default = null)
92 92
     {
93
-        $this->items = array_filter($this->items, function ($item) use ($key) {
93
+        $this->items = array_filter($this->items, function($item) use ($key) {
94 94
             $primaryKey = $this->getEntityKey($item);
95 95
 
96 96
             return $primaryKey !== $key;
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
      */
182 182
     public function getEntityHashes()
183 183
     {
184
-        return array_map(function ($entity) {
184
+        return array_map(function($entity) {
185 185
             $class = get_class($entity);
186 186
 
187 187
             $mapper = Manager::getMapper($class);
@@ -374,7 +374,7 @@  discard block
 block discarded – undo
374 374
      */
375 375
     public function max($key = null)
376 376
     {
377
-        return $this->reduce(function ($result, $item) use ($key) {
377
+        return $this->reduce(function($result, $item) use ($key) {
378 378
             $wrapper = $this->factory->make($item);
379 379
 
380 380
             return (is_null($result) || $wrapper->getEntityAttribute($key) > $result) ?
@@ -393,7 +393,7 @@  discard block
 block discarded – undo
393 393
      */
394 394
     public function min($key = null)
395 395
     {
396
-        return $this->reduce(function ($result, $item) use ($key) {
396
+        return $this->reduce(function($result, $item) use ($key) {
397 397
             $wrapper = $this->factory->make($item);
398 398
 
399 399
             return (is_null($result) || $wrapper->getEntityAttribute($key) < $result)
@@ -453,7 +453,7 @@  discard block
 block discarded – undo
453 453
      */
454 454
     public function offsetUnset($key)
455 455
     {
456
-        $this->items = array_filter($this->items, function ($item) use ($key) {
456
+        $this->items = array_filter($this->items, function($item) use ($key) {
457 457
             $primaryKey = $this->getEntityKey($item);
458 458
 
459 459
             return $primaryKey !== $key;
Please login to merge, or discard this patch.
src/ValueObject.php 1 patch
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -12,8 +12,8 @@
 block discarded – undo
12 12
  */
13 13
 class ValueObject implements Mappable, ArrayAccess, Jsonable, JsonSerializable, Arrayable
14 14
 {
15
-    use MappableTrait;
16
-    use MagicGetters;
17
-    use MagicSetters;
18
-    use MagicCasting;
15
+	use MappableTrait;
16
+	use MagicGetters;
17
+	use MagicSetters;
18
+	use MagicCasting;
19 19
 }
Please login to merge, or discard this patch.
src/Repository.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,7 @@
 block discarded – undo
31 31
      * - Mappable object instance
32 32
      * - Instance of mapper
33 33
      *
34
-     * @param Mapper|Mappable|string $mapper
34
+     * @param Mapper $mapper
35 35
      * @param EntityMap|null         $entityMap (optional)
36 36
      *
37 37
      * @throws \InvalidArgumentException
Please login to merge, or discard this patch.
Indentation   +128 added lines, -128 removed lines patch added patch discarded remove patch
@@ -17,141 +17,141 @@
 block discarded – undo
17 17
  */
18 18
 class Repository
19 19
 {
20
-    /**
21
-     * The mapper object for the corresponding entity.
22
-     *
23
-     * @var \Analogue\ORM\System\Mapper
24
-     */
25
-    protected $mapper;
20
+	/**
21
+	 * The mapper object for the corresponding entity.
22
+	 *
23
+	 * @var \Analogue\ORM\System\Mapper
24
+	 */
25
+	protected $mapper;
26 26
 
27
-    /**
28
-     * To build a repository, either provide :.
29
-     *
30
-     * - Mappable object's class name as a string
31
-     * - Mappable object instance
32
-     * - Instance of mapper
33
-     *
34
-     * @param Mapper|Mappable|string $mapper
35
-     * @param EntityMap|null         $entityMap (optional)
36
-     *
37
-     * @throws \InvalidArgumentException
38
-     * @throws MappingException
39
-     */
40
-    public function __construct($mapper, EntityMap $entityMap = null)
41
-    {
42
-        if ($mapper instanceof Mappable || is_string($mapper)) {
43
-            $this->mapper = Manager::getMapper($mapper, $entityMap);
44
-        } elseif ($mapper instanceof Mapper) {
45
-            $this->mapper = $mapper;
46
-        } else {
47
-            new InvalidArgumentException('Repository class constructor need a valid Mapper or Mappable object.');
48
-        }
49
-    }
27
+	/**
28
+	 * To build a repository, either provide :.
29
+	 *
30
+	 * - Mappable object's class name as a string
31
+	 * - Mappable object instance
32
+	 * - Instance of mapper
33
+	 *
34
+	 * @param Mapper|Mappable|string $mapper
35
+	 * @param EntityMap|null         $entityMap (optional)
36
+	 *
37
+	 * @throws \InvalidArgumentException
38
+	 * @throws MappingException
39
+	 */
40
+	public function __construct($mapper, EntityMap $entityMap = null)
41
+	{
42
+		if ($mapper instanceof Mappable || is_string($mapper)) {
43
+			$this->mapper = Manager::getMapper($mapper, $entityMap);
44
+		} elseif ($mapper instanceof Mapper) {
45
+			$this->mapper = $mapper;
46
+		} else {
47
+			new InvalidArgumentException('Repository class constructor need a valid Mapper or Mappable object.');
48
+		}
49
+	}
50 50
 
51
-    /**
52
-     * Return all Entities from database.
53
-     *
54
-     * @return \Illuminate\Support\Collection
55
-     */
56
-    public function all()
57
-    {
58
-        return $this->mapper->get();
59
-    }
51
+	/**
52
+	 * Return all Entities from database.
53
+	 *
54
+	 * @return \Illuminate\Support\Collection
55
+	 */
56
+	public function all()
57
+	{
58
+		return $this->mapper->get();
59
+	}
60 60
 
61
-    /**
62
-     * Fetch a record from the database.
63
-     *
64
-     * @param int $id
65
-     *
66
-     * @return \Analogue\ORM\Mappable
67
-     */
68
-    public function find($id)
69
-    {
70
-        return $this->mapper->find($id);
71
-    }
61
+	/**
62
+	 * Fetch a record from the database.
63
+	 *
64
+	 * @param int $id
65
+	 *
66
+	 * @return \Analogue\ORM\Mappable
67
+	 */
68
+	public function find($id)
69
+	{
70
+		return $this->mapper->find($id);
71
+	}
72 72
 
73
-    /**
74
-     * Get the first entity matching the given attributes.
75
-     *
76
-     * @param array $attributes
77
-     *
78
-     * @return \Analogue\ORM\Mappable|null
79
-     */
80
-    public function firstMatching(array $attributes)
81
-    {
82
-        return $this->mapper->where($attributes)->first();
83
-    }
73
+	/**
74
+	 * Get the first entity matching the given attributes.
75
+	 *
76
+	 * @param array $attributes
77
+	 *
78
+	 * @return \Analogue\ORM\Mappable|null
79
+	 */
80
+	public function firstMatching(array $attributes)
81
+	{
82
+		return $this->mapper->where($attributes)->first();
83
+	}
84 84
 
85
-    /**
86
-     * Return all the entities matching the given attributes.
87
-     *
88
-     * @param array $attributes
89
-     *
90
-     * @return \Analogue\ORM\EntityCollection
91
-     */
92
-    public function allMatching(array $attributes)
93
-    {
94
-        return $this->mapper->where($attributes)->get();
95
-    }
85
+	/**
86
+	 * Return all the entities matching the given attributes.
87
+	 *
88
+	 * @param array $attributes
89
+	 *
90
+	 * @return \Analogue\ORM\EntityCollection
91
+	 */
92
+	public function allMatching(array $attributes)
93
+	{
94
+		return $this->mapper->where($attributes)->get();
95
+	}
96 96
 
97
-    /**
98
-     * Return a paginator instance on the EntityCollection.
99
-     *
100
-     * @param int|null $perPage number of item per page (fallback on default setup in entity map)
101
-     *
102
-     * @return \Illuminate\Pagination\LengthAwarePaginator
103
-     */
104
-    public function paginate($perPage = null)
105
-    {
106
-        return $this->mapper->paginate($perPage);
107
-    }
97
+	/**
98
+	 * Return a paginator instance on the EntityCollection.
99
+	 *
100
+	 * @param int|null $perPage number of item per page (fallback on default setup in entity map)
101
+	 *
102
+	 * @return \Illuminate\Pagination\LengthAwarePaginator
103
+	 */
104
+	public function paginate($perPage = null)
105
+	{
106
+		return $this->mapper->paginate($perPage);
107
+	}
108 108
 
109
-    /**
110
-     * Delete an entity or an entity collection from the database.
111
-     *
112
-     * @param Mappable|EntityCollection $entity
113
-     *
114
-     * @throws MappingException
115
-     * @throws \InvalidArgumentException
116
-     *
117
-     * @return \Illuminate\Support\Collection|null
118
-     */
119
-    public function delete($entity)
120
-    {
121
-        return $this->mapper->delete($entity);
122
-    }
109
+	/**
110
+	 * Delete an entity or an entity collection from the database.
111
+	 *
112
+	 * @param Mappable|EntityCollection $entity
113
+	 *
114
+	 * @throws MappingException
115
+	 * @throws \InvalidArgumentException
116
+	 *
117
+	 * @return \Illuminate\Support\Collection|null
118
+	 */
119
+	public function delete($entity)
120
+	{
121
+		return $this->mapper->delete($entity);
122
+	}
123 123
 
124
-    /**
125
-     * Persist an entity or an entity collection in the database.
126
-     *
127
-     * @param Mappable|EntityCollection|array $entity
128
-     *
129
-     * @throws MappingException
130
-     * @throws \InvalidArgumentException
131
-     *
132
-     * @return Mappable|EntityCollection|array
133
-     */
134
-    public function store($entity)
135
-    {
136
-        return $this->mapper->store($entity);
137
-    }
124
+	/**
125
+	 * Persist an entity or an entity collection in the database.
126
+	 *
127
+	 * @param Mappable|EntityCollection|array $entity
128
+	 *
129
+	 * @throws MappingException
130
+	 * @throws \InvalidArgumentException
131
+	 *
132
+	 * @return Mappable|EntityCollection|array
133
+	 */
134
+	public function store($entity)
135
+	{
136
+		return $this->mapper->store($entity);
137
+	}
138 138
 
139
-    /**
140
-     * Make custom mapper custom commands available in repository.
141
-     *
142
-     * @param string $method
143
-     * @param array  $parameters
144
-     *
145
-     * @throws Exception
146
-     *
147
-     * @return mixed
148
-     */
149
-    public function __call($method, $parameters)
150
-    {
151
-        if ($this->mapper->hasCustomCommand($method)) {
152
-            call_user_func_array([$this->mapper, $method], $parameters);
153
-        } else {
154
-            throw new Exception("No method $method on ".get_class($this));
155
-        }
156
-    }
139
+	/**
140
+	 * Make custom mapper custom commands available in repository.
141
+	 *
142
+	 * @param string $method
143
+	 * @param array  $parameters
144
+	 *
145
+	 * @throws Exception
146
+	 *
147
+	 * @return mixed
148
+	 */
149
+	public function __call($method, $parameters)
150
+	{
151
+		if ($this->mapper->hasCustomCommand($method)) {
152
+			call_user_func_array([$this->mapper, $method], $parameters);
153
+		} else {
154
+			throw new Exception("No method $method on ".get_class($this));
155
+		}
156
+	}
157 157
 }
Please login to merge, or discard this patch.
src/System/Proxies/CollectionProxy.php 1 patch
Indentation   +1292 added lines, -1292 removed lines patch added patch discarded remove patch
@@ -11,1296 +11,1296 @@
 block discarded – undo
11 11
 
12 12
 class CollectionProxy extends EntityCollection implements ProxyInterface
13 13
 {
14
-    /**
15
-     * Indicate if the relationship has been lazy loaded.
16
-     *
17
-     * @var bool
18
-     */
19
-    protected $relationshipLoaded = false;
20
-
21
-    /**
22
-     * Added items.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $addedItems = [];
27
-
28
-    /**
29
-     * Parent entity.
30
-     *
31
-     * @var \Analogue\ORM\Mappable|string
32
-     */
33
-    protected $parentEntity;
34
-
35
-    /**
36
-     * Relationship.
37
-     *
38
-     * @var string
39
-     */
40
-    protected $relationshipMethod;
41
-
42
-    /**
43
-     * Create a new collection.
44
-     *
45
-     * @param mixed  $entity
46
-     * @param string $relation
47
-     */
48
-    public function __construct($entity, $relation)
49
-    {
50
-        $this->parentEntity = $entity;
51
-        $this->relationshipMethod = $relation;
52
-        parent::__construct();
53
-    }
54
-
55
-    /**
56
-     * Return Items that has been added without lazy loading
57
-     * the underlying collection.
58
-     *
59
-     * @return array
60
-     */
61
-    public function getAddedItems()
62
-    {
63
-        return $this->addedItems;
64
-    }
65
-
66
-    /**
67
-     * Force initialization of the proxy.
68
-     *
69
-     * @return bool true if the proxy could be initialized
70
-     */
71
-    public function initializeProxy() : bool
72
-    {
73
-        if ($this->isProxyInitialized()) {
74
-            return true;
75
-        }
76
-
77
-        $this->items = $this->getRelationshipInstance()
78
-            ->getResults($this->relationshipMethod)->all() + $this->addedItems;
79
-
80
-        $this->relationshipLoaded = true;
81
-
82
-        return true;
83
-    }
84
-
85
-    /**
86
-     * Return instance of the underlying relationship.
87
-     *
88
-     * @return Relationship
89
-     */
90
-    protected function getRelationshipInstance() : Relationship
91
-    {
92
-        $relation = $this->relationshipMethod;
93
-        $entity = $this->parentEntity;
94
-        $entityMap = Manager::getMapper($entity)->getEntityMap();
95
-
96
-        return $entityMap->$relation($entity);
97
-    }
98
-
99
-    /**
100
-     * {@inheritdoc}
101
-     */
102
-    public function isProxyInitialized() : bool
103
-    {
104
-        return $this->relationshipLoaded;
105
-    }
106
-
107
-    /**
108
-     * {@inheritdoc}
109
-     */
110
-    protected function toBaseCollection() : Collection
111
-    {
112
-        return new Collection($this->items);
113
-    }
114
-
115
-    /**
116
-     * {@inheritdoc}
117
-     */
118
-    public function all()
119
-    {
120
-        $this->initializeProxy();
121
-
122
-        return parent::all();
123
-    }
124
-
125
-    /**
126
-     * {@inheritdoc}
127
-     */
128
-    public function avg($callback = null)
129
-    {
130
-        $this->initializeProxy();
131
-
132
-        return parent::avg($callback);
133
-    }
134
-
135
-    /**
136
-     * {@inheritdoc}
137
-     */
138
-    public function median($key = null)
139
-    {
140
-        $this->initializeProxy();
141
-
142
-        return parent::median($key);
143
-    }
144
-
145
-    /**
146
-     * {@inheritdoc}
147
-     */
148
-    public function mode($key = null)
149
-    {
150
-        $this->initializeProxy();
151
-
152
-        return parent::mode($key);
153
-    }
154
-
155
-    /**
156
-     * {@inheritdoc}
157
-     */
158
-    public function collapse()
159
-    {
160
-        $this->initializeProxy();
161
-
162
-        $parent = $this->toBaseCollection();
163
-
164
-        return $parent->collapse();
165
-    }
166
-
167
-    /**
168
-     * {@inheritdoc}
169
-     */
170
-    public function contains($key, $operator = null, $value = null)
171
-    {
172
-        $this->initializeProxy();
173
-
174
-        $parent = $this->toBaseCollection();
175
-
176
-        switch (func_num_args()) {
177
-            case 1:
178
-                return $parent->contains($key);
179
-            case 2:
180
-                return $parent->contains($key, $operator);
181
-            case 3:
182
-                return $parent->contains($key, $operator, $value);
183
-        }
184
-    }
185
-
186
-    /**
187
-     * {@inheritdoc}
188
-     */
189
-    public function containsStrict($key, $value = null)
190
-    {
191
-        $this->initializeProxy();
192
-
193
-        switch (func_num_args()) {
194
-            case 1:
195
-                return parent::containsStrict($key);
196
-            case 2:
197
-                return parent::containsStrict($key, $value);
198
-        }
199
-    }
200
-
201
-    /**
202
-     * {@inheritdoc}
203
-     */
204
-    public function diff($items)
205
-    {
206
-        $this->initializeProxy();
207
-
208
-        $parent = $this->toBaseCollection();
209
-
210
-        return $parent->diff($items);
211
-    }
212
-
213
-    /**
214
-     * {@inheritdoc}
215
-     */
216
-    public function diffUsing($items, callable $callback)
217
-    {
218
-        $this->initializeProxy();
219
-
220
-        $parent = $this->toBaseCollection();
221
-
222
-        return $parent->diffUsing($items, $callback);
223
-    }
224
-
225
-    /**
226
-     * {@inheritdoc}
227
-     */
228
-    public function diffAssocUsing($items, callable $callback)
229
-    {
230
-        $this->initializeProxy();
231
-
232
-        $parent = $this->toBaseCollection();
233
-
234
-        return $parent->diffAssocUsing($items, $callback);
235
-    }
236
-
237
-    /**
238
-     * {@inheritdoc}
239
-     */
240
-    public function diffKeys($items)
241
-    {
242
-        $this->initializeProxy();
243
-
244
-        $parent = $this->toBaseCollection();
245
-
246
-        return $parent->diffKeys($items);
247
-    }
248
-
249
-    /**
250
-     * {@inheritdoc}
251
-     */
252
-    public function diffKeysUsing($items, callable $callback)
253
-    {
254
-        $this->initializeProxy();
255
-
256
-        $parent = $this->toBaseCollection();
257
-
258
-        return $parent->diffKeysUsing($items);
259
-    }
260
-
261
-    /**
262
-     * {@inheritdoc}
263
-     */
264
-    public function each(callable $callback)
265
-    {
266
-        $this->initializeProxy();
267
-
268
-        return parent::each($callback);
269
-    }
270
-
271
-    /**
272
-     * {@inheritdoc}
273
-     */
274
-    public function every($key, $operator = null, $value = null)
275
-    {
276
-        $this->initializeProxy();
277
-
278
-        $parent = $this->toBaseCollection();
279
-
280
-        switch (func_num_args()) {
281
-            case 1:
282
-                return $parent->every($key);
283
-            case 2:
284
-                return $parent->every($key, $operator);
285
-            case 3:
286
-                return $parent->every($key, $operator, $value);
287
-        }
288
-    }
289
-
290
-    /**
291
-     * {@inheritdoc}
292
-     */
293
-    public function except($keys)
294
-    {
295
-        $this->initializeProxy();
296
-
297
-        $parent = $this->toBaseCollection();
298
-
299
-        return $parent->except($keys);
300
-    }
301
-
302
-    /**
303
-     * {@inheritdoc}
304
-     */
305
-    public function filter(callable $callback = null)
306
-    {
307
-        $this->initializeProxy();
308
-
309
-        $parent = $this->toBaseCollection();
310
-
311
-        return $parent->filter($callback);
312
-    }
313
-
314
-    /**
315
-     * {@inheritdoc}
316
-     */
317
-    public function firstWhere($key, $operator, $value = null)
318
-    {
319
-        $this->initializeProxy();
320
-
321
-        $parent = $this->toBaseCollection();
322
-
323
-        return $parent->filterWhere($key, $operator, $value);
324
-    }
325
-
326
-    /**
327
-     * {@inheritdoc}
328
-     */
329
-    public function where($key, $operator, $value = null)
330
-    {
331
-        $this->initializeProxy();
332
-
333
-        $parent = $this->toBaseCollection();
334
-
335
-        return $parent->where($key, $operator, $value);
336
-    }
337
-
338
-    /**
339
-     * {@inheritdoc}
340
-     */
341
-    public function whereInstanceOf($type)
342
-    {
343
-        $this->initializeProxy();
344
-
345
-        return parent::whereInstanceOf($type);
346
-    }
347
-
348
-    /**
349
-     * {@inheritdoc}
350
-     */
351
-    public function whereNotIn($key, $values, $strict = false)
352
-    {
353
-        $this->initializeProxy();
354
-
355
-        $parent = $this->toBaseCollection();
356
-
357
-        return $parent->whereNotIn($key, $values, $strict);
358
-    }
359
-
360
-    /**
361
-     * {@inheritdoc}
362
-     */
363
-    public function whereStrict($key, $value)
364
-    {
365
-        $this->initializeProxy();
366
-
367
-        $parent = $this->toBaseCollection();
368
-
369
-        return $parent->whereStrict($key, $value);
370
-    }
371
-
372
-    /**
373
-     * {@inheritdoc}
374
-     */
375
-    public function whereIn($key, $values, $strict = false)
376
-    {
377
-        $this->initializeProxy();
378
-
379
-        $parent = $this->toBaseCollection();
380
-
381
-        return $parent->whereIn($key, $values, $strict);
382
-    }
383
-
384
-    /**
385
-     * {@inheritdoc}
386
-     */
387
-    public function whereInStrict($key, $values)
388
-    {
389
-        $this->initializeProxy();
390
-
391
-        $parent = $this->toBaseCollection();
392
-
393
-        return $parent->whereInStrict($key, $values);
394
-    }
395
-
396
-    /**
397
-     * {@inheritdoc}
398
-     */
399
-    public function first(callable $callback = null, $default = null)
400
-    {
401
-        // TODO Consider partial loading
402
-        $this->initializeProxy();
403
-
404
-        return parent::first($callback, $default);
405
-    }
406
-
407
-    /**
408
-     * {@inheritdoc}
409
-     */
410
-    public function flatten($depth = INF)
411
-    {
412
-        $this->initializeProxy();
413
-
414
-        $parent = $this->toBaseCollection();
415
-
416
-        return $parent->flatten($depth);
417
-    }
418
-
419
-    /**
420
-     * {@inheritdoc}
421
-     */
422
-    public function flip()
423
-    {
424
-        $this->initializeProxy();
425
-
426
-        $parent = $this->toBaseCollection();
427
-
428
-        return $parent->flip();
429
-    }
430
-
431
-    /**
432
-     * {@inheritdoc}
433
-     */
434
-    public function forget($keys)
435
-    {
436
-        // TODO, we could consider these as
437
-        // 'pending deletion', the same way that
438
-        // we treat added items
439
-        $this->initializeProxy();
440
-
441
-        return parent::forget($keys);
442
-    }
443
-
444
-    /**
445
-     * {@inheritdoc}
446
-     */
447
-    public function get($key, $default = null)
448
-    {
449
-        // TODO : We could also consider partial loading
450
-        // here
451
-        $this->initializeProxy();
452
-
453
-        return parent::get($key, $default);
454
-    }
455
-
456
-    /**
457
-     * {@inheritdoc}
458
-     */
459
-    public function groupBy($groupBy, $preserveKeys = false)
460
-    {
461
-        $this->initializeProxy();
462
-
463
-        $parent = $this->toBaseCollection();
464
-
465
-        return $parent->groupBy($groupBy, $preserveKeys);
466
-    }
467
-
468
-    /**
469
-     * {@inheritdoc}
470
-     */
471
-    public function keyBy($keyBy)
472
-    {
473
-        $this->initializeProxy();
474
-
475
-        $parent = $this->toBaseCollection();
476
-
477
-        return $parent->keyBy($keyBy);
478
-    }
479
-
480
-    /**
481
-     * {@inheritdoc}
482
-     */
483
-    public function has($key)
484
-    {
485
-        // TODO : we could do automagic here by directly
486
-        // calling the database if the collection hasn't
487
-        // been initialized yet.
488
-        // Potential issue is that several calls to this
489
-        // could cause a lot queries vs a single get query.
490
-        $this->initializeProxy();
491
-
492
-        return parent::has($key);
493
-    }
494
-
495
-    /**
496
-     * {@inheritdoc}
497
-     */
498
-    public function implode($value, $glue = null)
499
-    {
500
-        $this->initializeProxy();
501
-
502
-        return parent::implode($value, $glue);
503
-    }
504
-
505
-    /**
506
-     * {@inheritdoc}
507
-     */
508
-    public function intersect($items)
509
-    {
510
-        $this->initializeProxy();
511
-
512
-        $parent = $this->toBaseCollection();
513
-
514
-        return $parent->intersect($items);
515
-    }
516
-
517
-    /**
518
-     * {@inheritdoc}
519
-     */
520
-    public function intersectByKeys($items)
521
-    {
522
-        $this->initializeProxy();
523
-
524
-        return parent::intersectByKeys($items);
525
-    }
526
-
527
-    /**
528
-     * {@inheritdoc}
529
-     */
530
-    public function isEmpty()
531
-    {
532
-        $this->initializeProxy();
533
-
534
-        return parent::isEmpty();
535
-    }
536
-
537
-    /**
538
-     * {@inheritdoc}
539
-     */
540
-    public function keys()
541
-    {
542
-        $this->initializeProxy();
543
-
544
-        $parent = $this->toBaseCollection();
545
-
546
-        return $parent->keys();
547
-    }
548
-
549
-    /**
550
-     * {@inheritdoc}
551
-     */
552
-    public function last(callable $callback = null, $default = null)
553
-    {
554
-        // TODO : we could do partial loading there as well
555
-        $this->initializeProxy();
556
-
557
-        return parent::last($callback, $default);
558
-    }
559
-
560
-    /**
561
-     * {@inheritdoc}
562
-     */
563
-    public function pluck($value, $key = null)
564
-    {
565
-        // TODO : automagic call to QB if not initialized
566
-        $this->initializeProxy();
567
-
568
-        $parent = $this->toBaseCollection();
569
-
570
-        return $parent->pluck($value, $key);
571
-    }
572
-
573
-    /**
574
-     * {@inheritdoc}
575
-     */
576
-    public function map(callable $callback)
577
-    {
578
-        $this->initializeProxy();
579
-
580
-        $parent = $this->toBaseCollection();
581
-
582
-        return $parent->map($callback);
583
-    }
584
-
585
-    /**
586
-     * {@inheritdoc}
587
-     */
588
-    public function mapInto($class)
589
-    {
590
-        $this->initializeProxy();
591
-
592
-        $parent = $this->toBaseCollection();
593
-
594
-        return $parent->map($class);
595
-    }
596
-
597
-    /**
598
-     * {@inheritdoc}
599
-     */
600
-    public function mapWithKeys(callable $callback)
601
-    {
602
-        $this->initializeProxy();
603
-
604
-        $parent = $this->toBaseCollection();
605
-
606
-        return $parent->mapWithKeys($callback);
607
-    }
608
-
609
-    /**
610
-     * {@inheritdoc}
611
-     */
612
-    public function mapToDictionary(callable $callback)
613
-    {
614
-        $this->initializeProxy();
615
-
616
-        $parent = $this->toBaseCollection();
617
-
618
-        return $parent->mapWithKeys($callback);
619
-    }
620
-
621
-    /**
622
-     * {@inheritdoc}
623
-     */
624
-    public function flatMap(callable $callback)
625
-    {
626
-        $this->initializeProxy();
627
-
628
-        $parent = $this->toBaseCollection();
629
-
630
-        return $parent->flatMap($callback);
631
-    }
632
-
633
-    /**
634
-     * {@inheritdoc}
635
-     */
636
-    public function max($callback = null)
637
-    {
638
-        $this->initializeProxy();
639
-
640
-        return parent::max($callback);
641
-    }
642
-
643
-    /**
644
-     * {@inheritdoc}
645
-     */
646
-    public function merge($items)
647
-    {
648
-        $this->initializeProxy();
649
-
650
-        $parent = $this->toBaseCollection();
651
-
652
-        return $parent->merge($items);
653
-    }
654
-
655
-    /**
656
-     * {@inheritdoc}
657
-     */
658
-    public function pad($size, $value)
659
-    {
660
-        $this->initializeProxy();
661
-
662
-        $parent = $this->toBaseCollection();
663
-
664
-        return $parent($size, $value);
665
-    }
666
-
667
-    /**
668
-     * {@inheritdoc}
669
-     */
670
-    public function combine($values)
671
-    {
672
-        $this->initializeProxy();
673
-
674
-        $parent = $this->toBaseCollection();
675
-
676
-        return $parent->combine($values);
677
-    }
678
-
679
-    /**
680
-     * {@inheritdoc}
681
-     */
682
-    public static function times($amount, callable $callback = null)
683
-    {
684
-        $this->initializeProxy();
685
-
686
-        $parent = $this->toBaseCollection();
687
-
688
-        return $parent->times($amount, $callback);
689
-    }
690
-
691
-    /**
692
-     * {@inheritdoc}
693
-     */
694
-    public function crossJoin(...$lists)
695
-    {
696
-        $this->initializeProxy();
697
-
698
-        $parent = $this->toBaseCollection();
699
-
700
-        return $parent->times(func_num_args());
701
-    }
702
-
703
-    /**
704
-     * {@inheritdoc}
705
-     */
706
-    public function diffAssoc($items)
707
-    {
708
-        $this->initializeProxy();
709
-
710
-        $parent = $this->toBaseCollection();
711
-
712
-        return $parent->diffAssoc($items);
713
-    }
714
-
715
-    /**
716
-     * {@inheritdoc}
717
-     */
718
-    public function intersectKey($items)
719
-    {
720
-        $this->initializeProxy();
721
-
722
-        $parent = $this->toBaseCollection();
723
-
724
-        return $parent->intersectKey($items);
725
-    }
726
-
727
-    /**
728
-     * {@inheritdoc}
729
-     */
730
-    public function union($items)
731
-    {
732
-        $this->initializeProxy();
733
-
734
-        $parent = $this->toBaseCollection();
735
-
736
-        return $parent->union($items);
737
-    }
738
-
739
-    /**
740
-     * {@inheritdoc}
741
-     */
742
-    public function min($callback = null)
743
-    {
744
-        // TODO : we could rely on the QB
745
-        // for this, if initialization has not
746
-        // take place yet
747
-        $this->initializeProxy();
748
-
749
-        return parent::min($callback);
750
-    }
751
-
752
-    /**
753
-     * {@inheritdoc}
754
-     */
755
-    public function nth($step, $offset = 0)
756
-    {
757
-        $this->initializeProxy();
758
-
759
-        $parent = $this->toBaseCollection();
760
-
761
-        return $parent->nth($step, $offset);
762
-    }
763
-
764
-    /**
765
-     * {@inheritdoc}
766
-     */
767
-    public function only($keys)
768
-    {
769
-        // TODO : we could rely on the QB if
770
-        // the collection hasn't been initialized yet
771
-        $this->initializeProxy();
772
-
773
-        $parent = $this->toBaseCollection();
774
-
775
-        return $parent->only($keys);
776
-    }
777
-
778
-    /**
779
-     * {@inheritdoc}
780
-     */
781
-    public function forPage($page, $perPage)
782
-    {
783
-        // TODO : check possibility of partial loading
784
-        // if not initialized
785
-        $this->initializeProxy();
786
-
787
-        $parent = $this->toBaseCollection();
788
-
789
-        return $parent->forPage($page, $perPage);
790
-    }
791
-
792
-    /**
793
-     * {@inheritdoc}
794
-     */
795
-    public function partition($callback, $operator = null, $value = null)
796
-    {
797
-        $this->initializeProxy();
798
-
799
-        $parent = $this->toBaseCollection();
800
-
801
-        switch (func_num_args()) {
802
-            case 1:
803
-                return $parent->partition($callback);
804
-            case 2:
805
-                return $parent->partition($callback, $operator);
806
-            case 3:
807
-                return $parent->partition($callback, $operator, $value);
808
-        }
809
-    }
810
-
811
-    /**
812
-     * {@inheritdoc}
813
-     */
814
-    public function pipe(callable $callback)
815
-    {
816
-        $this->initializeProxy();
817
-
818
-        return parent::pipe($callback);
819
-    }
820
-
821
-    /**
822
-     * {@inheritdoc}
823
-     */
824
-    public function pop()
825
-    {
826
-        $this->initializeProxy();
827
-
828
-        return parent::pop();
829
-    }
830
-
831
-    /**
832
-     * {@inheritdoc}
833
-     */
834
-    public function prepend($value, $key = null)
835
-    {
836
-        // TODO : partial adding of values.
837
-        // we could have a $prepended , and $pushed arrays
838
-        // which we would combine at full initialization
839
-
840
-        $this->initializeProxy();
841
-
842
-        return parent::prepend($value, $key);
843
-    }
844
-
845
-    /**
846
-     * {@inheritdoc}
847
-     */
848
-    public function push($value)
849
-    {
850
-        // TODO : partial adding of values.
851
-        // we could have a $prepended , and $pushed arrays
852
-        // which we would combine at full initialization
853
-
854
-        $this->initializeProxy();
855
-
856
-        return parent::push($value);
857
-    }
858
-
859
-    /**
860
-     * {@inheritdoc}
861
-     */
862
-    public function pull($key, $default = null)
863
-    {
864
-        // TODO : QB query if the collection
865
-        // hasn't been initialized yet
866
-
867
-        $this->initializeProxy();
868
-
869
-        return parent::pull($key, $default);
870
-    }
871
-
872
-    /**
873
-     * {@inheritdoc}
874
-     */
875
-    public function put($key, $value)
876
-    {
877
-        // TODO : Partial loading ?
878
-
879
-        $this->initializeProxy();
880
-
881
-        return parent::put($key, $value);
882
-    }
883
-
884
-    /**
885
-     * {@inheritdoc}
886
-     */
887
-    public function random($amount = null)
888
-    {
889
-        // TODO : we could optimize this by only
890
-        // fetching the keys from the database
891
-        // and performing partial loading
892
-
893
-        $this->initializeProxy();
894
-
895
-        return parent::random($amount);
896
-    }
897
-
898
-    /**
899
-     * {@inheritdoc}
900
-     */
901
-    public function reduce(callable $callback, $initial = null)
902
-    {
903
-        $this->initializeProxy();
904
-
905
-        return parent::reduce($callback, $initial);
906
-    }
907
-
908
-    /**
909
-     * {@inheritdoc}
910
-     */
911
-    public function reject($callback)
912
-    {
913
-        $this->initializeProxy();
914
-
915
-        $parent = $this->toBaseCollection();
916
-
917
-        return $parent->reject($callback);
918
-    }
919
-
920
-    /**
921
-     * {@inheritdoc}
922
-     */
923
-    public function reverse()
924
-    {
925
-        $this->initializeProxy();
926
-
927
-        $parent = $this->toBaseCollection();
928
-
929
-        return $parent->reverse();
930
-    }
931
-
932
-    /**
933
-     * {@inheritdoc}
934
-     */
935
-    public function search($value, $strict = false)
936
-    {
937
-        $this->initializeProxy();
938
-
939
-        return parent::search($value, $strict);
940
-    }
941
-
942
-    /**
943
-     * {@inheritdoc}
944
-     */
945
-    public function shift()
946
-    {
947
-        // Todo : Partial Removing
948
-        // we could have a pending removal array
949
-        $this->initializeProxy();
950
-
951
-        return parent::shift();
952
-    }
953
-
954
-    /**
955
-     * {@inheritdoc}
956
-     */
957
-    public function shuffle($seed = null)
958
-    {
959
-        $this->initializeProxy();
960
-
961
-        $parent = $this->toBaseCollection();
962
-
963
-        return $parent->shuffle($seed);
964
-    }
965
-
966
-    /**
967
-     * {@inheritdoc}
968
-     */
969
-    public function slice($offset, $length = null)
970
-    {
971
-        $this->initializeProxy();
972
-
973
-        $parent = $this->toBaseCollection();
974
-
975
-        return $parent->slice($offset, $length);
976
-    }
977
-
978
-    /**
979
-     * {@inheritdoc}
980
-     */
981
-    public function split($numberOfGroups)
982
-    {
983
-        $this->initializeProxy();
984
-
985
-        $parent = $this->toBaseCollection();
986
-
987
-        return $parent->split($numberOfGroups);
988
-    }
989
-
990
-    /**
991
-     * {@inheritdoc}
992
-     */
993
-    public function chunk($size)
994
-    {
995
-        // TODO : partial loading ?
996
-        $this->initializeProxy();
997
-
998
-        $parent = $this->toBaseCollection();
999
-
1000
-        return $parent->chunk($size);
1001
-    }
1002
-
1003
-    /**
1004
-     * {@inheritdoc}
1005
-     */
1006
-    public function sort(callable $callback = null)
1007
-    {
1008
-        $this->initializeProxy();
1009
-
1010
-        $parent = $this->toBaseCollection();
1011
-
1012
-        return $parent->sort($callback);
1013
-    }
1014
-
1015
-    /**
1016
-     * {@inheritdoc}
1017
-     */
1018
-    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1019
-    {
1020
-        $this->initializeProxy();
1021
-
1022
-        $parent = $this->toBaseCollection();
1023
-
1024
-        return $parent->sortBy($callback, $options, $descending);
1025
-    }
1026
-
1027
-    /**
1028
-     * {@inheritdoc}
1029
-     */
1030
-    public function sortKeys($options = SORT_REGULAR, $descending = false)
1031
-    {
1032
-        $this->initializeProxy();
1033
-
1034
-        $parent = $this->toBaseCollection();
1035
-
1036
-        return $parent->sortKeys($options, $descending);
1037
-    }
1038
-
1039
-    /**
1040
-     * {@inheritdoc}
1041
-     */
1042
-    public function splice($offset, $length = null, $replacement = [])
1043
-    {
1044
-        $this->initializeProxy();
1045
-
1046
-        $parent = $this->toBaseCollection();
1047
-
1048
-        switch (func_num_args()) {
1049
-            case 1:
1050
-                $parent->splice($offset);
1051
-            case 2:
1052
-                $parent->splice($offset, $length);
1053
-            case 3:
1054
-                $parent->splice($offset, $length, $replacement);
1055
-        }
1056
-    }
1057
-
1058
-    /**
1059
-     * {@inheritdoc}
1060
-     */
1061
-    public function sum($callback = null)
1062
-    {
1063
-        $this->initializeProxy();
1064
-
1065
-        return parent::sum($callback);
1066
-    }
1067
-
1068
-    /**
1069
-     * {@inheritdoc}
1070
-     */
1071
-    public function take($limit)
1072
-    {
1073
-        // TODO: partial loading
1074
-        $this->initializeProxy();
1075
-
1076
-        $parent = $this->toBaseCollection();
1077
-
1078
-        return $parent->take($limit);
1079
-    }
1080
-
1081
-    /**
1082
-     * {@inheritdoc}
1083
-     */
1084
-    public function tap(callable $callback)
1085
-    {
1086
-        $this->initializeProxy();
1087
-
1088
-        return parent::tap($this);
1089
-    }
1090
-
1091
-    /**
1092
-     * {@inheritdoc}
1093
-     */
1094
-    public function transform(callable $callback)
1095
-    {
1096
-        $this->initializeProxy();
1097
-
1098
-        return parent::transform($callback);
1099
-    }
1100
-
1101
-    /**
1102
-     * {@inheritdoc}
1103
-     */
1104
-    public function unique($key = null, $strict = false)
1105
-    {
1106
-        $this->initializeProxy();
1107
-
1108
-        $parent = $this->toBaseCollection();
1109
-
1110
-        return $parent->unique($key, $strict);
1111
-    }
1112
-
1113
-    /**
1114
-     * {@inheritdoc}
1115
-     */
1116
-    public function values()
1117
-    {
1118
-        $this->initializeProxy();
1119
-
1120
-        $parent = $this->toBaseCollection();
1121
-
1122
-        return $parent->values();
1123
-    }
1124
-
1125
-    /**
1126
-     * {@inheritdoc}
1127
-     */
1128
-    public function when($value, callable $callback, callable $default = null)
1129
-    {
1130
-        $this->initializeProxy();
1131
-
1132
-        return parent::when($value, $callback);
1133
-    }
1134
-
1135
-    /**
1136
-     * {@inheritdoc}
1137
-     */
1138
-    public function zip($items)
1139
-    {
1140
-        $this->initializeProxy();
1141
-
1142
-        $parent = $this->toBaseCollection();
1143
-
1144
-        return $parent->zip($items);
1145
-    }
1146
-
1147
-    /**
1148
-     * {@inheritdoc}
1149
-     */
1150
-    public function toArray()
1151
-    {
1152
-        // If this is called on all subsequent proxy,
1153
-        // this would eventually trigger all lazy loading,
1154
-        // which is NOT what we would expect...
1155
-        // TODO : must think of this.
1156
-        $this->initializeProxy();
1157
-
1158
-        return parent::toArray();
1159
-    }
1160
-
1161
-    /**
1162
-     * {@inheritdoc}
1163
-     */
1164
-    public function jsonSerialize()
1165
-    {
1166
-        // If this is called on all subsequent proxy,
1167
-        // this would eventually trigger all lazy loading,
1168
-        // which is NOT what we would expect...
1169
-        // TODO : must think of this.
1170
-        $this->initializeProxy();
1171
-
1172
-        return parent::jsonSerialize();
1173
-    }
1174
-
1175
-    /**
1176
-     * {@inheritdoc}
1177
-     */
1178
-    public function toJson($options = 0)
1179
-    {
1180
-        // If this is called on all subsequent proxy,
1181
-        // this would eventually trigger all lazy loading,
1182
-        // which is NOT what we would expect...
1183
-        // TODO : must think of this.
1184
-        $this->initializeProxy();
1185
-
1186
-        return parent::toJson($options);
1187
-    }
1188
-
1189
-    /**
1190
-     * {@inheritdoc}
1191
-     */
1192
-    public function getIterator()
1193
-    {
1194
-        $this->initializeProxy();
1195
-
1196
-        return parent::getIterator();
1197
-    }
1198
-
1199
-    /**
1200
-     * {@inheritdoc}
1201
-     */
1202
-    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1203
-    {
1204
-        $this->initializeProxy();
1205
-
1206
-        return parent::getCachingIterator($flags);
1207
-    }
1208
-
1209
-    /**
1210
-     * {@inheritdoc}
1211
-     */
1212
-    public function count()
1213
-    {
1214
-        return $this->relationshipLoaded
1215
-            ? parent::count()
1216
-            : $this->countUsingDatabaseQuery();
1217
-    }
1218
-
1219
-    /**
1220
-     * Do a count query and return the result.
1221
-     *
1222
-     * @return int
1223
-     */
1224
-    protected function countUsingDatabaseQuery() : int
1225
-    {
1226
-        return $this->getRelationshipInstance()->count();
1227
-    }
1228
-
1229
-    /**
1230
-     * Get a base Support collection instance from this collection.
1231
-     *
1232
-     * @return \Illuminate\Support\Collection
1233
-     */
1234
-    public function toBase()
1235
-    {
1236
-        $this->initializeProxy();
1237
-
1238
-        return parent::toBase();
1239
-    }
1240
-
1241
-    /**
1242
-     * {@inheritdoc}
1243
-     */
1244
-    public function offsetExists($key)
1245
-    {
1246
-        // TODO rely on QB if no collection
1247
-        // initialized
1248
-        $this->initializeProxy();
1249
-
1250
-        return parent::offsetExists($key);
1251
-    }
1252
-
1253
-    /**
1254
-     * {@inheritdoc}
1255
-     */
1256
-    public function offsetGet($key)
1257
-    {
1258
-        // TODO rely on partial init if no collection
1259
-        // initialized
1260
-        $this->initializeProxy();
1261
-
1262
-        return parent::offsetGet($key);
1263
-    }
1264
-
1265
-    /**
1266
-     * {@inheritdoc}
1267
-     */
1268
-    public function offsetSet($key, $value)
1269
-    {
1270
-        // TODO : think of the use of it into a ProxyCollection
1271
-        // context
1272
-        $this->initializeProxy();
1273
-
1274
-        return parent::offsetSet($key, $value);
1275
-    }
1276
-
1277
-    /**
1278
-     * {@inheritdoc}
1279
-     */
1280
-    public function offsetUnset($key)
1281
-    {
1282
-        // TODO : think of the use of it into a ProxyCollection
1283
-        // context
1284
-        $this->initializeProxy();
1285
-
1286
-        return parent::offsetUnset($key);
1287
-    }
1288
-
1289
-    /**
1290
-     * {@inheritdoc}
1291
-     */
1292
-    public function __get($key)
1293
-    {
1294
-        parent::__get($key);
1295
-    }
1296
-
1297
-    /**
1298
-     * {@inheritdoc}
1299
-     */
1300
-    public function __call($method, $parameters)
1301
-    {
1302
-        $this->initializeProxy();
1303
-
1304
-        return parent::__call($method, $parameters);
1305
-    }
14
+	/**
15
+	 * Indicate if the relationship has been lazy loaded.
16
+	 *
17
+	 * @var bool
18
+	 */
19
+	protected $relationshipLoaded = false;
20
+
21
+	/**
22
+	 * Added items.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $addedItems = [];
27
+
28
+	/**
29
+	 * Parent entity.
30
+	 *
31
+	 * @var \Analogue\ORM\Mappable|string
32
+	 */
33
+	protected $parentEntity;
34
+
35
+	/**
36
+	 * Relationship.
37
+	 *
38
+	 * @var string
39
+	 */
40
+	protected $relationshipMethod;
41
+
42
+	/**
43
+	 * Create a new collection.
44
+	 *
45
+	 * @param mixed  $entity
46
+	 * @param string $relation
47
+	 */
48
+	public function __construct($entity, $relation)
49
+	{
50
+		$this->parentEntity = $entity;
51
+		$this->relationshipMethod = $relation;
52
+		parent::__construct();
53
+	}
54
+
55
+	/**
56
+	 * Return Items that has been added without lazy loading
57
+	 * the underlying collection.
58
+	 *
59
+	 * @return array
60
+	 */
61
+	public function getAddedItems()
62
+	{
63
+		return $this->addedItems;
64
+	}
65
+
66
+	/**
67
+	 * Force initialization of the proxy.
68
+	 *
69
+	 * @return bool true if the proxy could be initialized
70
+	 */
71
+	public function initializeProxy() : bool
72
+	{
73
+		if ($this->isProxyInitialized()) {
74
+			return true;
75
+		}
76
+
77
+		$this->items = $this->getRelationshipInstance()
78
+			->getResults($this->relationshipMethod)->all() + $this->addedItems;
79
+
80
+		$this->relationshipLoaded = true;
81
+
82
+		return true;
83
+	}
84
+
85
+	/**
86
+	 * Return instance of the underlying relationship.
87
+	 *
88
+	 * @return Relationship
89
+	 */
90
+	protected function getRelationshipInstance() : Relationship
91
+	{
92
+		$relation = $this->relationshipMethod;
93
+		$entity = $this->parentEntity;
94
+		$entityMap = Manager::getMapper($entity)->getEntityMap();
95
+
96
+		return $entityMap->$relation($entity);
97
+	}
98
+
99
+	/**
100
+	 * {@inheritdoc}
101
+	 */
102
+	public function isProxyInitialized() : bool
103
+	{
104
+		return $this->relationshipLoaded;
105
+	}
106
+
107
+	/**
108
+	 * {@inheritdoc}
109
+	 */
110
+	protected function toBaseCollection() : Collection
111
+	{
112
+		return new Collection($this->items);
113
+	}
114
+
115
+	/**
116
+	 * {@inheritdoc}
117
+	 */
118
+	public function all()
119
+	{
120
+		$this->initializeProxy();
121
+
122
+		return parent::all();
123
+	}
124
+
125
+	/**
126
+	 * {@inheritdoc}
127
+	 */
128
+	public function avg($callback = null)
129
+	{
130
+		$this->initializeProxy();
131
+
132
+		return parent::avg($callback);
133
+	}
134
+
135
+	/**
136
+	 * {@inheritdoc}
137
+	 */
138
+	public function median($key = null)
139
+	{
140
+		$this->initializeProxy();
141
+
142
+		return parent::median($key);
143
+	}
144
+
145
+	/**
146
+	 * {@inheritdoc}
147
+	 */
148
+	public function mode($key = null)
149
+	{
150
+		$this->initializeProxy();
151
+
152
+		return parent::mode($key);
153
+	}
154
+
155
+	/**
156
+	 * {@inheritdoc}
157
+	 */
158
+	public function collapse()
159
+	{
160
+		$this->initializeProxy();
161
+
162
+		$parent = $this->toBaseCollection();
163
+
164
+		return $parent->collapse();
165
+	}
166
+
167
+	/**
168
+	 * {@inheritdoc}
169
+	 */
170
+	public function contains($key, $operator = null, $value = null)
171
+	{
172
+		$this->initializeProxy();
173
+
174
+		$parent = $this->toBaseCollection();
175
+
176
+		switch (func_num_args()) {
177
+			case 1:
178
+				return $parent->contains($key);
179
+			case 2:
180
+				return $parent->contains($key, $operator);
181
+			case 3:
182
+				return $parent->contains($key, $operator, $value);
183
+		}
184
+	}
185
+
186
+	/**
187
+	 * {@inheritdoc}
188
+	 */
189
+	public function containsStrict($key, $value = null)
190
+	{
191
+		$this->initializeProxy();
192
+
193
+		switch (func_num_args()) {
194
+			case 1:
195
+				return parent::containsStrict($key);
196
+			case 2:
197
+				return parent::containsStrict($key, $value);
198
+		}
199
+	}
200
+
201
+	/**
202
+	 * {@inheritdoc}
203
+	 */
204
+	public function diff($items)
205
+	{
206
+		$this->initializeProxy();
207
+
208
+		$parent = $this->toBaseCollection();
209
+
210
+		return $parent->diff($items);
211
+	}
212
+
213
+	/**
214
+	 * {@inheritdoc}
215
+	 */
216
+	public function diffUsing($items, callable $callback)
217
+	{
218
+		$this->initializeProxy();
219
+
220
+		$parent = $this->toBaseCollection();
221
+
222
+		return $parent->diffUsing($items, $callback);
223
+	}
224
+
225
+	/**
226
+	 * {@inheritdoc}
227
+	 */
228
+	public function diffAssocUsing($items, callable $callback)
229
+	{
230
+		$this->initializeProxy();
231
+
232
+		$parent = $this->toBaseCollection();
233
+
234
+		return $parent->diffAssocUsing($items, $callback);
235
+	}
236
+
237
+	/**
238
+	 * {@inheritdoc}
239
+	 */
240
+	public function diffKeys($items)
241
+	{
242
+		$this->initializeProxy();
243
+
244
+		$parent = $this->toBaseCollection();
245
+
246
+		return $parent->diffKeys($items);
247
+	}
248
+
249
+	/**
250
+	 * {@inheritdoc}
251
+	 */
252
+	public function diffKeysUsing($items, callable $callback)
253
+	{
254
+		$this->initializeProxy();
255
+
256
+		$parent = $this->toBaseCollection();
257
+
258
+		return $parent->diffKeysUsing($items);
259
+	}
260
+
261
+	/**
262
+	 * {@inheritdoc}
263
+	 */
264
+	public function each(callable $callback)
265
+	{
266
+		$this->initializeProxy();
267
+
268
+		return parent::each($callback);
269
+	}
270
+
271
+	/**
272
+	 * {@inheritdoc}
273
+	 */
274
+	public function every($key, $operator = null, $value = null)
275
+	{
276
+		$this->initializeProxy();
277
+
278
+		$parent = $this->toBaseCollection();
279
+
280
+		switch (func_num_args()) {
281
+			case 1:
282
+				return $parent->every($key);
283
+			case 2:
284
+				return $parent->every($key, $operator);
285
+			case 3:
286
+				return $parent->every($key, $operator, $value);
287
+		}
288
+	}
289
+
290
+	/**
291
+	 * {@inheritdoc}
292
+	 */
293
+	public function except($keys)
294
+	{
295
+		$this->initializeProxy();
296
+
297
+		$parent = $this->toBaseCollection();
298
+
299
+		return $parent->except($keys);
300
+	}
301
+
302
+	/**
303
+	 * {@inheritdoc}
304
+	 */
305
+	public function filter(callable $callback = null)
306
+	{
307
+		$this->initializeProxy();
308
+
309
+		$parent = $this->toBaseCollection();
310
+
311
+		return $parent->filter($callback);
312
+	}
313
+
314
+	/**
315
+	 * {@inheritdoc}
316
+	 */
317
+	public function firstWhere($key, $operator, $value = null)
318
+	{
319
+		$this->initializeProxy();
320
+
321
+		$parent = $this->toBaseCollection();
322
+
323
+		return $parent->filterWhere($key, $operator, $value);
324
+	}
325
+
326
+	/**
327
+	 * {@inheritdoc}
328
+	 */
329
+	public function where($key, $operator, $value = null)
330
+	{
331
+		$this->initializeProxy();
332
+
333
+		$parent = $this->toBaseCollection();
334
+
335
+		return $parent->where($key, $operator, $value);
336
+	}
337
+
338
+	/**
339
+	 * {@inheritdoc}
340
+	 */
341
+	public function whereInstanceOf($type)
342
+	{
343
+		$this->initializeProxy();
344
+
345
+		return parent::whereInstanceOf($type);
346
+	}
347
+
348
+	/**
349
+	 * {@inheritdoc}
350
+	 */
351
+	public function whereNotIn($key, $values, $strict = false)
352
+	{
353
+		$this->initializeProxy();
354
+
355
+		$parent = $this->toBaseCollection();
356
+
357
+		return $parent->whereNotIn($key, $values, $strict);
358
+	}
359
+
360
+	/**
361
+	 * {@inheritdoc}
362
+	 */
363
+	public function whereStrict($key, $value)
364
+	{
365
+		$this->initializeProxy();
366
+
367
+		$parent = $this->toBaseCollection();
368
+
369
+		return $parent->whereStrict($key, $value);
370
+	}
371
+
372
+	/**
373
+	 * {@inheritdoc}
374
+	 */
375
+	public function whereIn($key, $values, $strict = false)
376
+	{
377
+		$this->initializeProxy();
378
+
379
+		$parent = $this->toBaseCollection();
380
+
381
+		return $parent->whereIn($key, $values, $strict);
382
+	}
383
+
384
+	/**
385
+	 * {@inheritdoc}
386
+	 */
387
+	public function whereInStrict($key, $values)
388
+	{
389
+		$this->initializeProxy();
390
+
391
+		$parent = $this->toBaseCollection();
392
+
393
+		return $parent->whereInStrict($key, $values);
394
+	}
395
+
396
+	/**
397
+	 * {@inheritdoc}
398
+	 */
399
+	public function first(callable $callback = null, $default = null)
400
+	{
401
+		// TODO Consider partial loading
402
+		$this->initializeProxy();
403
+
404
+		return parent::first($callback, $default);
405
+	}
406
+
407
+	/**
408
+	 * {@inheritdoc}
409
+	 */
410
+	public function flatten($depth = INF)
411
+	{
412
+		$this->initializeProxy();
413
+
414
+		$parent = $this->toBaseCollection();
415
+
416
+		return $parent->flatten($depth);
417
+	}
418
+
419
+	/**
420
+	 * {@inheritdoc}
421
+	 */
422
+	public function flip()
423
+	{
424
+		$this->initializeProxy();
425
+
426
+		$parent = $this->toBaseCollection();
427
+
428
+		return $parent->flip();
429
+	}
430
+
431
+	/**
432
+	 * {@inheritdoc}
433
+	 */
434
+	public function forget($keys)
435
+	{
436
+		// TODO, we could consider these as
437
+		// 'pending deletion', the same way that
438
+		// we treat added items
439
+		$this->initializeProxy();
440
+
441
+		return parent::forget($keys);
442
+	}
443
+
444
+	/**
445
+	 * {@inheritdoc}
446
+	 */
447
+	public function get($key, $default = null)
448
+	{
449
+		// TODO : We could also consider partial loading
450
+		// here
451
+		$this->initializeProxy();
452
+
453
+		return parent::get($key, $default);
454
+	}
455
+
456
+	/**
457
+	 * {@inheritdoc}
458
+	 */
459
+	public function groupBy($groupBy, $preserveKeys = false)
460
+	{
461
+		$this->initializeProxy();
462
+
463
+		$parent = $this->toBaseCollection();
464
+
465
+		return $parent->groupBy($groupBy, $preserveKeys);
466
+	}
467
+
468
+	/**
469
+	 * {@inheritdoc}
470
+	 */
471
+	public function keyBy($keyBy)
472
+	{
473
+		$this->initializeProxy();
474
+
475
+		$parent = $this->toBaseCollection();
476
+
477
+		return $parent->keyBy($keyBy);
478
+	}
479
+
480
+	/**
481
+	 * {@inheritdoc}
482
+	 */
483
+	public function has($key)
484
+	{
485
+		// TODO : we could do automagic here by directly
486
+		// calling the database if the collection hasn't
487
+		// been initialized yet.
488
+		// Potential issue is that several calls to this
489
+		// could cause a lot queries vs a single get query.
490
+		$this->initializeProxy();
491
+
492
+		return parent::has($key);
493
+	}
494
+
495
+	/**
496
+	 * {@inheritdoc}
497
+	 */
498
+	public function implode($value, $glue = null)
499
+	{
500
+		$this->initializeProxy();
501
+
502
+		return parent::implode($value, $glue);
503
+	}
504
+
505
+	/**
506
+	 * {@inheritdoc}
507
+	 */
508
+	public function intersect($items)
509
+	{
510
+		$this->initializeProxy();
511
+
512
+		$parent = $this->toBaseCollection();
513
+
514
+		return $parent->intersect($items);
515
+	}
516
+
517
+	/**
518
+	 * {@inheritdoc}
519
+	 */
520
+	public function intersectByKeys($items)
521
+	{
522
+		$this->initializeProxy();
523
+
524
+		return parent::intersectByKeys($items);
525
+	}
526
+
527
+	/**
528
+	 * {@inheritdoc}
529
+	 */
530
+	public function isEmpty()
531
+	{
532
+		$this->initializeProxy();
533
+
534
+		return parent::isEmpty();
535
+	}
536
+
537
+	/**
538
+	 * {@inheritdoc}
539
+	 */
540
+	public function keys()
541
+	{
542
+		$this->initializeProxy();
543
+
544
+		$parent = $this->toBaseCollection();
545
+
546
+		return $parent->keys();
547
+	}
548
+
549
+	/**
550
+	 * {@inheritdoc}
551
+	 */
552
+	public function last(callable $callback = null, $default = null)
553
+	{
554
+		// TODO : we could do partial loading there as well
555
+		$this->initializeProxy();
556
+
557
+		return parent::last($callback, $default);
558
+	}
559
+
560
+	/**
561
+	 * {@inheritdoc}
562
+	 */
563
+	public function pluck($value, $key = null)
564
+	{
565
+		// TODO : automagic call to QB if not initialized
566
+		$this->initializeProxy();
567
+
568
+		$parent = $this->toBaseCollection();
569
+
570
+		return $parent->pluck($value, $key);
571
+	}
572
+
573
+	/**
574
+	 * {@inheritdoc}
575
+	 */
576
+	public function map(callable $callback)
577
+	{
578
+		$this->initializeProxy();
579
+
580
+		$parent = $this->toBaseCollection();
581
+
582
+		return $parent->map($callback);
583
+	}
584
+
585
+	/**
586
+	 * {@inheritdoc}
587
+	 */
588
+	public function mapInto($class)
589
+	{
590
+		$this->initializeProxy();
591
+
592
+		$parent = $this->toBaseCollection();
593
+
594
+		return $parent->map($class);
595
+	}
596
+
597
+	/**
598
+	 * {@inheritdoc}
599
+	 */
600
+	public function mapWithKeys(callable $callback)
601
+	{
602
+		$this->initializeProxy();
603
+
604
+		$parent = $this->toBaseCollection();
605
+
606
+		return $parent->mapWithKeys($callback);
607
+	}
608
+
609
+	/**
610
+	 * {@inheritdoc}
611
+	 */
612
+	public function mapToDictionary(callable $callback)
613
+	{
614
+		$this->initializeProxy();
615
+
616
+		$parent = $this->toBaseCollection();
617
+
618
+		return $parent->mapWithKeys($callback);
619
+	}
620
+
621
+	/**
622
+	 * {@inheritdoc}
623
+	 */
624
+	public function flatMap(callable $callback)
625
+	{
626
+		$this->initializeProxy();
627
+
628
+		$parent = $this->toBaseCollection();
629
+
630
+		return $parent->flatMap($callback);
631
+	}
632
+
633
+	/**
634
+	 * {@inheritdoc}
635
+	 */
636
+	public function max($callback = null)
637
+	{
638
+		$this->initializeProxy();
639
+
640
+		return parent::max($callback);
641
+	}
642
+
643
+	/**
644
+	 * {@inheritdoc}
645
+	 */
646
+	public function merge($items)
647
+	{
648
+		$this->initializeProxy();
649
+
650
+		$parent = $this->toBaseCollection();
651
+
652
+		return $parent->merge($items);
653
+	}
654
+
655
+	/**
656
+	 * {@inheritdoc}
657
+	 */
658
+	public function pad($size, $value)
659
+	{
660
+		$this->initializeProxy();
661
+
662
+		$parent = $this->toBaseCollection();
663
+
664
+		return $parent($size, $value);
665
+	}
666
+
667
+	/**
668
+	 * {@inheritdoc}
669
+	 */
670
+	public function combine($values)
671
+	{
672
+		$this->initializeProxy();
673
+
674
+		$parent = $this->toBaseCollection();
675
+
676
+		return $parent->combine($values);
677
+	}
678
+
679
+	/**
680
+	 * {@inheritdoc}
681
+	 */
682
+	public static function times($amount, callable $callback = null)
683
+	{
684
+		$this->initializeProxy();
685
+
686
+		$parent = $this->toBaseCollection();
687
+
688
+		return $parent->times($amount, $callback);
689
+	}
690
+
691
+	/**
692
+	 * {@inheritdoc}
693
+	 */
694
+	public function crossJoin(...$lists)
695
+	{
696
+		$this->initializeProxy();
697
+
698
+		$parent = $this->toBaseCollection();
699
+
700
+		return $parent->times(func_num_args());
701
+	}
702
+
703
+	/**
704
+	 * {@inheritdoc}
705
+	 */
706
+	public function diffAssoc($items)
707
+	{
708
+		$this->initializeProxy();
709
+
710
+		$parent = $this->toBaseCollection();
711
+
712
+		return $parent->diffAssoc($items);
713
+	}
714
+
715
+	/**
716
+	 * {@inheritdoc}
717
+	 */
718
+	public function intersectKey($items)
719
+	{
720
+		$this->initializeProxy();
721
+
722
+		$parent = $this->toBaseCollection();
723
+
724
+		return $parent->intersectKey($items);
725
+	}
726
+
727
+	/**
728
+	 * {@inheritdoc}
729
+	 */
730
+	public function union($items)
731
+	{
732
+		$this->initializeProxy();
733
+
734
+		$parent = $this->toBaseCollection();
735
+
736
+		return $parent->union($items);
737
+	}
738
+
739
+	/**
740
+	 * {@inheritdoc}
741
+	 */
742
+	public function min($callback = null)
743
+	{
744
+		// TODO : we could rely on the QB
745
+		// for this, if initialization has not
746
+		// take place yet
747
+		$this->initializeProxy();
748
+
749
+		return parent::min($callback);
750
+	}
751
+
752
+	/**
753
+	 * {@inheritdoc}
754
+	 */
755
+	public function nth($step, $offset = 0)
756
+	{
757
+		$this->initializeProxy();
758
+
759
+		$parent = $this->toBaseCollection();
760
+
761
+		return $parent->nth($step, $offset);
762
+	}
763
+
764
+	/**
765
+	 * {@inheritdoc}
766
+	 */
767
+	public function only($keys)
768
+	{
769
+		// TODO : we could rely on the QB if
770
+		// the collection hasn't been initialized yet
771
+		$this->initializeProxy();
772
+
773
+		$parent = $this->toBaseCollection();
774
+
775
+		return $parent->only($keys);
776
+	}
777
+
778
+	/**
779
+	 * {@inheritdoc}
780
+	 */
781
+	public function forPage($page, $perPage)
782
+	{
783
+		// TODO : check possibility of partial loading
784
+		// if not initialized
785
+		$this->initializeProxy();
786
+
787
+		$parent = $this->toBaseCollection();
788
+
789
+		return $parent->forPage($page, $perPage);
790
+	}
791
+
792
+	/**
793
+	 * {@inheritdoc}
794
+	 */
795
+	public function partition($callback, $operator = null, $value = null)
796
+	{
797
+		$this->initializeProxy();
798
+
799
+		$parent = $this->toBaseCollection();
800
+
801
+		switch (func_num_args()) {
802
+			case 1:
803
+				return $parent->partition($callback);
804
+			case 2:
805
+				return $parent->partition($callback, $operator);
806
+			case 3:
807
+				return $parent->partition($callback, $operator, $value);
808
+		}
809
+	}
810
+
811
+	/**
812
+	 * {@inheritdoc}
813
+	 */
814
+	public function pipe(callable $callback)
815
+	{
816
+		$this->initializeProxy();
817
+
818
+		return parent::pipe($callback);
819
+	}
820
+
821
+	/**
822
+	 * {@inheritdoc}
823
+	 */
824
+	public function pop()
825
+	{
826
+		$this->initializeProxy();
827
+
828
+		return parent::pop();
829
+	}
830
+
831
+	/**
832
+	 * {@inheritdoc}
833
+	 */
834
+	public function prepend($value, $key = null)
835
+	{
836
+		// TODO : partial adding of values.
837
+		// we could have a $prepended , and $pushed arrays
838
+		// which we would combine at full initialization
839
+
840
+		$this->initializeProxy();
841
+
842
+		return parent::prepend($value, $key);
843
+	}
844
+
845
+	/**
846
+	 * {@inheritdoc}
847
+	 */
848
+	public function push($value)
849
+	{
850
+		// TODO : partial adding of values.
851
+		// we could have a $prepended , and $pushed arrays
852
+		// which we would combine at full initialization
853
+
854
+		$this->initializeProxy();
855
+
856
+		return parent::push($value);
857
+	}
858
+
859
+	/**
860
+	 * {@inheritdoc}
861
+	 */
862
+	public function pull($key, $default = null)
863
+	{
864
+		// TODO : QB query if the collection
865
+		// hasn't been initialized yet
866
+
867
+		$this->initializeProxy();
868
+
869
+		return parent::pull($key, $default);
870
+	}
871
+
872
+	/**
873
+	 * {@inheritdoc}
874
+	 */
875
+	public function put($key, $value)
876
+	{
877
+		// TODO : Partial loading ?
878
+
879
+		$this->initializeProxy();
880
+
881
+		return parent::put($key, $value);
882
+	}
883
+
884
+	/**
885
+	 * {@inheritdoc}
886
+	 */
887
+	public function random($amount = null)
888
+	{
889
+		// TODO : we could optimize this by only
890
+		// fetching the keys from the database
891
+		// and performing partial loading
892
+
893
+		$this->initializeProxy();
894
+
895
+		return parent::random($amount);
896
+	}
897
+
898
+	/**
899
+	 * {@inheritdoc}
900
+	 */
901
+	public function reduce(callable $callback, $initial = null)
902
+	{
903
+		$this->initializeProxy();
904
+
905
+		return parent::reduce($callback, $initial);
906
+	}
907
+
908
+	/**
909
+	 * {@inheritdoc}
910
+	 */
911
+	public function reject($callback)
912
+	{
913
+		$this->initializeProxy();
914
+
915
+		$parent = $this->toBaseCollection();
916
+
917
+		return $parent->reject($callback);
918
+	}
919
+
920
+	/**
921
+	 * {@inheritdoc}
922
+	 */
923
+	public function reverse()
924
+	{
925
+		$this->initializeProxy();
926
+
927
+		$parent = $this->toBaseCollection();
928
+
929
+		return $parent->reverse();
930
+	}
931
+
932
+	/**
933
+	 * {@inheritdoc}
934
+	 */
935
+	public function search($value, $strict = false)
936
+	{
937
+		$this->initializeProxy();
938
+
939
+		return parent::search($value, $strict);
940
+	}
941
+
942
+	/**
943
+	 * {@inheritdoc}
944
+	 */
945
+	public function shift()
946
+	{
947
+		// Todo : Partial Removing
948
+		// we could have a pending removal array
949
+		$this->initializeProxy();
950
+
951
+		return parent::shift();
952
+	}
953
+
954
+	/**
955
+	 * {@inheritdoc}
956
+	 */
957
+	public function shuffle($seed = null)
958
+	{
959
+		$this->initializeProxy();
960
+
961
+		$parent = $this->toBaseCollection();
962
+
963
+		return $parent->shuffle($seed);
964
+	}
965
+
966
+	/**
967
+	 * {@inheritdoc}
968
+	 */
969
+	public function slice($offset, $length = null)
970
+	{
971
+		$this->initializeProxy();
972
+
973
+		$parent = $this->toBaseCollection();
974
+
975
+		return $parent->slice($offset, $length);
976
+	}
977
+
978
+	/**
979
+	 * {@inheritdoc}
980
+	 */
981
+	public function split($numberOfGroups)
982
+	{
983
+		$this->initializeProxy();
984
+
985
+		$parent = $this->toBaseCollection();
986
+
987
+		return $parent->split($numberOfGroups);
988
+	}
989
+
990
+	/**
991
+	 * {@inheritdoc}
992
+	 */
993
+	public function chunk($size)
994
+	{
995
+		// TODO : partial loading ?
996
+		$this->initializeProxy();
997
+
998
+		$parent = $this->toBaseCollection();
999
+
1000
+		return $parent->chunk($size);
1001
+	}
1002
+
1003
+	/**
1004
+	 * {@inheritdoc}
1005
+	 */
1006
+	public function sort(callable $callback = null)
1007
+	{
1008
+		$this->initializeProxy();
1009
+
1010
+		$parent = $this->toBaseCollection();
1011
+
1012
+		return $parent->sort($callback);
1013
+	}
1014
+
1015
+	/**
1016
+	 * {@inheritdoc}
1017
+	 */
1018
+	public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1019
+	{
1020
+		$this->initializeProxy();
1021
+
1022
+		$parent = $this->toBaseCollection();
1023
+
1024
+		return $parent->sortBy($callback, $options, $descending);
1025
+	}
1026
+
1027
+	/**
1028
+	 * {@inheritdoc}
1029
+	 */
1030
+	public function sortKeys($options = SORT_REGULAR, $descending = false)
1031
+	{
1032
+		$this->initializeProxy();
1033
+
1034
+		$parent = $this->toBaseCollection();
1035
+
1036
+		return $parent->sortKeys($options, $descending);
1037
+	}
1038
+
1039
+	/**
1040
+	 * {@inheritdoc}
1041
+	 */
1042
+	public function splice($offset, $length = null, $replacement = [])
1043
+	{
1044
+		$this->initializeProxy();
1045
+
1046
+		$parent = $this->toBaseCollection();
1047
+
1048
+		switch (func_num_args()) {
1049
+			case 1:
1050
+				$parent->splice($offset);
1051
+			case 2:
1052
+				$parent->splice($offset, $length);
1053
+			case 3:
1054
+				$parent->splice($offset, $length, $replacement);
1055
+		}
1056
+	}
1057
+
1058
+	/**
1059
+	 * {@inheritdoc}
1060
+	 */
1061
+	public function sum($callback = null)
1062
+	{
1063
+		$this->initializeProxy();
1064
+
1065
+		return parent::sum($callback);
1066
+	}
1067
+
1068
+	/**
1069
+	 * {@inheritdoc}
1070
+	 */
1071
+	public function take($limit)
1072
+	{
1073
+		// TODO: partial loading
1074
+		$this->initializeProxy();
1075
+
1076
+		$parent = $this->toBaseCollection();
1077
+
1078
+		return $parent->take($limit);
1079
+	}
1080
+
1081
+	/**
1082
+	 * {@inheritdoc}
1083
+	 */
1084
+	public function tap(callable $callback)
1085
+	{
1086
+		$this->initializeProxy();
1087
+
1088
+		return parent::tap($this);
1089
+	}
1090
+
1091
+	/**
1092
+	 * {@inheritdoc}
1093
+	 */
1094
+	public function transform(callable $callback)
1095
+	{
1096
+		$this->initializeProxy();
1097
+
1098
+		return parent::transform($callback);
1099
+	}
1100
+
1101
+	/**
1102
+	 * {@inheritdoc}
1103
+	 */
1104
+	public function unique($key = null, $strict = false)
1105
+	{
1106
+		$this->initializeProxy();
1107
+
1108
+		$parent = $this->toBaseCollection();
1109
+
1110
+		return $parent->unique($key, $strict);
1111
+	}
1112
+
1113
+	/**
1114
+	 * {@inheritdoc}
1115
+	 */
1116
+	public function values()
1117
+	{
1118
+		$this->initializeProxy();
1119
+
1120
+		$parent = $this->toBaseCollection();
1121
+
1122
+		return $parent->values();
1123
+	}
1124
+
1125
+	/**
1126
+	 * {@inheritdoc}
1127
+	 */
1128
+	public function when($value, callable $callback, callable $default = null)
1129
+	{
1130
+		$this->initializeProxy();
1131
+
1132
+		return parent::when($value, $callback);
1133
+	}
1134
+
1135
+	/**
1136
+	 * {@inheritdoc}
1137
+	 */
1138
+	public function zip($items)
1139
+	{
1140
+		$this->initializeProxy();
1141
+
1142
+		$parent = $this->toBaseCollection();
1143
+
1144
+		return $parent->zip($items);
1145
+	}
1146
+
1147
+	/**
1148
+	 * {@inheritdoc}
1149
+	 */
1150
+	public function toArray()
1151
+	{
1152
+		// If this is called on all subsequent proxy,
1153
+		// this would eventually trigger all lazy loading,
1154
+		// which is NOT what we would expect...
1155
+		// TODO : must think of this.
1156
+		$this->initializeProxy();
1157
+
1158
+		return parent::toArray();
1159
+	}
1160
+
1161
+	/**
1162
+	 * {@inheritdoc}
1163
+	 */
1164
+	public function jsonSerialize()
1165
+	{
1166
+		// If this is called on all subsequent proxy,
1167
+		// this would eventually trigger all lazy loading,
1168
+		// which is NOT what we would expect...
1169
+		// TODO : must think of this.
1170
+		$this->initializeProxy();
1171
+
1172
+		return parent::jsonSerialize();
1173
+	}
1174
+
1175
+	/**
1176
+	 * {@inheritdoc}
1177
+	 */
1178
+	public function toJson($options = 0)
1179
+	{
1180
+		// If this is called on all subsequent proxy,
1181
+		// this would eventually trigger all lazy loading,
1182
+		// which is NOT what we would expect...
1183
+		// TODO : must think of this.
1184
+		$this->initializeProxy();
1185
+
1186
+		return parent::toJson($options);
1187
+	}
1188
+
1189
+	/**
1190
+	 * {@inheritdoc}
1191
+	 */
1192
+	public function getIterator()
1193
+	{
1194
+		$this->initializeProxy();
1195
+
1196
+		return parent::getIterator();
1197
+	}
1198
+
1199
+	/**
1200
+	 * {@inheritdoc}
1201
+	 */
1202
+	public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1203
+	{
1204
+		$this->initializeProxy();
1205
+
1206
+		return parent::getCachingIterator($flags);
1207
+	}
1208
+
1209
+	/**
1210
+	 * {@inheritdoc}
1211
+	 */
1212
+	public function count()
1213
+	{
1214
+		return $this->relationshipLoaded
1215
+			? parent::count()
1216
+			: $this->countUsingDatabaseQuery();
1217
+	}
1218
+
1219
+	/**
1220
+	 * Do a count query and return the result.
1221
+	 *
1222
+	 * @return int
1223
+	 */
1224
+	protected function countUsingDatabaseQuery() : int
1225
+	{
1226
+		return $this->getRelationshipInstance()->count();
1227
+	}
1228
+
1229
+	/**
1230
+	 * Get a base Support collection instance from this collection.
1231
+	 *
1232
+	 * @return \Illuminate\Support\Collection
1233
+	 */
1234
+	public function toBase()
1235
+	{
1236
+		$this->initializeProxy();
1237
+
1238
+		return parent::toBase();
1239
+	}
1240
+
1241
+	/**
1242
+	 * {@inheritdoc}
1243
+	 */
1244
+	public function offsetExists($key)
1245
+	{
1246
+		// TODO rely on QB if no collection
1247
+		// initialized
1248
+		$this->initializeProxy();
1249
+
1250
+		return parent::offsetExists($key);
1251
+	}
1252
+
1253
+	/**
1254
+	 * {@inheritdoc}
1255
+	 */
1256
+	public function offsetGet($key)
1257
+	{
1258
+		// TODO rely on partial init if no collection
1259
+		// initialized
1260
+		$this->initializeProxy();
1261
+
1262
+		return parent::offsetGet($key);
1263
+	}
1264
+
1265
+	/**
1266
+	 * {@inheritdoc}
1267
+	 */
1268
+	public function offsetSet($key, $value)
1269
+	{
1270
+		// TODO : think of the use of it into a ProxyCollection
1271
+		// context
1272
+		$this->initializeProxy();
1273
+
1274
+		return parent::offsetSet($key, $value);
1275
+	}
1276
+
1277
+	/**
1278
+	 * {@inheritdoc}
1279
+	 */
1280
+	public function offsetUnset($key)
1281
+	{
1282
+		// TODO : think of the use of it into a ProxyCollection
1283
+		// context
1284
+		$this->initializeProxy();
1285
+
1286
+		return parent::offsetUnset($key);
1287
+	}
1288
+
1289
+	/**
1290
+	 * {@inheritdoc}
1291
+	 */
1292
+	public function __get($key)
1293
+	{
1294
+		parent::__get($key);
1295
+	}
1296
+
1297
+	/**
1298
+	 * {@inheritdoc}
1299
+	 */
1300
+	public function __call($method, $parameters)
1301
+	{
1302
+		$this->initializeProxy();
1303
+
1304
+		return parent::__call($method, $parameters);
1305
+	}
1306 1306
 }
Please login to merge, or discard this patch.
src/System/Cache/AttributeCache.php 2 patches
Indentation   +360 added lines, -360 removed lines patch added patch discarded remove patch
@@ -17,364 +17,364 @@
 block discarded – undo
17 17
  */
18 18
 class AttributeCache
19 19
 {
20
-    /**
21
-     * Entity's raw attributes/relationships.
22
-     *
23
-     * @var array
24
-     */
25
-    protected $cache = [];
26
-
27
-    /**
28
-     * Primary key => Entity instance correspondancy.
29
-     *
30
-     * @var array
31
-     */
32
-    protected $instances = [];
33
-
34
-    /**
35
-     * Entity Map for the current Entity Type.
36
-     *
37
-     * @var \Analogue\ORM\EntityMap
38
-     */
39
-    protected $entityMap;
40
-
41
-    /**
42
-     * Wrapper factory.
43
-     *
44
-     * @var \Analogue\ORM\System\Wrappers\Factory
45
-     */
46
-    protected $factory;
47
-
48
-    /**
49
-     * Associative array containing list of pivot attributes per relationship
50
-     * so we don't have to call relationship method on refresh.
51
-     *
52
-     * @var array
53
-     */
54
-    protected $pivotAttributes = [];
55
-
56
-    /**
57
-     * EntityCache constructor.
58
-     *
59
-     * @param EntityMap $entityMap
60
-     */
61
-    public function __construct(EntityMap $entityMap)
62
-    {
63
-        $this->entityMap = $entityMap;
64
-
65
-        $this->factory = new Factory();
66
-    }
67
-
68
-    /**
69
-     * Add an array of key=>attributes representing
70
-     * the initial state of loaded entities.
71
-     *
72
-     * @param array $results
73
-     */
74
-    public function add(array $results)
75
-    {
76
-        $cachedResults = [];
77
-
78
-        $keyColumn = $this->entityMap->getKeyName();
79
-
80
-        foreach ($results as $result) {
81
-            $id = $result[$keyColumn];
82
-
83
-            // Forget the ID field from the cache attributes
84
-            // to prevent any side effect.
85
-            // TODO : remove primary key check from dirty attributes parsing
86
-            //unset($result[$keyColumn]);
87
-            $cachedResults[$id] = $this->rawResult($result);
88
-        }
89
-
90
-        if (empty($this->cache)) {
91
-            $this->cache = $cachedResults;
92
-        } else {
93
-            $this->mergeCacheResults($cachedResults);
94
-        }
95
-    }
96
-
97
-    /**
98
-     * Return result without any collection or object.
99
-     *
100
-     * @param array $result
101
-     *
102
-     * @return array
103
-     */
104
-    protected function rawResult(array $result): array
105
-    {
106
-        return $result;
107
-
108
-        return array_filter($result, function ($attribute) {
109
-            return !is_object($attribute);
110
-        });
111
-    }
112
-
113
-    /**
114
-     * Retrieve initial attributes for a single entity.
115
-     *
116
-     * @param string $id
117
-     *
118
-     * @return array
119
-     */
120
-    public function get(string $id = null): array
121
-    {
122
-        if ($this->has($id)) {
123
-            return $this->cache[$id];
124
-        }
125
-
126
-        return [];
127
-    }
128
-
129
-    /**
130
-     * Check if a record for this id exists.
131
-     *
132
-     * @param string $id
133
-     *
134
-     * @return bool
135
-     */
136
-    public function has(string $id = null): bool
137
-    {
138
-        return array_key_exists($id, $this->cache);
139
-    }
140
-
141
-    /**
142
-     * Combine new result set with existing attributes in
143
-     * cache.
144
-     *
145
-     * @param array $results
146
-     *
147
-     * @return void
148
-     */
149
-    protected function mergeCacheResults(array $results)
150
-    {
151
-        foreach ($results as $key => $entity) {
152
-            $this->cache[$key] = $entity;
153
-        }
154
-    }
155
-
156
-    /**
157
-     * Cache Relation's query result for an entity.
158
-     *
159
-     * @param string       $key          primary key of the cached entity
160
-     * @param string       $relation     name of the relation
161
-     * @param mixed        $results      results of the relationship's query
162
-     * @param Relationship $relationship
163
-     *
164
-     * @throws MappingException
165
-     *
166
-     * @return void
167
-     */
168
-    public function cacheLoadedRelationResult(string $key, string $relation, $results, Relationship $relationship)
169
-    {
170
-        if ($results instanceof EntityCollection) {
171
-            $this->cacheManyRelationResults($key, $relation, $results, $relationship);
172
-        }
173
-
174
-        // TODO : As we support popo Entities, Maybe this check isn't needed anymore,
175
-        // or we have to check that $result is an object instead
176
-        if ($results instanceof Mappable) {
177
-            $this->cacheSingleRelationResult($key, $relation, $results, $relationship);
178
-        }
179
-    }
180
-
181
-    /**
182
-     * Create a cachedRelationship instance which will hold related entity's hash and pivot attributes, if any.
183
-     *
184
-     * @param string       $relation
185
-     * @param array        $result
186
-     * @param Relationship $relationship
187
-     *
188
-     * @throws MappingException
189
-     *
190
-     * @return CachedRelationship
191
-     */
192
-    protected function getCachedRelationship(string $relation, $result, Relationship $relationship)
193
-    {
194
-        $pivotColumns = $relationship->getPivotAttributes();
195
-
196
-        if (!array_key_exists($relation, $this->pivotAttributes)) {
197
-            $this->pivotAttributes[$relation] = $pivotColumns;
198
-        }
199
-
200
-        $wrapper = $this->factory->make($result);
201
-
202
-        $hash = $wrapper->getEntityHash();
203
-
204
-        if (count($pivotColumns) > 0) {
205
-            $pivotAttributes = [];
206
-            foreach ($pivotColumns as $column) {
207
-                $pivot = $wrapper->getEntityAttribute('pivot');
208
-
209
-                $pivotWrapper = $this->factory->make($pivot);
210
-
211
-                $pivotAttributes[$column] = $pivotWrapper->getEntityAttribute($column);
212
-            }
213
-
214
-            $cachedRelationship = new CachedRelationship($hash, $pivotAttributes);
215
-        } else {
216
-            $cachedRelationship = new CachedRelationship($hash);
217
-        }
218
-
219
-        return $cachedRelationship;
220
-    }
221
-
222
-    /**
223
-     * Cache a many relationship.
224
-     *
225
-     * @param string           $parentKey
226
-     * @param string           $relation
227
-     * @param EntityCollection $results
228
-     * @param Relationship     $relationship
229
-     *
230
-     * @throws MappingException
231
-     */
232
-    protected function cacheManyRelationResults(string $parentKey, string $relation, $results, Relationship $relationship)
233
-    {
234
-        $this->cache[$parentKey][$relation] = [];
235
-
236
-        foreach ($results as $result) {
237
-            $cachedRelationship = $this->getCachedRelationship($relation, $result, $relationship);
238
-
239
-            $relatedHash = $cachedRelationship->getHash();
240
-
241
-            $this->cache[$parentKey][$relation][$relatedHash] = $cachedRelationship;
242
-        }
243
-    }
244
-
245
-    /**
246
-     * Cache a single relationship.
247
-     *
248
-     * @param string       $parentKey
249
-     * @param string       $relation
250
-     * @param Mappable     $result
251
-     * @param Relationship $relationship
252
-     *
253
-     * @throws MappingException
254
-     */
255
-    protected function cacheSingleRelationResult(string $parentKey, string $relation, $result, Relationship $relationship)
256
-    {
257
-        $this->cache[$parentKey][$relation] = $this->getCachedRelationship($relation, $result, $relationship);
258
-    }
259
-
260
-    /**
261
-     * Get Entity's Hash.
262
-     *
263
-     * @param  $entity
264
-     *
265
-     * @throws MappingException
266
-     *
267
-     * @return string
268
-     */
269
-    protected function getEntityHash(InternallyMappable $entity): string
270
-    {
271
-        $class = $entity->getEntityClass();
272
-
273
-        $mapper = Manager::getMapper($class);
274
-
275
-        $keyName = $mapper->getEntityMap()->getKeyName();
276
-
277
-        return $class.'.'.$entity->getEntityAttribute($keyName);
278
-    }
279
-
280
-    /**
281
-     * Refresh the cache record for an aggregated entity after a write operation.
282
-     *
283
-     * @param Aggregate $entity
284
-     */
285
-    public function refresh(Aggregate $entity)
286
-    {
287
-        $this->cache[$entity->getEntityKeyValue()] = $this->transform($entity);
288
-    }
289
-
290
-    /**
291
-     * Transform an Aggregated Entity into a cache record.
292
-     *
293
-     * @param Aggregate $aggregatedEntity
294
-     *
295
-     * @throws MappingException
296
-     *
297
-     * @return array
298
-     */
299
-    protected function transform(Aggregate $aggregatedEntity): array
300
-    {
301
-        $baseAttributes = $aggregatedEntity->getRawAttributes();
302
-
303
-        $relationAttributes = [];
304
-
305
-        // First we'll handle each relationships that are a one to one
306
-        // relation, and which will be saved as a CachedRelationship
307
-        // object inside the cache.
308
-
309
-        // NOTE : storing localRelationships maybe useless has we store
310
-        // the foreign key in the attributes already.
311
-
312
-        foreach ($this->entityMap->getSingleRelationships() as $relation) {
313
-            $aggregates = $aggregatedEntity->getRelationship($relation);
314
-
315
-            if (count($aggregates) == 1) {
316
-                $related = $aggregates[0];
317
-                $relationAttributes[$relation] = new CachedRelationship($related->getEntityHash());
318
-            }
319
-            if (count($aggregates) > 1) {
320
-                throw new MappingException("Single Relationship '$relation' contains several related entities");
321
-            }
322
-        }
323
-
324
-        // Then we'll handle the 'many' relationships and store them as
325
-        // an array of CachedRelationship objects.
326
-
327
-        foreach ($this->entityMap->getManyRelationships() as $relation) {
328
-            $aggregates = $aggregatedEntity->getRelationship($relation);
329
-
330
-            $relationAttributes[$relation] = [];
331
-
332
-            foreach ($aggregates as $aggregate) {
333
-                $relationAttributes[$relation][] = new CachedRelationship(
334
-                    $aggregate->getEntityHash(),
335
-                    $aggregate->getPivotAttributes()
336
-                );
337
-            }
338
-        }
339
-
340
-        return $baseAttributes + $relationAttributes;
341
-    }
342
-
343
-    /**
344
-     * Get pivot attributes for a relation.
345
-     *
346
-     * @param string             $relation
347
-     * @param InternallyMappable $entity
348
-     *
349
-     * @return array
350
-     */
351
-    protected function getPivotValues(string $relation, InternallyMappable $entity): array
352
-    {
353
-        $values = [];
354
-
355
-        $entityAttributes = $entity->getEntityAttributes();
356
-
357
-        if (array_key_exists($relation, $this->pivotAttributes)) {
358
-            foreach ($this->pivotAttributes[$relation] as $attribute) {
359
-                if (array_key_exists($attribute, $entityAttributes)) {
360
-                    $values[$attribute] = $entity->getEntityAttribute('pivot')->$attribute;
361
-                }
362
-            }
363
-        }
364
-
365
-        return $values;
366
-    }
367
-
368
-    /**
369
-     * Clear the entity Cache. Use with caution as it could result
370
-     * in unpredictable behaviour if the cached entities are stored
371
-     * after the cache clear operation.
372
-     *
373
-     * @return void
374
-     */
375
-    public function clear()
376
-    {
377
-        $this->cache = [];
378
-        $this->pivotAttributes = [];
379
-    }
20
+	/**
21
+	 * Entity's raw attributes/relationships.
22
+	 *
23
+	 * @var array
24
+	 */
25
+	protected $cache = [];
26
+
27
+	/**
28
+	 * Primary key => Entity instance correspondancy.
29
+	 *
30
+	 * @var array
31
+	 */
32
+	protected $instances = [];
33
+
34
+	/**
35
+	 * Entity Map for the current Entity Type.
36
+	 *
37
+	 * @var \Analogue\ORM\EntityMap
38
+	 */
39
+	protected $entityMap;
40
+
41
+	/**
42
+	 * Wrapper factory.
43
+	 *
44
+	 * @var \Analogue\ORM\System\Wrappers\Factory
45
+	 */
46
+	protected $factory;
47
+
48
+	/**
49
+	 * Associative array containing list of pivot attributes per relationship
50
+	 * so we don't have to call relationship method on refresh.
51
+	 *
52
+	 * @var array
53
+	 */
54
+	protected $pivotAttributes = [];
55
+
56
+	/**
57
+	 * EntityCache constructor.
58
+	 *
59
+	 * @param EntityMap $entityMap
60
+	 */
61
+	public function __construct(EntityMap $entityMap)
62
+	{
63
+		$this->entityMap = $entityMap;
64
+
65
+		$this->factory = new Factory();
66
+	}
67
+
68
+	/**
69
+	 * Add an array of key=>attributes representing
70
+	 * the initial state of loaded entities.
71
+	 *
72
+	 * @param array $results
73
+	 */
74
+	public function add(array $results)
75
+	{
76
+		$cachedResults = [];
77
+
78
+		$keyColumn = $this->entityMap->getKeyName();
79
+
80
+		foreach ($results as $result) {
81
+			$id = $result[$keyColumn];
82
+
83
+			// Forget the ID field from the cache attributes
84
+			// to prevent any side effect.
85
+			// TODO : remove primary key check from dirty attributes parsing
86
+			//unset($result[$keyColumn]);
87
+			$cachedResults[$id] = $this->rawResult($result);
88
+		}
89
+
90
+		if (empty($this->cache)) {
91
+			$this->cache = $cachedResults;
92
+		} else {
93
+			$this->mergeCacheResults($cachedResults);
94
+		}
95
+	}
96
+
97
+	/**
98
+	 * Return result without any collection or object.
99
+	 *
100
+	 * @param array $result
101
+	 *
102
+	 * @return array
103
+	 */
104
+	protected function rawResult(array $result): array
105
+	{
106
+		return $result;
107
+
108
+		return array_filter($result, function ($attribute) {
109
+			return !is_object($attribute);
110
+		});
111
+	}
112
+
113
+	/**
114
+	 * Retrieve initial attributes for a single entity.
115
+	 *
116
+	 * @param string $id
117
+	 *
118
+	 * @return array
119
+	 */
120
+	public function get(string $id = null): array
121
+	{
122
+		if ($this->has($id)) {
123
+			return $this->cache[$id];
124
+		}
125
+
126
+		return [];
127
+	}
128
+
129
+	/**
130
+	 * Check if a record for this id exists.
131
+	 *
132
+	 * @param string $id
133
+	 *
134
+	 * @return bool
135
+	 */
136
+	public function has(string $id = null): bool
137
+	{
138
+		return array_key_exists($id, $this->cache);
139
+	}
140
+
141
+	/**
142
+	 * Combine new result set with existing attributes in
143
+	 * cache.
144
+	 *
145
+	 * @param array $results
146
+	 *
147
+	 * @return void
148
+	 */
149
+	protected function mergeCacheResults(array $results)
150
+	{
151
+		foreach ($results as $key => $entity) {
152
+			$this->cache[$key] = $entity;
153
+		}
154
+	}
155
+
156
+	/**
157
+	 * Cache Relation's query result for an entity.
158
+	 *
159
+	 * @param string       $key          primary key of the cached entity
160
+	 * @param string       $relation     name of the relation
161
+	 * @param mixed        $results      results of the relationship's query
162
+	 * @param Relationship $relationship
163
+	 *
164
+	 * @throws MappingException
165
+	 *
166
+	 * @return void
167
+	 */
168
+	public function cacheLoadedRelationResult(string $key, string $relation, $results, Relationship $relationship)
169
+	{
170
+		if ($results instanceof EntityCollection) {
171
+			$this->cacheManyRelationResults($key, $relation, $results, $relationship);
172
+		}
173
+
174
+		// TODO : As we support popo Entities, Maybe this check isn't needed anymore,
175
+		// or we have to check that $result is an object instead
176
+		if ($results instanceof Mappable) {
177
+			$this->cacheSingleRelationResult($key, $relation, $results, $relationship);
178
+		}
179
+	}
180
+
181
+	/**
182
+	 * Create a cachedRelationship instance which will hold related entity's hash and pivot attributes, if any.
183
+	 *
184
+	 * @param string       $relation
185
+	 * @param array        $result
186
+	 * @param Relationship $relationship
187
+	 *
188
+	 * @throws MappingException
189
+	 *
190
+	 * @return CachedRelationship
191
+	 */
192
+	protected function getCachedRelationship(string $relation, $result, Relationship $relationship)
193
+	{
194
+		$pivotColumns = $relationship->getPivotAttributes();
195
+
196
+		if (!array_key_exists($relation, $this->pivotAttributes)) {
197
+			$this->pivotAttributes[$relation] = $pivotColumns;
198
+		}
199
+
200
+		$wrapper = $this->factory->make($result);
201
+
202
+		$hash = $wrapper->getEntityHash();
203
+
204
+		if (count($pivotColumns) > 0) {
205
+			$pivotAttributes = [];
206
+			foreach ($pivotColumns as $column) {
207
+				$pivot = $wrapper->getEntityAttribute('pivot');
208
+
209
+				$pivotWrapper = $this->factory->make($pivot);
210
+
211
+				$pivotAttributes[$column] = $pivotWrapper->getEntityAttribute($column);
212
+			}
213
+
214
+			$cachedRelationship = new CachedRelationship($hash, $pivotAttributes);
215
+		} else {
216
+			$cachedRelationship = new CachedRelationship($hash);
217
+		}
218
+
219
+		return $cachedRelationship;
220
+	}
221
+
222
+	/**
223
+	 * Cache a many relationship.
224
+	 *
225
+	 * @param string           $parentKey
226
+	 * @param string           $relation
227
+	 * @param EntityCollection $results
228
+	 * @param Relationship     $relationship
229
+	 *
230
+	 * @throws MappingException
231
+	 */
232
+	protected function cacheManyRelationResults(string $parentKey, string $relation, $results, Relationship $relationship)
233
+	{
234
+		$this->cache[$parentKey][$relation] = [];
235
+
236
+		foreach ($results as $result) {
237
+			$cachedRelationship = $this->getCachedRelationship($relation, $result, $relationship);
238
+
239
+			$relatedHash = $cachedRelationship->getHash();
240
+
241
+			$this->cache[$parentKey][$relation][$relatedHash] = $cachedRelationship;
242
+		}
243
+	}
244
+
245
+	/**
246
+	 * Cache a single relationship.
247
+	 *
248
+	 * @param string       $parentKey
249
+	 * @param string       $relation
250
+	 * @param Mappable     $result
251
+	 * @param Relationship $relationship
252
+	 *
253
+	 * @throws MappingException
254
+	 */
255
+	protected function cacheSingleRelationResult(string $parentKey, string $relation, $result, Relationship $relationship)
256
+	{
257
+		$this->cache[$parentKey][$relation] = $this->getCachedRelationship($relation, $result, $relationship);
258
+	}
259
+
260
+	/**
261
+	 * Get Entity's Hash.
262
+	 *
263
+	 * @param  $entity
264
+	 *
265
+	 * @throws MappingException
266
+	 *
267
+	 * @return string
268
+	 */
269
+	protected function getEntityHash(InternallyMappable $entity): string
270
+	{
271
+		$class = $entity->getEntityClass();
272
+
273
+		$mapper = Manager::getMapper($class);
274
+
275
+		$keyName = $mapper->getEntityMap()->getKeyName();
276
+
277
+		return $class.'.'.$entity->getEntityAttribute($keyName);
278
+	}
279
+
280
+	/**
281
+	 * Refresh the cache record for an aggregated entity after a write operation.
282
+	 *
283
+	 * @param Aggregate $entity
284
+	 */
285
+	public function refresh(Aggregate $entity)
286
+	{
287
+		$this->cache[$entity->getEntityKeyValue()] = $this->transform($entity);
288
+	}
289
+
290
+	/**
291
+	 * Transform an Aggregated Entity into a cache record.
292
+	 *
293
+	 * @param Aggregate $aggregatedEntity
294
+	 *
295
+	 * @throws MappingException
296
+	 *
297
+	 * @return array
298
+	 */
299
+	protected function transform(Aggregate $aggregatedEntity): array
300
+	{
301
+		$baseAttributes = $aggregatedEntity->getRawAttributes();
302
+
303
+		$relationAttributes = [];
304
+
305
+		// First we'll handle each relationships that are a one to one
306
+		// relation, and which will be saved as a CachedRelationship
307
+		// object inside the cache.
308
+
309
+		// NOTE : storing localRelationships maybe useless has we store
310
+		// the foreign key in the attributes already.
311
+
312
+		foreach ($this->entityMap->getSingleRelationships() as $relation) {
313
+			$aggregates = $aggregatedEntity->getRelationship($relation);
314
+
315
+			if (count($aggregates) == 1) {
316
+				$related = $aggregates[0];
317
+				$relationAttributes[$relation] = new CachedRelationship($related->getEntityHash());
318
+			}
319
+			if (count($aggregates) > 1) {
320
+				throw new MappingException("Single Relationship '$relation' contains several related entities");
321
+			}
322
+		}
323
+
324
+		// Then we'll handle the 'many' relationships and store them as
325
+		// an array of CachedRelationship objects.
326
+
327
+		foreach ($this->entityMap->getManyRelationships() as $relation) {
328
+			$aggregates = $aggregatedEntity->getRelationship($relation);
329
+
330
+			$relationAttributes[$relation] = [];
331
+
332
+			foreach ($aggregates as $aggregate) {
333
+				$relationAttributes[$relation][] = new CachedRelationship(
334
+					$aggregate->getEntityHash(),
335
+					$aggregate->getPivotAttributes()
336
+				);
337
+			}
338
+		}
339
+
340
+		return $baseAttributes + $relationAttributes;
341
+	}
342
+
343
+	/**
344
+	 * Get pivot attributes for a relation.
345
+	 *
346
+	 * @param string             $relation
347
+	 * @param InternallyMappable $entity
348
+	 *
349
+	 * @return array
350
+	 */
351
+	protected function getPivotValues(string $relation, InternallyMappable $entity): array
352
+	{
353
+		$values = [];
354
+
355
+		$entityAttributes = $entity->getEntityAttributes();
356
+
357
+		if (array_key_exists($relation, $this->pivotAttributes)) {
358
+			foreach ($this->pivotAttributes[$relation] as $attribute) {
359
+				if (array_key_exists($attribute, $entityAttributes)) {
360
+					$values[$attribute] = $entity->getEntityAttribute('pivot')->$attribute;
361
+				}
362
+			}
363
+		}
364
+
365
+		return $values;
366
+	}
367
+
368
+	/**
369
+	 * Clear the entity Cache. Use with caution as it could result
370
+	 * in unpredictable behaviour if the cached entities are stored
371
+	 * after the cache clear operation.
372
+	 *
373
+	 * @return void
374
+	 */
375
+	public function clear()
376
+	{
377
+		$this->cache = [];
378
+		$this->pivotAttributes = [];
379
+	}
380 380
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -105,7 +105,7 @@
 block discarded – undo
105 105
     {
106 106
         return $result;
107 107
 
108
-        return array_filter($result, function ($attribute) {
108
+        return array_filter($result, function($attribute) {
109 109
             return !is_object($attribute);
110 110
         });
111 111
     }
Please login to merge, or discard this patch.
src/Relationships/EmbeddedRelationship.php 1 patch
Indentation   +246 added lines, -246 removed lines patch added patch discarded remove patch
@@ -8,250 +8,250 @@
 block discarded – undo
8 8
 
9 9
 abstract class EmbeddedRelationship
10 10
 {
11
-    /**
12
-     * The class that embeds the current relation.
13
-     *
14
-     * @var string
15
-     */
16
-    protected $parentClass;
17
-
18
-    /**
19
-     * The class of the embedded relation.
20
-     *
21
-     * @var string
22
-     */
23
-    protected $relatedClass;
24
-
25
-    /**
26
-     * The relation attribute on the parent object.
27
-     *
28
-     * @var string
29
-     */
30
-    protected $relation;
31
-
32
-    /**
33
-     * If set to true, embedded Object's attributes will
34
-     * be stored as a serialized array in a JSON Column.
35
-     *
36
-     * @var bool
37
-     */
38
-    protected $asArray = false;
39
-
40
-    /**
41
-     * If set to true, embedded Object's attributes will
42
-     * be json encoded before storing to database.
43
-     *
44
-     * @var bool
45
-     */
46
-    protected $asJson = false;
47
-
48
-    /**
49
-     * Prefix on which the object's attributes are saved into
50
-     * the parent's table. defaults to "<relatedClass>_".
51
-     *
52
-     * @var string
53
-     */
54
-    protected $prefix;
55
-
56
-    /**
57
-     * Attributes Map allow the calling EntityMap to overrides attributes
58
-     * on the embedded relation.
59
-     *
60
-     * @var array
61
-     */
62
-    protected $columnMap = [];
63
-
64
-    /**
65
-     * Wrapper factory.
66
-     *
67
-     * @var \Analogue\ORM\System\Wrappers\Factory
68
-     */
69
-    protected $factory;
70
-
71
-    public function __construct($parent, string $relatedClass, string $relation)
72
-    {
73
-        $this->parentClass = get_class($parent);
74
-        $this->relatedClass = $relatedClass;
75
-        $this->relation = $relation;
76
-        $this->prefix = $relation.'_';
77
-        $this->factory = new Factory();
78
-    }
79
-
80
-    /**
81
-     * Switch the 'store as array' feature.
82
-     *
83
-     * @param bool $storeAsArray
84
-     *
85
-     * @return static
86
-     */
87
-    public function asArray(bool $storeAsArray = true)
88
-    {
89
-        $this->asArray = $storeAsArray;
90
-
91
-        return $this;
92
-    }
93
-
94
-    /**
95
-     * Switch the 'store as json' feature.
96
-     *
97
-     * @param bool $storeAsJson
98
-     *
99
-     * @return static
100
-     */
101
-    public function asJson(bool $storeAsJson = true)
102
-    {
103
-        $this->asJson = $storeAsJson;
104
-
105
-        return $this->asArray();
106
-    }
107
-
108
-    /**
109
-     * Set the column map for the embedded relation.
110
-     *
111
-     * @param array $columns
112
-     *
113
-     * @return static
114
-     */
115
-    public function setColumnMap(array $columns)
116
-    {
117
-        $this->columnMap = $columns;
118
-
119
-        return $this;
120
-    }
121
-
122
-    /**
123
-     * Set parent's attribute prefix.
124
-     *
125
-     * @param string $prefix
126
-     *
127
-     * @return static
128
-     */
129
-    public function setPrefix(string $prefix)
130
-    {
131
-        $this->prefix = $prefix;
132
-
133
-        return $this;
134
-    }
135
-
136
-    /**
137
-     * Return parent's attribute prefix.
138
-     *
139
-     * @return string
140
-     */
141
-    public function getPrefix() : string
142
-    {
143
-        return $this->prefix;
144
-    }
145
-
146
-    /**
147
-     * Get the embedded object's attributes that will be
148
-     * hydrated using parent's entity attributes.
149
-     *
150
-     * @return array
151
-     */
152
-    protected function getEmbeddedObjectAttributes() : array
153
-    {
154
-        $entityMap = $this->getRelatedMapper()->getEntityMap();
155
-
156
-        $attributes = $entityMap->getAttributes();
157
-        $properties = $entityMap->getProperties();
158
-
159
-        return array_merge($attributes, $properties);
160
-    }
161
-
162
-    /**
163
-     * Get the corresponding attribute on parent's attributes.
164
-     *
165
-     * @param string $key
166
-     *
167
-     * @return string
168
-     */
169
-    protected function getParentAttributeKey($key) : string
170
-    {
171
-        return $this->getPrefixedAttributeKey($this->getMappedParentAttribute($key));
172
-    }
173
-
174
-    /**
175
-     * Get attribute name from the parent, if a map has been
176
-     * defined.
177
-     *
178
-     * @param string $key
179
-     *
180
-     * @return string
181
-     */
182
-    protected function getMappedParentAttribute(string $key) : string
183
-    {
184
-        if (array_key_exists($key, $this->columnMap)) {
185
-            return $this->columnMap[$key];
186
-        } else {
187
-            return $key;
188
-        }
189
-    }
190
-
191
-    /**
192
-     * Return the name of the attribute with key.
193
-     *
194
-     * @param string $attributeKey
195
-     *
196
-     * @return string
197
-     */
198
-    protected function getPrefixedAttributeKey(string $attributeKey) : string
199
-    {
200
-        return $this->prefix.$attributeKey;
201
-    }
202
-
203
-    /**
204
-     * Transform attributes into embedded object(s), and
205
-     * match it into the given resultset.
206
-     *
207
-     * @return array
208
-     */
209
-    abstract public function match(array $results) : array;
210
-
211
-    /**
212
-     * Build an embedded object instance.
213
-     *
214
-     * @param array $attributes
215
-     *
216
-     * @return mixed
217
-     */
218
-    protected function buildEmbeddedObject(array $attributes)
219
-    {
220
-        $resultBuilder = new ResultBuilder($this->getRelatedMapper());
221
-
222
-        // TODO : find a way to support eager load within an embedded
223
-        // object.
224
-        $eagerLoads = [];
225
-
226
-        return $resultBuilder->build([$attributes], $eagerLoads)[0];
227
-    }
228
-
229
-    /**
230
-     * Transform embedded object into db column(s).
231
-     *
232
-     * @param mixed $object
233
-     *
234
-     * @return array $columns
235
-     */
236
-    abstract public function normalize($object) : array;
237
-
238
-    /**
239
-     * Return parent mapper.
240
-     *
241
-     * @return \Analogue\ORM\System\Mapper
242
-     */
243
-    protected function getParentMapper()
244
-    {
245
-        return Manager::getInstance()->mapper($this->parentClass);
246
-    }
247
-
248
-    /**
249
-     * Return embedded relationship mapper.
250
-     *
251
-     * @return \Analogue\ORM\System\Mapper
252
-     */
253
-    protected function getRelatedMapper()
254
-    {
255
-        return Manager::getInstance()->mapper($this->relatedClass);
256
-    }
11
+	/**
12
+	 * The class that embeds the current relation.
13
+	 *
14
+	 * @var string
15
+	 */
16
+	protected $parentClass;
17
+
18
+	/**
19
+	 * The class of the embedded relation.
20
+	 *
21
+	 * @var string
22
+	 */
23
+	protected $relatedClass;
24
+
25
+	/**
26
+	 * The relation attribute on the parent object.
27
+	 *
28
+	 * @var string
29
+	 */
30
+	protected $relation;
31
+
32
+	/**
33
+	 * If set to true, embedded Object's attributes will
34
+	 * be stored as a serialized array in a JSON Column.
35
+	 *
36
+	 * @var bool
37
+	 */
38
+	protected $asArray = false;
39
+
40
+	/**
41
+	 * If set to true, embedded Object's attributes will
42
+	 * be json encoded before storing to database.
43
+	 *
44
+	 * @var bool
45
+	 */
46
+	protected $asJson = false;
47
+
48
+	/**
49
+	 * Prefix on which the object's attributes are saved into
50
+	 * the parent's table. defaults to "<relatedClass>_".
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $prefix;
55
+
56
+	/**
57
+	 * Attributes Map allow the calling EntityMap to overrides attributes
58
+	 * on the embedded relation.
59
+	 *
60
+	 * @var array
61
+	 */
62
+	protected $columnMap = [];
63
+
64
+	/**
65
+	 * Wrapper factory.
66
+	 *
67
+	 * @var \Analogue\ORM\System\Wrappers\Factory
68
+	 */
69
+	protected $factory;
70
+
71
+	public function __construct($parent, string $relatedClass, string $relation)
72
+	{
73
+		$this->parentClass = get_class($parent);
74
+		$this->relatedClass = $relatedClass;
75
+		$this->relation = $relation;
76
+		$this->prefix = $relation.'_';
77
+		$this->factory = new Factory();
78
+	}
79
+
80
+	/**
81
+	 * Switch the 'store as array' feature.
82
+	 *
83
+	 * @param bool $storeAsArray
84
+	 *
85
+	 * @return static
86
+	 */
87
+	public function asArray(bool $storeAsArray = true)
88
+	{
89
+		$this->asArray = $storeAsArray;
90
+
91
+		return $this;
92
+	}
93
+
94
+	/**
95
+	 * Switch the 'store as json' feature.
96
+	 *
97
+	 * @param bool $storeAsJson
98
+	 *
99
+	 * @return static
100
+	 */
101
+	public function asJson(bool $storeAsJson = true)
102
+	{
103
+		$this->asJson = $storeAsJson;
104
+
105
+		return $this->asArray();
106
+	}
107
+
108
+	/**
109
+	 * Set the column map for the embedded relation.
110
+	 *
111
+	 * @param array $columns
112
+	 *
113
+	 * @return static
114
+	 */
115
+	public function setColumnMap(array $columns)
116
+	{
117
+		$this->columnMap = $columns;
118
+
119
+		return $this;
120
+	}
121
+
122
+	/**
123
+	 * Set parent's attribute prefix.
124
+	 *
125
+	 * @param string $prefix
126
+	 *
127
+	 * @return static
128
+	 */
129
+	public function setPrefix(string $prefix)
130
+	{
131
+		$this->prefix = $prefix;
132
+
133
+		return $this;
134
+	}
135
+
136
+	/**
137
+	 * Return parent's attribute prefix.
138
+	 *
139
+	 * @return string
140
+	 */
141
+	public function getPrefix() : string
142
+	{
143
+		return $this->prefix;
144
+	}
145
+
146
+	/**
147
+	 * Get the embedded object's attributes that will be
148
+	 * hydrated using parent's entity attributes.
149
+	 *
150
+	 * @return array
151
+	 */
152
+	protected function getEmbeddedObjectAttributes() : array
153
+	{
154
+		$entityMap = $this->getRelatedMapper()->getEntityMap();
155
+
156
+		$attributes = $entityMap->getAttributes();
157
+		$properties = $entityMap->getProperties();
158
+
159
+		return array_merge($attributes, $properties);
160
+	}
161
+
162
+	/**
163
+	 * Get the corresponding attribute on parent's attributes.
164
+	 *
165
+	 * @param string $key
166
+	 *
167
+	 * @return string
168
+	 */
169
+	protected function getParentAttributeKey($key) : string
170
+	{
171
+		return $this->getPrefixedAttributeKey($this->getMappedParentAttribute($key));
172
+	}
173
+
174
+	/**
175
+	 * Get attribute name from the parent, if a map has been
176
+	 * defined.
177
+	 *
178
+	 * @param string $key
179
+	 *
180
+	 * @return string
181
+	 */
182
+	protected function getMappedParentAttribute(string $key) : string
183
+	{
184
+		if (array_key_exists($key, $this->columnMap)) {
185
+			return $this->columnMap[$key];
186
+		} else {
187
+			return $key;
188
+		}
189
+	}
190
+
191
+	/**
192
+	 * Return the name of the attribute with key.
193
+	 *
194
+	 * @param string $attributeKey
195
+	 *
196
+	 * @return string
197
+	 */
198
+	protected function getPrefixedAttributeKey(string $attributeKey) : string
199
+	{
200
+		return $this->prefix.$attributeKey;
201
+	}
202
+
203
+	/**
204
+	 * Transform attributes into embedded object(s), and
205
+	 * match it into the given resultset.
206
+	 *
207
+	 * @return array
208
+	 */
209
+	abstract public function match(array $results) : array;
210
+
211
+	/**
212
+	 * Build an embedded object instance.
213
+	 *
214
+	 * @param array $attributes
215
+	 *
216
+	 * @return mixed
217
+	 */
218
+	protected function buildEmbeddedObject(array $attributes)
219
+	{
220
+		$resultBuilder = new ResultBuilder($this->getRelatedMapper());
221
+
222
+		// TODO : find a way to support eager load within an embedded
223
+		// object.
224
+		$eagerLoads = [];
225
+
226
+		return $resultBuilder->build([$attributes], $eagerLoads)[0];
227
+	}
228
+
229
+	/**
230
+	 * Transform embedded object into db column(s).
231
+	 *
232
+	 * @param mixed $object
233
+	 *
234
+	 * @return array $columns
235
+	 */
236
+	abstract public function normalize($object) : array;
237
+
238
+	/**
239
+	 * Return parent mapper.
240
+	 *
241
+	 * @return \Analogue\ORM\System\Mapper
242
+	 */
243
+	protected function getParentMapper()
244
+	{
245
+		return Manager::getInstance()->mapper($this->parentClass);
246
+	}
247
+
248
+	/**
249
+	 * Return embedded relationship mapper.
250
+	 *
251
+	 * @return \Analogue\ORM\System\Mapper
252
+	 */
253
+	protected function getRelatedMapper()
254
+	{
255
+		return Manager::getInstance()->mapper($this->relatedClass);
256
+	}
257 257
 }
Please login to merge, or discard this patch.
src/Relationships/EmbedsOne.php 1 patch
Indentation   +192 added lines, -192 removed lines patch added patch discarded remove patch
@@ -6,196 +6,196 @@
 block discarded – undo
6 6
 
7 7
 class EmbedsOne extends EmbeddedRelationship
8 8
 {
9
-    /**
10
-     * The relation attribute on the parent object.
11
-     *
12
-     * @var string
13
-     */
14
-    protected $relation;
15
-
16
-    /**
17
-     * Transform attributes into embedded object(s), and
18
-     * match it into the given result set.
19
-     *
20
-     * @param array $results
21
-     *
22
-     * @return array
23
-     */
24
-    public function match(array $results) : array
25
-    {
26
-        return array_map([$this, 'matchSingleResult'], $results);
27
-    }
28
-
29
-    /**
30
-     * Match a single database row's attributes to a single
31
-     * object, and return the updated attributes.
32
-     *
33
-     * @param array $attributes
34
-     *
35
-     * @return array
36
-     */
37
-    public function matchSingleResult(array $attributes) : array
38
-    {
39
-        return $this->asArray ? $this->matchAsArray($attributes) : $this->matchAsAttributes($attributes);
40
-    }
41
-
42
-    /**
43
-     * Match array attribute from parent to an embedded object,
44
-     * and return the updated attributes.
45
-     *
46
-     * @param array $attributes
47
-     *
48
-     * @throws MappingException
49
-     *
50
-     * @return array
51
-     */
52
-    protected function matchAsArray(array $attributes) : array
53
-    {
54
-        // Extract the attributes with the key of the relation,
55
-        // which should be an array.
56
-        $key = $this->relation;
57
-
58
-        if (!array_key_exists($key, $attributes) && !is_array($key)) {
59
-            throw new MappingException("'$key' column should be an array");
60
-        }
61
-
62
-        if ($this->asJson) {
63
-            $attributes[$key] = json_decode($attributes[$key], true);
64
-        }
65
-
66
-        $attributes[$key] = $this->buildEmbeddedObject($attributes[$key]);
67
-
68
-        return $attributes;
69
-    }
70
-
71
-    /**
72
-     * Transform attributes from the parent entity result into
73
-     * an embedded object, and return the updated attributes.
74
-     *
75
-     * @param array $attributes
76
-     *
77
-     * @return array
78
-     */
79
-    protected function matchAsAttributes(array $attributes) : array
80
-    {
81
-        $attributesMap = $this->getAttributesDictionnary();
82
-
83
-        // Get the subset that only the embedded object is concerned with and, convert it back
84
-        // to embedded object attributes keys
85
-        $originalAttributes = array_only($attributes, $attributesMap);
86
-
87
-        $embeddedAttributes = [];
88
-
89
-        foreach ($originalAttributes as $key => $value) {
90
-            $embeddedKey = array_search($key, $attributesMap);
91
-            $embeddedAttributes[$embeddedKey] = $value;
92
-        }
93
-
94
-        // Unset original attributes before, just in case one of the keys of the
95
-        // original attributes is equals the relation name.
96
-        foreach (array_keys($originalAttributes) as $key) {
97
-            unset($attributes[$key]);
98
-        }
99
-
100
-        // Build object
101
-        $attributes[$this->relation] = $this->buildEmbeddedObject($embeddedAttributes);
102
-
103
-        return $attributes;
104
-    }
105
-
106
-    /**
107
-     * Return a dictionary of attributes key on parent Entity.
108
-     *
109
-     * @return array
110
-     */
111
-    protected function getAttributesDictionnary() : array
112
-    {
113
-        // Get attributes that belongs to the embedded object
114
-        $embeddedAttributeKeys = $this->getEmbeddedObjectAttributes();
115
-
116
-        $attributesMap = [];
117
-
118
-        // Build a dictionary for corresponding object attributes => parent attributes
119
-        foreach ($embeddedAttributeKeys as $key) {
120
-            $attributesMap[$key] = $this->getParentAttributeKey($key);
121
-        }
122
-
123
-        return $attributesMap;
124
-    }
125
-
126
-    /**
127
-     * Transform embedded object into DB column(s).
128
-     *
129
-     * @param mixed $object
130
-     *
131
-     * @return array $columns
132
-     */
133
-    public function normalize($object) : array
134
-    {
135
-        return $this->asArray ? $this->normalizeAsArray($object) : $this->normalizeAsAttributes($object);
136
-    }
137
-
138
-    /**
139
-     * Normalize object an array containing raw attributes.
140
-     *
141
-     * @param mixed $object
142
-     *
143
-     * @return array
144
-     */
145
-    protected function normalizeAsArray($object) : array
146
-    {
147
-        $wrapper = $this->factory->make($object);
148
-
149
-        $value = $wrapper->getEntityAttributes();
150
-
151
-        if ($this->asJson) {
152
-            $value = json_encode($value);
153
-        }
154
-
155
-        return [$this->relation => $value];
156
-    }
157
-
158
-    /**
159
-     * Normalize object as parent's attributes.
160
-     *
161
-     * @param mixed $object
162
-     *
163
-     * @return array
164
-     */
165
-    protected function normalizeAsAttributes($object) : array
166
-    {
167
-        if (is_null($object)) {
168
-            return $this->nullObjectAttributes();
169
-        }
170
-
171
-        $attributesMap = $this->getAttributesDictionnary();
172
-
173
-        $wrapper = $this->factory->make($object);
174
-
175
-        $normalizedAttributes = [];
176
-
177
-        foreach ($attributesMap as $embedKey => $parentKey) {
178
-            $normalizedAttributes[$parentKey] = $wrapper->getEntityAttribute($embedKey);
179
-        }
180
-
181
-        return $normalizedAttributes;
182
-    }
183
-
184
-    /**
185
-     * Set all object attributes to null.
186
-     *
187
-     * @return array
188
-     */
189
-    protected function nullObjectAttributes() : array
190
-    {
191
-        $attributesMap = $this->getAttributesDictionnary();
192
-
193
-        $normalizedAttributes = [];
194
-
195
-        foreach ($attributesMap as $embedKey => $parentKey) {
196
-            $normalizedAttributes[$parentKey] = null;
197
-        }
198
-
199
-        return $normalizedAttributes;
200
-    }
9
+	/**
10
+	 * The relation attribute on the parent object.
11
+	 *
12
+	 * @var string
13
+	 */
14
+	protected $relation;
15
+
16
+	/**
17
+	 * Transform attributes into embedded object(s), and
18
+	 * match it into the given result set.
19
+	 *
20
+	 * @param array $results
21
+	 *
22
+	 * @return array
23
+	 */
24
+	public function match(array $results) : array
25
+	{
26
+		return array_map([$this, 'matchSingleResult'], $results);
27
+	}
28
+
29
+	/**
30
+	 * Match a single database row's attributes to a single
31
+	 * object, and return the updated attributes.
32
+	 *
33
+	 * @param array $attributes
34
+	 *
35
+	 * @return array
36
+	 */
37
+	public function matchSingleResult(array $attributes) : array
38
+	{
39
+		return $this->asArray ? $this->matchAsArray($attributes) : $this->matchAsAttributes($attributes);
40
+	}
41
+
42
+	/**
43
+	 * Match array attribute from parent to an embedded object,
44
+	 * and return the updated attributes.
45
+	 *
46
+	 * @param array $attributes
47
+	 *
48
+	 * @throws MappingException
49
+	 *
50
+	 * @return array
51
+	 */
52
+	protected function matchAsArray(array $attributes) : array
53
+	{
54
+		// Extract the attributes with the key of the relation,
55
+		// which should be an array.
56
+		$key = $this->relation;
57
+
58
+		if (!array_key_exists($key, $attributes) && !is_array($key)) {
59
+			throw new MappingException("'$key' column should be an array");
60
+		}
61
+
62
+		if ($this->asJson) {
63
+			$attributes[$key] = json_decode($attributes[$key], true);
64
+		}
65
+
66
+		$attributes[$key] = $this->buildEmbeddedObject($attributes[$key]);
67
+
68
+		return $attributes;
69
+	}
70
+
71
+	/**
72
+	 * Transform attributes from the parent entity result into
73
+	 * an embedded object, and return the updated attributes.
74
+	 *
75
+	 * @param array $attributes
76
+	 *
77
+	 * @return array
78
+	 */
79
+	protected function matchAsAttributes(array $attributes) : array
80
+	{
81
+		$attributesMap = $this->getAttributesDictionnary();
82
+
83
+		// Get the subset that only the embedded object is concerned with and, convert it back
84
+		// to embedded object attributes keys
85
+		$originalAttributes = array_only($attributes, $attributesMap);
86
+
87
+		$embeddedAttributes = [];
88
+
89
+		foreach ($originalAttributes as $key => $value) {
90
+			$embeddedKey = array_search($key, $attributesMap);
91
+			$embeddedAttributes[$embeddedKey] = $value;
92
+		}
93
+
94
+		// Unset original attributes before, just in case one of the keys of the
95
+		// original attributes is equals the relation name.
96
+		foreach (array_keys($originalAttributes) as $key) {
97
+			unset($attributes[$key]);
98
+		}
99
+
100
+		// Build object
101
+		$attributes[$this->relation] = $this->buildEmbeddedObject($embeddedAttributes);
102
+
103
+		return $attributes;
104
+	}
105
+
106
+	/**
107
+	 * Return a dictionary of attributes key on parent Entity.
108
+	 *
109
+	 * @return array
110
+	 */
111
+	protected function getAttributesDictionnary() : array
112
+	{
113
+		// Get attributes that belongs to the embedded object
114
+		$embeddedAttributeKeys = $this->getEmbeddedObjectAttributes();
115
+
116
+		$attributesMap = [];
117
+
118
+		// Build a dictionary for corresponding object attributes => parent attributes
119
+		foreach ($embeddedAttributeKeys as $key) {
120
+			$attributesMap[$key] = $this->getParentAttributeKey($key);
121
+		}
122
+
123
+		return $attributesMap;
124
+	}
125
+
126
+	/**
127
+	 * Transform embedded object into DB column(s).
128
+	 *
129
+	 * @param mixed $object
130
+	 *
131
+	 * @return array $columns
132
+	 */
133
+	public function normalize($object) : array
134
+	{
135
+		return $this->asArray ? $this->normalizeAsArray($object) : $this->normalizeAsAttributes($object);
136
+	}
137
+
138
+	/**
139
+	 * Normalize object an array containing raw attributes.
140
+	 *
141
+	 * @param mixed $object
142
+	 *
143
+	 * @return array
144
+	 */
145
+	protected function normalizeAsArray($object) : array
146
+	{
147
+		$wrapper = $this->factory->make($object);
148
+
149
+		$value = $wrapper->getEntityAttributes();
150
+
151
+		if ($this->asJson) {
152
+			$value = json_encode($value);
153
+		}
154
+
155
+		return [$this->relation => $value];
156
+	}
157
+
158
+	/**
159
+	 * Normalize object as parent's attributes.
160
+	 *
161
+	 * @param mixed $object
162
+	 *
163
+	 * @return array
164
+	 */
165
+	protected function normalizeAsAttributes($object) : array
166
+	{
167
+		if (is_null($object)) {
168
+			return $this->nullObjectAttributes();
169
+		}
170
+
171
+		$attributesMap = $this->getAttributesDictionnary();
172
+
173
+		$wrapper = $this->factory->make($object);
174
+
175
+		$normalizedAttributes = [];
176
+
177
+		foreach ($attributesMap as $embedKey => $parentKey) {
178
+			$normalizedAttributes[$parentKey] = $wrapper->getEntityAttribute($embedKey);
179
+		}
180
+
181
+		return $normalizedAttributes;
182
+	}
183
+
184
+	/**
185
+	 * Set all object attributes to null.
186
+	 *
187
+	 * @return array
188
+	 */
189
+	protected function nullObjectAttributes() : array
190
+	{
191
+		$attributesMap = $this->getAttributesDictionnary();
192
+
193
+		$normalizedAttributes = [];
194
+
195
+		foreach ($attributesMap as $embedKey => $parentKey) {
196
+			$normalizedAttributes[$parentKey] = null;
197
+		}
198
+
199
+		return $normalizedAttributes;
200
+	}
201 201
 }
Please login to merge, or discard this patch.