Completed
Branch master (cbd196)
by Rémi
08:54
created
src/EntityMap.php 3 patches
Doc Comments   +3 added lines, -7 removed lines patch added patch discarded remove patch
@@ -928,8 +928,7 @@  discard block
 block discarded – undo
928 928
     /**
929 929
      * Define an Embedded Object.
930 930
      *
931
-     * @param mixed  $entity
932
-     * @param string $related
931
+     * @param string $relatedClass
933 932
      *
934 933
      * @return EmbedsOne
935 934
      */
@@ -949,8 +948,7 @@  discard block
 block discarded – undo
949 948
     /**
950 949
      * Define an Embedded Collection.
951 950
      *
952
-     * @param mixed  $entity
953
-     * @param string $related
951
+     * @param string $relatedClass
954 952
      *
955 953
      * @return EmbedsOne
956 954
      */
@@ -1056,7 +1054,6 @@  discard block
 block discarded – undo
1056 1054
      * @param string      $related
1057 1055
      * @param string|null $foreignKey
1058 1056
      * @param string|null $otherKey
1059
-     * @param string|null $relation
1060 1057
      *
1061 1058
      * @throws MappingException
1062 1059
      *
@@ -1261,11 +1258,10 @@  discard block
 block discarded – undo
1261 1258
      * Define a many-to-many relationship.
1262 1259
      *
1263 1260
      * @param mixed       $entity
1264
-     * @param string      $relatedClass
1261
+     * @param string      $related
1265 1262
      * @param string|null $table
1266 1263
      * @param string|null $foreignKey
1267 1264
      * @param string|null $otherKey
1268
-     * @param string|null $relation
1269 1265
      *
1270 1266
      * @throws MappingException
1271 1267
      *
Please login to merge, or discard this patch.
Indentation   +1553 added lines, -1553 removed lines patch added patch discarded remove patch
@@ -25,1557 +25,1557 @@
 block discarded – undo
25 25
  */
26 26
 class EntityMap
27 27
 {
28
-    /**
29
-     * The mapping driver to use with this entity.
30
-     *
31
-     * @var string
32
-     */
33
-    protected $driver = 'illuminate';
34
-
35
-    /**
36
-     * The Database Connection name for the model.
37
-     *
38
-     * @var string
39
-     */
40
-    protected $connection;
41
-
42
-    /**
43
-     * The table associated with the entity.
44
-     *
45
-     * @var string|null
46
-     */
47
-    protected $table = null;
48
-
49
-    /**
50
-     * The primary key for the model.
51
-     *
52
-     * @var string
53
-     */
54
-    protected $primaryKey = 'id';
55
-
56
-    /**
57
-     * Name of the entity's array property that should
58
-     * contain the attributes.
59
-     * If set to null, analogue will only hydrate object's properties.
60
-     *
61
-     * @var string|null
62
-     */
63
-    protected $arrayName = 'attributes';
64
-
65
-    /**
66
-     * Array containing the list of database columns to be mapped
67
-     * in the attributes array of the entity.
68
-     *
69
-     * @var array
70
-     */
71
-    protected $attributes = [];
72
-
73
-    /**
74
-     * Array containing the list of database columns to be mapped
75
-     * to the entity's class properties.
76
-     *
77
-     * @var array
78
-     */
79
-    protected $properties = [];
80
-
81
-    /**
82
-     * The Custom Domain Class to use with this mapping.
83
-     *
84
-     * @var string|null
85
-     */
86
-    protected $class = null;
87
-
88
-    /**
89
-     * Embedded Value Objects.
90
-     *
91
-     * @var array
92
-     */
93
-    protected $embeddables = [];
94
-
95
-    /**
96
-     * Determine the relationships method used on the entity.
97
-     * If not set, mapper will autodetect them.
98
-     *
99
-     * @var array
100
-     */
101
-    private $relationships = [];
102
-
103
-    /**
104
-     * Relationships that should be treated as collection.
105
-     *
106
-     * @var array
107
-     */
108
-    private $manyRelations = [];
109
-
110
-    /**
111
-     * Relationships that should be treated as single entity.
112
-     *
113
-     * @var array
114
-     */
115
-    private $singleRelations = [];
116
-
117
-    /**
118
-     * Relationships for which the key is stored in the Entity itself.
119
-     *
120
-     * @var array
121
-     */
122
-    private $localRelations = [];
123
-
124
-    /**
125
-     * List of local keys associated to local relation methods.
126
-     *
127
-     * @var array
128
-     */
129
-    private $localForeignKeys = [];
130
-
131
-    /**
132
-     * Relationships for which the key is stored in the Related Entity.
133
-     *
134
-     * @var array
135
-     */
136
-    private $foreignRelations = [];
137
-
138
-    /**
139
-     * Relationships which use a pivot record.
140
-     *
141
-     * @var array
142
-     */
143
-    private $pivotRelations = [];
144
-
145
-    /**
146
-     * Polymorphic relationships.
147
-     *
148
-     * @var array
149
-     */
150
-    private $polymorphicRelations = [];
151
-
152
-    /**
153
-     * Dynamic relationships.
154
-     *
155
-     * @var array
156
-     */
157
-    private $dynamicRelationships = [];
158
-
159
-    /**
160
-     * Targetted class for the relationship method. value is set to `null` for
161
-     * polymorphic relations.
162
-     *
163
-     * @var array
164
-     */
165
-    private $relatedClasses = [];
166
-
167
-    /**
168
-     * Some relation methods like embedded objects, or HasOne and MorphOne,
169
-     * will never have a proxy loaded on them.
170
-     *
171
-     * @var array
172
-     */
173
-    private $nonProxyRelationships = [];
174
-
175
-    /**
176
-     * Relation methods that are embedded objects.
177
-     *
178
-     * @var array
179
-     */
180
-    private $embeddedRelations = [];
181
-
182
-    /**
183
-     * The number of models to return for pagination.
184
-     *
185
-     * @var int
186
-     */
187
-    protected $perPage = 15;
188
-
189
-    /**
190
-     * The relations to eager load on every query.
191
-     *
192
-     * @var array
193
-     */
194
-    protected $with = [];
195
-
196
-    /**
197
-     * The class name to be used in polymorphic relations.
198
-     *
199
-     * @var string
200
-     */
201
-    protected $morphClass;
202
-
203
-    /**
204
-     * Sequence name, to be used with postgreSql
205
-     * defaults to %table_name%_id_seq.
206
-     *
207
-     * @var string|null
208
-     */
209
-    protected $sequence = null;
210
-
211
-    /**
212
-     * Indicates if the entity should be timestamped.
213
-     *
214
-     * @var bool
215
-     */
216
-    public $timestamps = false;
217
-
218
-    /**
219
-     * The name of the "created at" column.
220
-     *
221
-     * @var string
222
-     */
223
-    protected $createdAtColumn = 'created_at';
224
-
225
-    /**
226
-     * The name of the "updated at" column.
227
-     *
228
-     * @var string
229
-     */
230
-    protected $updatedAtColumn = 'updated_at';
231
-
232
-    /**
233
-     * Indicates if the entity uses softdeletes.
234
-     *
235
-     * @var bool
236
-     */
237
-    public $softDeletes = false;
238
-
239
-    /**
240
-     * The name of the "deleted at" column.
241
-     *
242
-     * @var string
243
-     */
244
-    protected $deletedAtColumn = 'deleted_at';
245
-
246
-    /**
247
-     * The date format to use with the current database connection.
248
-     *
249
-     * @var string
250
-     */
251
-    protected $dateFormat;
252
-
253
-    /**
254
-     * Set this property to true if the entity should be instantiated
255
-     * using the IoC Container.
256
-     *
257
-     * @var bool
258
-     */
259
-    protected $dependencyInjection = false;
260
-
261
-    /**
262
-     * Set the usage of inheritance, possible values are :
263
-     * "single_table"
264
-     * null.
265
-     *
266
-     * @var string | null
267
-     */
268
-    protected $inheritanceType = null;
269
-
270
-    /**
271
-     * Discriminator column name.
272
-     *
273
-     * @var string
274
-     */
275
-    protected $discriminatorColumn = 'type';
276
-
277
-    /**
278
-     * Allow using a string to define which entity type should be instantiated.
279
-     * If not set, analogue will uses entity's FQDN.
280
-     *
281
-     * @var array
282
-     */
283
-    protected $discriminatorColumnMap = [];
284
-
285
-    /**
286
-     * Return Domain class attributes, useful when mapping to a Plain PHP Object.
287
-     *
288
-     * @return array
289
-     */
290
-    public function getAttributes() : array
291
-    {
292
-        return $this->attributes;
293
-    }
294
-
295
-    /**
296
-     * Set the domain class attributes.
297
-     *
298
-     * @param array $attributeNames
299
-     */
300
-    public function setAttributes(array $attributeNames)
301
-    {
302
-        $this->attributes = $attributeNames;
303
-    }
304
-
305
-    /**
306
-     * Return true if the Entity has an 'attributes' array property.
307
-     *
308
-     * @return bool
309
-     */
310
-    public function usesAttributesArray() : bool
311
-    {
312
-        if ($this->arrayName === null) {
313
-            return false;
314
-        }
315
-        if ($this->attributes === null) {
316
-            return false;
317
-        }
318
-
319
-        return true;
320
-    }
321
-
322
-    /**
323
-     * Return the name of the Entity's attributes property.
324
-     *
325
-     * @return string|null
326
-     */
327
-    public function getAttributesArrayName()
328
-    {
329
-        return $this->arrayName;
330
-    }
331
-
332
-    /**
333
-     * Get all the attribute names for the class, including relationships, embeddables and primary key.
334
-     *
335
-     * @return array
336
-     */
337
-    public function getCompiledAttributes() : array
338
-    {
339
-        $key = $this->getKeyName();
340
-
341
-        $embeddables = array_keys($this->getEmbeddables());
342
-
343
-        $relationships = $this->getRelationships();
344
-
345
-        $attributes = $this->getAttributes();
346
-
347
-        return array_merge([$key], $embeddables, $relationships, $attributes);
348
-    }
349
-
350
-    /**
351
-     * Set the date format to use with the current database connection.
352
-     *
353
-     * @param string $format
354
-     */
355
-    public function setDateFormat($format)
356
-    {
357
-        $this->dateFormat = $format;
358
-    }
359
-
360
-    /**
361
-     * Get the date format to use with the current database connection.
362
-     *
363
-     *  @return string
364
-     */
365
-    public function getDateFormat() : string
366
-    {
367
-        return $this->dateFormat;
368
-    }
369
-
370
-    /**
371
-     * Set the Driver for this mapping.
372
-     *
373
-     * @param string $driver
374
-     */
375
-    public function setDriver($driver)
376
-    {
377
-        $this->driver = $driver;
378
-    }
379
-
380
-    /**
381
-     * Get the Driver for this mapping.
382
-     *
383
-     * @return string
384
-     */
385
-    public function getDriver() : string
386
-    {
387
-        return $this->driver;
388
-    }
389
-
390
-    /**
391
-     * Set the db connection to use on the table.
392
-     *
393
-     * @param $connection
394
-     */
395
-    public function setConnection($connection)
396
-    {
397
-        $this->connection = $connection;
398
-    }
399
-
400
-    /**
401
-     * Get the Database connection the Entity is stored on.
402
-     *
403
-     * @return string | null
404
-     */
405
-    public function getConnection()
406
-    {
407
-        return $this->connection;
408
-    }
409
-
410
-    /**
411
-     * Get the table associated with the entity.
412
-     *
413
-     * @return string
414
-     */
415
-    public function getTable() : string
416
-    {
417
-        if (!is_null($this->table)) {
418
-            return $this->table;
419
-        }
420
-
421
-        return str_replace('\\', '', snake_case(str_plural(class_basename($this->getClass()))));
422
-    }
423
-
424
-    /**
425
-     * Set the database table name.
426
-     *
427
-     * @param string $table
428
-     */
429
-    public function setTable($table)
430
-    {
431
-        $this->table = $table;
432
-    }
433
-
434
-    /**
435
-     * Get the pgSql sequence name.
436
-     *
437
-     * @return string
438
-     */
439
-    public function getSequence()
440
-    {
441
-        if (!is_null($this->sequence)) {
442
-            return $this->sequence;
443
-        } else {
444
-            return $this->getTable().'_id_seq';
445
-        }
446
-    }
447
-
448
-    /**
449
-     * Get the custom entity class.
450
-     *
451
-     * @return string namespaced class name
452
-     */
453
-    public function getClass() : string
454
-    {
455
-        return isset($this->class) ? $this->class : null;
456
-    }
457
-
458
-    /**
459
-     * Set the custom entity class.
460
-     *
461
-     * @param string $class namespaced class name
462
-     */
463
-    public function setClass($class)
464
-    {
465
-        $this->class = $class;
466
-    }
467
-
468
-    /**
469
-     * Get the embedded Value Objects.
470
-     *
471
-     * @return array
472
-     */
473
-    public function getEmbeddables() : array
474
-    {
475
-        return $this->embeddables;
476
-    }
477
-
478
-    /**
479
-     * Return attributes that should be mapped to class properties.
480
-     *
481
-     * @return array
482
-     */
483
-    public function getProperties() : array
484
-    {
485
-        return $this->properties;
486
-    }
487
-
488
-    /**
489
-     * Return the array property in which will be mapped all attributes
490
-     * that are not mapped to class properties.
491
-     *
492
-     * @return string
493
-     */
494
-    public function getAttributesPropertyName() : string
495
-    {
496
-    }
497
-
498
-    /**
499
-     * Set the embedded Value Objects.
500
-     *
501
-     * @param array $embeddables
502
-     */
503
-    public function setEmbeddables(array $embeddables)
504
-    {
505
-        $this->embeddables = $embeddables;
506
-    }
507
-
508
-    /**
509
-     * Get the relationships to map on a custom domain
510
-     * class.
511
-     *
512
-     * @return array
513
-     */
514
-    public function getRelationships() : array
515
-    {
516
-        return $this->relationships;
517
-    }
518
-
519
-    /**
520
-     * Return all relationships that are not embedded objects.
521
-     *
522
-     * @return array
523
-     */
524
-    public function getNonEmbeddedRelationships() : array
525
-    {
526
-        return array_diff($this->relationships, $this->embeddedRelations);
527
-    }
528
-
529
-    /**
530
-     * Get the relationships that will not have a proxy
531
-     * set on them.
532
-     *
533
-     * @return array
534
-     */
535
-    public function getRelationshipsWithoutProxy() : array
536
-    {
537
-        return $this->nonProxyRelationships;
538
-    }
539
-
540
-    /**
541
-     * Relationships of the Entity type.
542
-     *
543
-     * @return array
544
-     */
545
-    public function getSingleRelationships() : array
546
-    {
547
-        return $this->singleRelations;
548
-    }
549
-
550
-    /**
551
-     * Relationships of type Collection.
552
-     *
553
-     * @return array
554
-     */
555
-    public function getManyRelationships() : array
556
-    {
557
-        return $this->manyRelations;
558
-    }
559
-
560
-    /**
561
-     * Relationships with foreign key in the mapped entity record.
562
-     *
563
-     * @return array
564
-     */
565
-    public function getLocalRelationships() : array
566
-    {
567
-        return $this->localRelations;
568
-    }
569
-
570
-    /**
571
-     * Return the local keys associated to the relationship.
572
-     *
573
-     * @param string $relation
574
-     *
575
-     * @return string | array | null
576
-     */
577
-    public function getLocalKeys($relation)
578
-    {
579
-        return isset($this->localForeignKeys[$relation]) ? $this->localForeignKeys[$relation] : null;
580
-    }
581
-
582
-    /**
583
-     * Relationships with foreign key in the related Entity record.
584
-     *
585
-     * @return array
586
-     */
587
-    public function getForeignRelationships() : array
588
-    {
589
-        return $this->foreignRelations;
590
-    }
591
-
592
-    /**
593
-     * Relationships which keys are stored in a pivot record.
594
-     *
595
-     * @return array
596
-     */
597
-    public function getPivotRelationships() : array
598
-    {
599
-        return $this->pivotRelations;
600
-    }
601
-
602
-    /**
603
-     * Return an array containing all embedded relationships.
604
-     *
605
-     * @return array
606
-     */
607
-    public function getEmbeddedRelationships() : array
608
-    {
609
-        return $this->embeddedRelations;
610
-    }
611
-
612
-    /**
613
-     * Return true if the relationship method is polymorphic.
614
-     *
615
-     * @param string $relation
616
-     *
617
-     * @return bool
618
-     */
619
-    public function isPolymorphic($relation) : bool
620
-    {
621
-        return in_array($relation, $this->polymorphicRelations);
622
-    }
623
-
624
-    /**
625
-     * Get the targetted type for a relationship. Return null if polymorphic.
626
-     *
627
-     * @param string $relation
628
-     *
629
-     * @return string | null
630
-     */
631
-    public function getTargettedClass($relation)
632
-    {
633
-        if (!array_key_exists($relation, $this->relatedClasses)) {
634
-            return;
635
-        }
636
-
637
-        return $this->relatedClasses[$relation];
638
-    }
639
-
640
-    /**
641
-     * Add a Dynamic Relationship method at runtime. This has to be done
642
-     * by hooking the 'initializing' event, before entityMap is initialized.
643
-     *
644
-     * @param string   $name         Relation name
645
-     * @param \Closure $relationship
646
-     *
647
-     * @return void
648
-     */
649
-    public function addRelationshipMethod($name, \Closure $relationship)
650
-    {
651
-        $this->dynamicRelationships[$name] = $relationship;
652
-    }
653
-
654
-    /**
655
-     * Get the dynamic relationship method names.
656
-     *
657
-     * @return array
658
-     */
659
-    public function getDynamicRelationships() : array
660
-    {
661
-        return array_keys($this->dynamicRelationships);
662
-    }
663
-
664
-    /**
665
-     * Get the relationships that have to be eager loaded
666
-     * on each request.
667
-     *
668
-     * @return array
669
-     */
670
-    public function getEagerloadedRelationships() : array
671
-    {
672
-        return $this->with;
673
-    }
674
-
675
-    /**
676
-     * Get the primary key attribute for the entity.
677
-     *
678
-     * @return string
679
-     */
680
-    public function getKeyName() : string
681
-    {
682
-        return $this->primaryKey;
683
-    }
684
-
685
-    /**
686
-     * Set the primary key for the entity.
687
-     *
688
-     * @param $key
689
-     *
690
-     * @return void
691
-     */
692
-    public function setKeyName($key)
693
-    {
694
-        $this->primaryKey = $key;
695
-    }
696
-
697
-    /**
698
-     * Get the table qualified key name.
699
-     *
700
-     * @return string
701
-     */
702
-    public function getQualifiedKeyName() : string
703
-    {
704
-        return $this->getTable().'.'.$this->getKeyName();
705
-    }
706
-
707
-    /**
708
-     * Get the number of models to return per page.
709
-     *
710
-     * @return int
711
-     */
712
-    public function getPerPage() : int
713
-    {
714
-        return $this->perPage;
715
-    }
716
-
717
-    /**
718
-     * Set the number of models to return per page.
719
-     *
720
-     * @param int $perPage
721
-     *
722
-     * @return void
723
-     */
724
-    public function setPerPage($perPage)
725
-    {
726
-        $this->perPage = $perPage;
727
-    }
728
-
729
-    /**
730
-     * Determine if the entity uses get.
731
-     *
732
-     * @return bool
733
-     */
734
-    public function usesTimestamps() : bool
735
-    {
736
-        return $this->timestamps;
737
-    }
738
-
739
-    /**
740
-     * Determine if the entity uses soft deletes.
741
-     *
742
-     * @return bool
743
-     */
744
-    public function usesSoftDeletes() : bool
745
-    {
746
-        return $this->softDeletes;
747
-    }
748
-
749
-    /**
750
-     * Get the 'created_at' column name.
751
-     *
752
-     * @return string
753
-     */
754
-    public function getCreatedAtColumn() : string
755
-    {
756
-        return $this->createdAtColumn;
757
-    }
758
-
759
-    /**
760
-     * Get the 'updated_at' column name.
761
-     *
762
-     * @return string
763
-     */
764
-    public function getUpdatedAtColumn() : string
765
-    {
766
-        return $this->updatedAtColumn;
767
-    }
768
-
769
-    /**
770
-     * Get the deleted_at column.
771
-     *
772
-     * @return string
773
-     */
774
-    public function getQualifiedDeletedAtColumn() : string
775
-    {
776
-        return $this->deletedAtColumn;
777
-    }
778
-
779
-    /**
780
-     * Get the default foreign key name for the model.
781
-     *
782
-     * @return string
783
-     */
784
-    public function getForeignKey() : string
785
-    {
786
-        return snake_case(class_basename($this->getClass())).'_id';
787
-    }
788
-
789
-    /**
790
-     * Return the inheritance type used by the entity.
791
-     *
792
-     * @return string|null
793
-     */
794
-    public function getInheritanceType()
795
-    {
796
-        return $this->inheritanceType;
797
-    }
798
-
799
-    /**
800
-     * Return the discriminator column name on the entity that's
801
-     * used for table inheritance.
802
-     *
803
-     * @return string
804
-     */
805
-    public function getDiscriminatorColumn() : string
806
-    {
807
-        return $this->discriminatorColumn;
808
-    }
809
-
810
-    /**
811
-     * Return the mapping of discriminator column values to
812
-     * entity class names that are used for table inheritance.
813
-     *
814
-     * @return array
815
-     */
816
-    public function getDiscriminatorColumnMap() : array
817
-    {
818
-        return $this->discriminatorColumnMap;
819
-    }
820
-
821
-    /**
822
-     * Return true if the entity should be instanciated using
823
-     * the IoC Container.
824
-     *
825
-     * @return bool
826
-     */
827
-    public function useDependencyInjection() : bool
828
-    {
829
-        return $this->dependencyInjection;
830
-    }
831
-
832
-    /**
833
-     * Add a single relation method name once.
834
-     *
835
-     * @param string $relation
836
-     */
837
-    protected function addSingleRelation($relation)
838
-    {
839
-        if (!in_array($relation, $this->singleRelations)) {
840
-            $this->singleRelations[] = $relation;
841
-        }
842
-    }
843
-
844
-    /**
845
-     * Add a foreign relation method name once.
846
-     *
847
-     * @param string $relation
848
-     */
849
-    protected function addForeignRelation($relation)
850
-    {
851
-        if (!in_array($relation, $this->foreignRelations)) {
852
-            $this->foreignRelations[] = $relation;
853
-        }
854
-    }
855
-
856
-    /**
857
-     * Add a polymorphic relation method name once.
858
-     *
859
-     * @param string $relation
860
-     */
861
-    protected function addPolymorphicRelation($relation)
862
-    {
863
-        if (!in_array($relation, $this->polymorphicRelations)) {
864
-            $this->polymorphicRelations[] = $relation;
865
-        }
866
-    }
867
-
868
-    /**
869
-     * Add a non proxy relation method name once.
870
-     *
871
-     * @param string $relation
872
-     */
873
-    protected function addNonProxyRelation($relation)
874
-    {
875
-        if (!in_array($relation, $this->nonProxyRelationships)) {
876
-            $this->nonProxyRelationships[] = $relation;
877
-        }
878
-    }
879
-
880
-    /**
881
-     * Add a local relation method name once.
882
-     *
883
-     * @param string $relation
884
-     */
885
-    protected function addLocalRelation($relation)
886
-    {
887
-        if (!in_array($relation, $this->localRelations)) {
888
-            $this->localRelations[] = $relation;
889
-        }
890
-    }
891
-
892
-    /**
893
-     * Add a many relation method name once.
894
-     *
895
-     * @param string $relation
896
-     */
897
-    protected function addManyRelation($relation)
898
-    {
899
-        if (!in_array($relation, $this->manyRelations)) {
900
-            $this->manyRelations[] = $relation;
901
-        }
902
-    }
903
-
904
-    /**
905
-     * Add a pivot relation method name once.
906
-     *
907
-     * @param string $relation
908
-     */
909
-    protected function addPivotRelation($relation)
910
-    {
911
-        if (!in_array($relation, $this->pivotRelations)) {
912
-            $this->pivotRelations[] = $relation;
913
-        }
914
-    }
915
-
916
-    /**
917
-     * Add an embedded relation.
918
-     *
919
-     * @param string $relation
920
-     */
921
-    protected function addEmbeddedRelation($relation)
922
-    {
923
-        if (!in_array($relation, $this->embeddedRelations)) {
924
-            $this->embeddedRelations[] = $relation;
925
-        }
926
-    }
927
-
928
-    /**
929
-     * Define an Embedded Object.
930
-     *
931
-     * @param mixed  $entity
932
-     * @param string $related
933
-     *
934
-     * @return EmbedsOne
935
-     */
936
-    public function embedsOne($parent, string $relatedClass, $relation = null) : EmbedsOne
937
-    {
938
-        if(is_null($relation)) {
939
-            list(, $caller) = debug_backtrace(false);
940
-            $relation = $caller['function'];
941
-        }
942
-
943
-        $this->addEmbeddedRelation($relation);
944
-        $this->addNonProxyRelation($relation);
945
-
946
-        return new EmbedsOne($parent, $relatedClass, $relation);
947
-    }
948
-
949
-    /**
950
-     * Define an Embedded Collection.
951
-     *
952
-     * @param mixed  $entity
953
-     * @param string $related
954
-     *
955
-     * @return EmbedsOne
956
-     */
957
-    public function embedsMany($parent, string $relatedClass, $relation = null) : EmbedsMany
958
-    {
959
-        if(is_null($relation)) {
960
-            list(, $caller) = debug_backtrace(false);
961
-            $relation = $caller['function'];
962
-        }
963
-
964
-        $this->addEmbeddedRelation($relation);
965
-        $this->addNonProxyRelation($relation);
966
-
967
-        return new EmbedsMany($parent, $relatedClass, $relation);
968
-    }
969
-
970
-    /**
971
-     * Define a one-to-one relationship.
972
-     *
973
-     * @param mixed  $entity
974
-     * @param string $related    entity class
975
-     * @param string $foreignKey
976
-     * @param string $localKey
977
-     *
978
-     * @throws MappingException
979
-     *
980
-     * @return \Analogue\ORM\Relationships\HasOne
981
-     */
982
-    public function hasOne($entity, $related, $foreignKey = null, $localKey = null)
983
-    {
984
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
985
-
986
-        $relatedMapper = Manager::getInstance()->mapper($related);
987
-
988
-        $relatedMap = $relatedMapper->getEntityMap();
989
-
990
-        $localKey = $localKey ?: $this->getKeyName();
991
-
992
-        // Add the relation to the definition in map
993
-        list(, $caller) = debug_backtrace(false);
994
-        $relation = $caller['function'];
995
-        $this->relatedClasses[$relation] = $related;
996
-
997
-        $this->addSingleRelation($relation);
998
-        $this->addForeignRelation($relation);
999
-        $this->addNonProxyRelation($relation);
1000
-
1001
-        // This relationship will always be eager loaded, as proxying it would
1002
-        // mean having an object that doesn't actually exists.
1003
-        if (!in_array($relation, $this->with)) {
1004
-            $this->with[] = $relation;
1005
-        }
1006
-
1007
-        return new HasOne($relatedMapper, $entity, /*$relatedMap->getTable().'.'*/$foreignKey, $localKey);
1008
-    }
1009
-
1010
-    /**
1011
-     * Define a polymorphic one-to-one relationship.
1012
-     *
1013
-     * @param mixed       $entity
1014
-     * @param string      $related
1015
-     * @param string      $name
1016
-     * @param string|null $type
1017
-     * @param string|null $id
1018
-     * @param string|null $localKey
1019
-     *
1020
-     * @throws MappingException
1021
-     *
1022
-     * @return \Analogue\ORM\Relationships\MorphOne
1023
-     */
1024
-    public function morphOne($entity, $related, $name, $type = null, $id = null, $localKey = null)
1025
-    {
1026
-        list($type, $id) = $this->getMorphs($name, $type, $id);
1027
-
1028
-        $localKey = $localKey ?: $this->getKeyName();
1029
-
1030
-        $relatedMapper = Manager::getInstance()->mapper($related);
1031
-
1032
-        //$table = $relatedMapper->getEntityMap()->getTable();
1033
-
1034
-        // Add the relation to the definition in map
1035
-        list(, $caller) = debug_backtrace(false);
1036
-        $relation = $caller['function'];
1037
-        $this->relatedClasses[$relation] = $related;
1038
-
1039
-        $this->addSingleRelation($relation);
1040
-        $this->addForeignRelation($relation);
1041
-        $this->addNonProxyRelation($relation);
1042
-
1043
-        // This relationship will always be eager loaded, as proxying it would
1044
-        // mean having an object that doesn't actually exists.
1045
-        if (!in_array($relation, $this->with)) {
1046
-            $this->with[] = $relation;
1047
-        }
1048
-
1049
-        return new MorphOne($relatedMapper, $entity, /*$table.'.'.*/$type, /*$table.'.'.*/$id, $localKey);
1050
-    }
1051
-
1052
-    /**
1053
-     * Define an inverse one-to-one or many relationship.
1054
-     *
1055
-     * @param mixed       $entity
1056
-     * @param string      $related
1057
-     * @param string|null $foreignKey
1058
-     * @param string|null $otherKey
1059
-     * @param string|null $relation
1060
-     *
1061
-     * @throws MappingException
1062
-     *
1063
-     * @return \Analogue\ORM\Relationships\BelongsTo
1064
-     */
1065
-    public function belongsTo($entity, $related, $foreignKey = null, $otherKey = null)
1066
-    {
1067
-        // Add the relation to the definition in map
1068
-        list(, $caller) = debug_backtrace(false);
1069
-        $relation = $caller['function'];
1070
-        $this->relatedClasses[$relation] = $related;
1071
-
1072
-        $this->addSingleRelation($relation);
1073
-        $this->addLocalRelation($relation);
1074
-
1075
-        // If no foreign key was supplied, we can use a backtrace to guess the proper
1076
-        // foreign key name by using the name of the relationship function, which
1077
-        // when combined with an "_id" should conventionally match the columns.
1078
-        if (is_null($foreignKey)) {
1079
-            $foreignKey = snake_case($relation).'_id';
1080
-        }
1081
-
1082
-        $this->localForeignKeys[$relation] = $foreignKey;
1083
-
1084
-        $relatedMapper = Manager::getInstance()->mapper($related);
1085
-
1086
-        $otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getKeyName();
1087
-
1088
-        return new BelongsTo($relatedMapper, $entity, $foreignKey, $otherKey, $relation);
1089
-    }
1090
-
1091
-    /**
1092
-     * Define a polymorphic, inverse one-to-one or many relationship.
1093
-     *
1094
-     * @param mixed       $entity
1095
-     * @param string|null $name
1096
-     * @param string|null $type
1097
-     * @param string|null $id
1098
-     *
1099
-     * @throws MappingException
1100
-     *
1101
-     * @return \Analogue\ORM\Relationships\MorphTo
1102
-     */
1103
-    public function morphTo($entity, $name = null, $type = null, $id = null)
1104
-    {
1105
-        // If no name is provided, we will use the backtrace to get the function name
1106
-        // since that is most likely the name of the polymorphic interface. We can
1107
-        // use that to get both the class and foreign key that will be utilized.
1108
-        if (is_null($name)) {
1109
-            list(, $caller) = debug_backtrace(false);
1110
-
1111
-            $name = snake_case($caller['function']);
1112
-        }
1113
-        $this->addSingleRelation($name);
1114
-        $this->addLocalRelation($name);
1115
-        $this->addPolymorphicRelation($name);
1116
-
1117
-        $this->relatedClass[$name] = null;
1118
-
1119
-        list($type, $id) = $this->getMorphs($name, $type, $id);
1120
-
1121
-        // Store the foreign key in the entity map.
1122
-        // We might want to store the (key, type) as we might need it
1123
-        // to build a MorphTo proxy
1124
-        $this->localForeignKeys[$name] = [
1125
-            'id'   => $id,
1126
-            'type' => $type,
1127
-        ];
1128
-
1129
-        $mapper = Manager::getInstance()->mapper(get_class($entity));
1130
-
1131
-        // If the type value is null it is probably safe to assume we're eager loading
1132
-        // the relationship. When that is the case we will pass in a dummy query as
1133
-        // there are multiple types in the morph and we can't use single queries.
1134
-        $factory = new Factory();
1135
-        $wrapper = $factory->make($entity);
1136
-
1137
-        if (is_null($class = $wrapper->getEntityAttribute($type))) {
1138
-            return new MorphTo(
1139
-                $mapper, $entity, $id, null, $type, $name
1140
-            );
1141
-        }
1142
-
1143
-        // If we are not eager loading the relationship we will essentially treat this
1144
-        // as a belongs-to style relationship since morph-to extends that class and
1145
-        // we will pass in the appropriate values so that it behaves as expected.
1146
-        else {
1147
-            $class = Manager::getInstance()->getInverseMorphMap($class);
1148
-            $relatedMapper = Manager::getInstance()->mapper($class);
1149
-
1150
-            $foreignKey = $relatedMapper->getEntityMap()->getKeyName();
1151
-
1152
-            return new MorphTo(
1153
-                $relatedMapper, $entity, $id, $foreignKey, $type, $name
1154
-            );
1155
-        }
1156
-    }
1157
-
1158
-    /**
1159
-     * Define a one-to-many relationship.
1160
-     *
1161
-     * @param mixed       $entity
1162
-     * @param string      $related
1163
-     * @param string|null $foreignKey
1164
-     * @param string|null $localKey
1165
-     *
1166
-     * @throws MappingException
1167
-     *
1168
-     * @return \Analogue\ORM\Relationships\HasMany
1169
-     */
1170
-    public function hasMany($entity, $related, $foreignKey = null, $localKey = null)
1171
-    {
1172
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
1173
-
1174
-        $relatedMapper = Manager::getInstance()->mapper($related);
1175
-
1176
-        $localKey = $localKey ?: $this->getKeyName();
1177
-
1178
-        // Add the relation to the definition in map
1179
-        list(, $caller) = debug_backtrace(false);
1180
-        $relation = $caller['function'];
1181
-        $this->relatedClasses[$relation] = $related;
1182
-
1183
-        $this->addManyRelation($relation);
1184
-        $this->addForeignRelation($relation);
1185
-
1186
-        return new HasMany($relatedMapper, $entity, $foreignKey, $localKey);
1187
-    }
1188
-
1189
-    /**
1190
-     * Define a has-many-through relationship.
1191
-     *
1192
-     * @param mixed       $entity
1193
-     * @param string      $related
1194
-     * @param string      $through
1195
-     * @param string|null $firstKey
1196
-     * @param string|null $secondKey
1197
-     *
1198
-     * @throws MappingException
1199
-     *
1200
-     * @return \Analogue\ORM\Relationships\HasManyThrough
1201
-     */
1202
-    public function hasManyThrough($entity, $related, $through, $firstKey = null, $secondKey = null)
1203
-    {
1204
-        $relatedMapper = Manager::getInstance()->mapper($related);
1205
-        $throughMapper = Manager::getInstance()->mapper($through);
1206
-
1207
-        $firstKey = $firstKey ?: $this->getForeignKey();
1208
-
1209
-        $throughMap = $throughMapper->getEntityMap();
1210
-
1211
-        $secondKey = $secondKey ?: $throughMap->getForeignKey();
1212
-
1213
-        // Add the relation to the definition in map
1214
-        list(, $caller) = debug_backtrace(false);
1215
-        $relation = $caller['function'];
1216
-        $this->relatedClasses[$relation] = $related;
1217
-
1218
-        $this->addManyRelation($relation);
1219
-        $this->addForeignRelation($relation);
1220
-
1221
-        return new HasManyThrough($relatedMapper, $entity, $throughMap, $firstKey, $secondKey);
1222
-    }
1223
-
1224
-    /**
1225
-     * Define a polymorphic one-to-many relationship.
1226
-     *
1227
-     * @param mixed       $entity
1228
-     * @param string      $related
1229
-     * @param string      $name
1230
-     * @param string|null $type
1231
-     * @param string|null $id
1232
-     * @param string|null $localKey
1233
-     *
1234
-     * @return \Analogue\ORM\Relationships\MorphMany
1235
-     */
1236
-    public function morphMany($entity, $related, $name, $type = null, $id = null, $localKey = null)
1237
-    {
1238
-        // Here we will gather up the morph type and ID for the relationship so that we
1239
-        // can properly query the intermediate table of a relation. Finally, we will
1240
-        // get the table and create the relationship instances for the developers.
1241
-        list($type, $id) = $this->getMorphs($name, $type, $id);
1242
-
1243
-        $relatedMapper = Manager::getInstance()->mapper($related);
1244
-
1245
-        $table = $relatedMapper->getEntityMap()->getTable();
1246
-
1247
-        $localKey = $localKey ?: $this->getKeyName();
1248
-
1249
-        // Add the relation to the definition in map
1250
-        list(, $caller) = debug_backtrace(false);
1251
-        $relation = $caller['function'];
1252
-        $this->relatedClasses[$relation] = $related;
1253
-
1254
-        $this->addManyRelation($relation);
1255
-        $this->addForeignRelation($relation);
1256
-
1257
-        return new MorphMany($relatedMapper, $entity, /*$table.'.'.*/$type, /*$table.'.'.*/$id, $localKey);
1258
-    }
1259
-
1260
-    /**
1261
-     * Define a many-to-many relationship.
1262
-     *
1263
-     * @param mixed       $entity
1264
-     * @param string      $relatedClass
1265
-     * @param string|null $table
1266
-     * @param string|null $foreignKey
1267
-     * @param string|null $otherKey
1268
-     * @param string|null $relation
1269
-     *
1270
-     * @throws MappingException
1271
-     *
1272
-     * @return \Analogue\ORM\Relationships\BelongsToMany
1273
-     */
1274
-    public function belongsToMany($entity, $related, $table = null, $foreignKey = null, $otherKey = null)
1275
-    {
1276
-        // Add the relation to the definition in map
1277
-        list(, $caller) = debug_backtrace(false);
1278
-        $relation = $caller['function'];
1279
-        $this->relatedClasses[$relation] = $related;
1280
-
1281
-        $this->addManyRelation($relation);
1282
-        $this->addForeignRelation($relation);
1283
-        $this->addPivotRelation($relation);
1284
-
1285
-        // First, we'll need to determine the foreign key and "other key" for the
1286
-        // relationship. Once we have determined the keys we'll make the query
1287
-        // instances as well as the relationship instances we need for this.
1288
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
1289
-
1290
-        $relatedMapper = Manager::getInstance()->mapper($related);
1291
-
1292
-        $relatedMap = $relatedMapper->getEntityMap();
1293
-
1294
-        $otherKey = $otherKey ?: $relatedMap->getForeignKey();
1295
-
1296
-        // If no table name was provided, we can guess it by concatenating the two
1297
-        // models using underscores in alphabetical order. The two model names
1298
-        // are transformed to snake case from their default CamelCase also.
1299
-        if (is_null($table)) {
1300
-            $table = $this->joiningTable($relatedMap);
1301
-        }
1302
-
1303
-        return new BelongsToMany($relatedMapper, $entity, $table, $foreignKey, $otherKey, $relation);
1304
-    }
1305
-
1306
-    /**
1307
-     * Define a polymorphic many-to-many relationship.
1308
-     *
1309
-     * @param mixed       $entity
1310
-     * @param string      $related
1311
-     * @param string      $name
1312
-     * @param string|null $table
1313
-     * @param string|null $foreignKey
1314
-     * @param string|null $otherKey
1315
-     * @param bool        $inverse
1316
-     *
1317
-     * @throws MappingException
1318
-     *
1319
-     * @return \Analogue\ORM\Relationships\MorphToMany
1320
-     */
1321
-    public function morphToMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
1322
-    {
1323
-        // Add the relation to the definition in map
1324
-        list(, $caller) = debug_backtrace(false);
1325
-        $relation = $caller['function'];
1326
-        $this->relatedClasses[$relation] = $related;
1327
-
1328
-        $this->addManyRelation($relation);
1329
-        $this->addForeignRelation($relation);
1330
-        $this->addPivotRelation($relation);
1331
-
1332
-        // First, we will need to determine the foreign key and "other key" for the
1333
-        // relationship. Once we have determined the keys we will make the query
1334
-        // instances, as well as the relationship instances we need for these.
1335
-        $foreignKey = $foreignKey ?: $name.'_id';
1336
-
1337
-        $relatedMapper = Manager::getInstance()->mapper($related);
1338
-
1339
-        $otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getForeignKey();
1340
-
1341
-        $table = $table ?: str_plural($name);
1342
-
1343
-        return new MorphToMany($relatedMapper, $entity, $name, $table, $foreignKey, $otherKey, $caller, $inverse);
1344
-    }
1345
-
1346
-    /**
1347
-     * Define a polymorphic, inverse many-to-many relationship.
1348
-     *
1349
-     * @param mixed       $entity
1350
-     * @param string      $related
1351
-     * @param string      $name
1352
-     * @param string|null $table
1353
-     * @param string|null $foreignKey
1354
-     * @param string|null $otherKey
1355
-     *
1356
-     * @throws MappingException
1357
-     *
1358
-     * @return \Analogue\ORM\Relationships\MorphToMany
1359
-     */
1360
-    public function morphedByMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null)
1361
-    {
1362
-        // Add the relation to the definition in map
1363
-        list(, $caller) = debug_backtrace(false);
1364
-        $relation = $caller['function'];
1365
-        $this->relatedClasses[$relation] = $related;
1366
-
1367
-        $this->addManyRelation($relation);
1368
-        $this->addForeignRelation($relation);
1369
-
1370
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
1371
-
1372
-        // For the inverse of the polymorphic many-to-many relations, we will change
1373
-        // the way we determine the foreign and other keys, as it is the opposite
1374
-        // of the morph-to-many method since we're figuring out these inverses.
1375
-        $otherKey = $otherKey ?: $name.'_id';
1376
-
1377
-        return $this->morphToMany($entity, $related, $name, $table, $foreignKey, $otherKey, true);
1378
-    }
1379
-
1380
-    /**
1381
-     * Get the joining table name for a many-to-many relation.
1382
-     *
1383
-     * @param EntityMap $relatedMap
1384
-     *
1385
-     * @return string
1386
-     */
1387
-    public function joiningTable($relatedMap)
1388
-    {
1389
-        // The joining table name, by convention, is simply the snake cased models
1390
-        // sorted alphabetically and concatenated with an underscore, so we can
1391
-        // just sort the models and join them together to get the table name.
1392
-        $base = $this->getTable();
1393
-
1394
-        $related = $relatedMap->getTable();
1395
-
1396
-        $tables = [$related, $base];
1397
-
1398
-        // Now that we have the model names in an array we can just sort them and
1399
-        // use the implode function to join them together with an underscores,
1400
-        // which is typically used by convention within the database system.
1401
-        sort($tables);
1402
-
1403
-        return strtolower(implode('_', $tables));
1404
-    }
1405
-
1406
-    /**
1407
-     * Get the polymorphic relationship columns.
1408
-     *
1409
-     * @param string $name
1410
-     * @param string $type
1411
-     * @param string $id
1412
-     *
1413
-     * @return string[]
1414
-     */
1415
-    protected function getMorphs($name, $type, $id)
1416
-    {
1417
-        $type = $type ?: $name.'_type';
1418
-
1419
-        $id = $id ?: $name.'_id';
1420
-
1421
-        return [$type, $id];
1422
-    }
1423
-
1424
-    /**
1425
-     * Get the class name for polymorphic relations.
1426
-     *
1427
-     * @return string
1428
-     */
1429
-    public function getMorphClass()
1430
-    {
1431
-        $morphClass = Manager::getInstance()->getMorphMap($this->getClass());
1432
-
1433
-        return $this->morphClass ?: $morphClass;
1434
-    }
1435
-
1436
-    /**
1437
-     * Create a new Entity Collection instance.
1438
-     *
1439
-     * @param array $entities
1440
-     *
1441
-     * @return \Analogue\ORM\EntityCollection
1442
-     */
1443
-    public function newCollection(array $entities = [])
1444
-    {
1445
-        $collection = new EntityCollection($entities, $this);
1446
-
1447
-        return $collection->keyBy($this->getKeyName());
1448
-    }
1449
-
1450
-    /**
1451
-     * Process EntityMap parsing at initialization time.
1452
-     *
1453
-     * @return void
1454
-     */
1455
-    public function initialize()
1456
-    {
1457
-        $userMethods = $this->getCustomMethods();
1458
-
1459
-        // Parse EntityMap for method based relationship
1460
-        if (count($userMethods) > 0) {
1461
-            $this->relationships = $this->parseMethodsForRelationship($userMethods);
1462
-        }
1463
-
1464
-        // Parse EntityMap for dynamic relationships
1465
-        if (count($this->dynamicRelationships) > 0) {
1466
-            $this->relationships = $this->relationships + $this->getDynamicRelationships();
1467
-        }
1468
-    }
1469
-
1470
-    /**
1471
-     * Parse every relationships on the EntityMap and sort
1472
-     * them by type.
1473
-     *
1474
-     * @return void
1475
-     */
1476
-    public function boot()
1477
-    {
1478
-        if (count($this->relationships > 0)) {
1479
-            $this->sortRelationshipsByType();
1480
-        }
1481
-    }
1482
-
1483
-    /**
1484
-     * Get Methods that has been added in the child class.
1485
-     *
1486
-     * @return array
1487
-     */
1488
-    protected function getCustomMethods()
1489
-    {
1490
-        $mapMethods = get_class_methods($this);
1491
-
1492
-        $parentsMethods = get_class_methods('Analogue\ORM\EntityMap');
1493
-
1494
-        return array_diff($mapMethods, $parentsMethods);
1495
-    }
1496
-
1497
-    /**
1498
-     * Parse user's class methods for relationships.
1499
-     *
1500
-     * @param array $customMethods
1501
-     *
1502
-     * @return array
1503
-     */
1504
-    protected function parseMethodsForRelationship(array $customMethods)
1505
-    {
1506
-        $relationships = [];
1507
-
1508
-        $class = new ReflectionClass(get_class($this));
1509
-
1510
-        // Get the mapped Entity class, as we will detect relationships
1511
-        // methods by testing that the first argument is type-hinted to
1512
-        // the same class as the mapped Entity.
1513
-        $entityClass = $this->getClass();
1514
-
1515
-        foreach ($customMethods as $methodName) {
1516
-            $method = $class->getMethod($methodName);
1517
-
1518
-            if ($method->getNumberOfParameters() > 0) {
1519
-                $params = $method->getParameters();
1520
-
1521
-                if ($params[0]->getClass() && ($params[0]->getClass()->name == $entityClass || is_subclass_of($entityClass, $params[0]->getClass()->name))) {
1522
-                    $relationships[] = $methodName;
1523
-                }
1524
-            }
1525
-        }
1526
-
1527
-        return $relationships;
1528
-    }
1529
-
1530
-    /**
1531
-     * Sort Relationships methods by type.
1532
-     *
1533
-     * TODO : replace this by direclty setting these value
1534
-     * in the corresponding methods, so we won't need
1535
-     * the correpondancy tabble
1536
-     *
1537
-     * @return void
1538
-     */
1539
-    protected function sortRelationshipsByType()
1540
-    {
1541
-        $entityClass = $this->getClass();
1542
-
1543
-        // Instantiate a dummy entity which we will pass to relationship methods.
1544
-        $entity = unserialize(sprintf('O:%d:"%s":0:{}', strlen($entityClass), $entityClass));
1545
-
1546
-        foreach ($this->relationships as $relation) {
1547
-            $this->$relation($entity);
1548
-        }
1549
-    }
1550
-
1551
-    /**
1552
-     * Override this method for custom entity instantiation.
1553
-     *
1554
-     * @return null
1555
-     */
1556
-    public function activator()
1557
-    {
1558
-    }
1559
-
1560
-    /**
1561
-     * Magic call to dynamic relationships.
1562
-     *
1563
-     * @param string $method
1564
-     * @param array  $parameters
1565
-     *
1566
-     * @throws Exception
1567
-     *
1568
-     * @return mixed
1569
-     */
1570
-    public function __call($method, $parameters)
1571
-    {
1572
-        if (!array_key_exists($method, $this->dynamicRelationships)) {
1573
-            throw new Exception(get_class($this)." has no method $method");
1574
-        }
1575
-
1576
-        // Add $this to parameters so the closure can call relationship method on the map.
1577
-        $parameters[] = $this;
1578
-
1579
-        return  call_user_func_array([$this->dynamicRelationships[$method], $parameters]);
1580
-    }
28
+	/**
29
+	 * The mapping driver to use with this entity.
30
+	 *
31
+	 * @var string
32
+	 */
33
+	protected $driver = 'illuminate';
34
+
35
+	/**
36
+	 * The Database Connection name for the model.
37
+	 *
38
+	 * @var string
39
+	 */
40
+	protected $connection;
41
+
42
+	/**
43
+	 * The table associated with the entity.
44
+	 *
45
+	 * @var string|null
46
+	 */
47
+	protected $table = null;
48
+
49
+	/**
50
+	 * The primary key for the model.
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $primaryKey = 'id';
55
+
56
+	/**
57
+	 * Name of the entity's array property that should
58
+	 * contain the attributes.
59
+	 * If set to null, analogue will only hydrate object's properties.
60
+	 *
61
+	 * @var string|null
62
+	 */
63
+	protected $arrayName = 'attributes';
64
+
65
+	/**
66
+	 * Array containing the list of database columns to be mapped
67
+	 * in the attributes array of the entity.
68
+	 *
69
+	 * @var array
70
+	 */
71
+	protected $attributes = [];
72
+
73
+	/**
74
+	 * Array containing the list of database columns to be mapped
75
+	 * to the entity's class properties.
76
+	 *
77
+	 * @var array
78
+	 */
79
+	protected $properties = [];
80
+
81
+	/**
82
+	 * The Custom Domain Class to use with this mapping.
83
+	 *
84
+	 * @var string|null
85
+	 */
86
+	protected $class = null;
87
+
88
+	/**
89
+	 * Embedded Value Objects.
90
+	 *
91
+	 * @var array
92
+	 */
93
+	protected $embeddables = [];
94
+
95
+	/**
96
+	 * Determine the relationships method used on the entity.
97
+	 * If not set, mapper will autodetect them.
98
+	 *
99
+	 * @var array
100
+	 */
101
+	private $relationships = [];
102
+
103
+	/**
104
+	 * Relationships that should be treated as collection.
105
+	 *
106
+	 * @var array
107
+	 */
108
+	private $manyRelations = [];
109
+
110
+	/**
111
+	 * Relationships that should be treated as single entity.
112
+	 *
113
+	 * @var array
114
+	 */
115
+	private $singleRelations = [];
116
+
117
+	/**
118
+	 * Relationships for which the key is stored in the Entity itself.
119
+	 *
120
+	 * @var array
121
+	 */
122
+	private $localRelations = [];
123
+
124
+	/**
125
+	 * List of local keys associated to local relation methods.
126
+	 *
127
+	 * @var array
128
+	 */
129
+	private $localForeignKeys = [];
130
+
131
+	/**
132
+	 * Relationships for which the key is stored in the Related Entity.
133
+	 *
134
+	 * @var array
135
+	 */
136
+	private $foreignRelations = [];
137
+
138
+	/**
139
+	 * Relationships which use a pivot record.
140
+	 *
141
+	 * @var array
142
+	 */
143
+	private $pivotRelations = [];
144
+
145
+	/**
146
+	 * Polymorphic relationships.
147
+	 *
148
+	 * @var array
149
+	 */
150
+	private $polymorphicRelations = [];
151
+
152
+	/**
153
+	 * Dynamic relationships.
154
+	 *
155
+	 * @var array
156
+	 */
157
+	private $dynamicRelationships = [];
158
+
159
+	/**
160
+	 * Targetted class for the relationship method. value is set to `null` for
161
+	 * polymorphic relations.
162
+	 *
163
+	 * @var array
164
+	 */
165
+	private $relatedClasses = [];
166
+
167
+	/**
168
+	 * Some relation methods like embedded objects, or HasOne and MorphOne,
169
+	 * will never have a proxy loaded on them.
170
+	 *
171
+	 * @var array
172
+	 */
173
+	private $nonProxyRelationships = [];
174
+
175
+	/**
176
+	 * Relation methods that are embedded objects.
177
+	 *
178
+	 * @var array
179
+	 */
180
+	private $embeddedRelations = [];
181
+
182
+	/**
183
+	 * The number of models to return for pagination.
184
+	 *
185
+	 * @var int
186
+	 */
187
+	protected $perPage = 15;
188
+
189
+	/**
190
+	 * The relations to eager load on every query.
191
+	 *
192
+	 * @var array
193
+	 */
194
+	protected $with = [];
195
+
196
+	/**
197
+	 * The class name to be used in polymorphic relations.
198
+	 *
199
+	 * @var string
200
+	 */
201
+	protected $morphClass;
202
+
203
+	/**
204
+	 * Sequence name, to be used with postgreSql
205
+	 * defaults to %table_name%_id_seq.
206
+	 *
207
+	 * @var string|null
208
+	 */
209
+	protected $sequence = null;
210
+
211
+	/**
212
+	 * Indicates if the entity should be timestamped.
213
+	 *
214
+	 * @var bool
215
+	 */
216
+	public $timestamps = false;
217
+
218
+	/**
219
+	 * The name of the "created at" column.
220
+	 *
221
+	 * @var string
222
+	 */
223
+	protected $createdAtColumn = 'created_at';
224
+
225
+	/**
226
+	 * The name of the "updated at" column.
227
+	 *
228
+	 * @var string
229
+	 */
230
+	protected $updatedAtColumn = 'updated_at';
231
+
232
+	/**
233
+	 * Indicates if the entity uses softdeletes.
234
+	 *
235
+	 * @var bool
236
+	 */
237
+	public $softDeletes = false;
238
+
239
+	/**
240
+	 * The name of the "deleted at" column.
241
+	 *
242
+	 * @var string
243
+	 */
244
+	protected $deletedAtColumn = 'deleted_at';
245
+
246
+	/**
247
+	 * The date format to use with the current database connection.
248
+	 *
249
+	 * @var string
250
+	 */
251
+	protected $dateFormat;
252
+
253
+	/**
254
+	 * Set this property to true if the entity should be instantiated
255
+	 * using the IoC Container.
256
+	 *
257
+	 * @var bool
258
+	 */
259
+	protected $dependencyInjection = false;
260
+
261
+	/**
262
+	 * Set the usage of inheritance, possible values are :
263
+	 * "single_table"
264
+	 * null.
265
+	 *
266
+	 * @var string | null
267
+	 */
268
+	protected $inheritanceType = null;
269
+
270
+	/**
271
+	 * Discriminator column name.
272
+	 *
273
+	 * @var string
274
+	 */
275
+	protected $discriminatorColumn = 'type';
276
+
277
+	/**
278
+	 * Allow using a string to define which entity type should be instantiated.
279
+	 * If not set, analogue will uses entity's FQDN.
280
+	 *
281
+	 * @var array
282
+	 */
283
+	protected $discriminatorColumnMap = [];
284
+
285
+	/**
286
+	 * Return Domain class attributes, useful when mapping to a Plain PHP Object.
287
+	 *
288
+	 * @return array
289
+	 */
290
+	public function getAttributes() : array
291
+	{
292
+		return $this->attributes;
293
+	}
294
+
295
+	/**
296
+	 * Set the domain class attributes.
297
+	 *
298
+	 * @param array $attributeNames
299
+	 */
300
+	public function setAttributes(array $attributeNames)
301
+	{
302
+		$this->attributes = $attributeNames;
303
+	}
304
+
305
+	/**
306
+	 * Return true if the Entity has an 'attributes' array property.
307
+	 *
308
+	 * @return bool
309
+	 */
310
+	public function usesAttributesArray() : bool
311
+	{
312
+		if ($this->arrayName === null) {
313
+			return false;
314
+		}
315
+		if ($this->attributes === null) {
316
+			return false;
317
+		}
318
+
319
+		return true;
320
+	}
321
+
322
+	/**
323
+	 * Return the name of the Entity's attributes property.
324
+	 *
325
+	 * @return string|null
326
+	 */
327
+	public function getAttributesArrayName()
328
+	{
329
+		return $this->arrayName;
330
+	}
331
+
332
+	/**
333
+	 * Get all the attribute names for the class, including relationships, embeddables and primary key.
334
+	 *
335
+	 * @return array
336
+	 */
337
+	public function getCompiledAttributes() : array
338
+	{
339
+		$key = $this->getKeyName();
340
+
341
+		$embeddables = array_keys($this->getEmbeddables());
342
+
343
+		$relationships = $this->getRelationships();
344
+
345
+		$attributes = $this->getAttributes();
346
+
347
+		return array_merge([$key], $embeddables, $relationships, $attributes);
348
+	}
349
+
350
+	/**
351
+	 * Set the date format to use with the current database connection.
352
+	 *
353
+	 * @param string $format
354
+	 */
355
+	public function setDateFormat($format)
356
+	{
357
+		$this->dateFormat = $format;
358
+	}
359
+
360
+	/**
361
+	 * Get the date format to use with the current database connection.
362
+	 *
363
+	 *  @return string
364
+	 */
365
+	public function getDateFormat() : string
366
+	{
367
+		return $this->dateFormat;
368
+	}
369
+
370
+	/**
371
+	 * Set the Driver for this mapping.
372
+	 *
373
+	 * @param string $driver
374
+	 */
375
+	public function setDriver($driver)
376
+	{
377
+		$this->driver = $driver;
378
+	}
379
+
380
+	/**
381
+	 * Get the Driver for this mapping.
382
+	 *
383
+	 * @return string
384
+	 */
385
+	public function getDriver() : string
386
+	{
387
+		return $this->driver;
388
+	}
389
+
390
+	/**
391
+	 * Set the db connection to use on the table.
392
+	 *
393
+	 * @param $connection
394
+	 */
395
+	public function setConnection($connection)
396
+	{
397
+		$this->connection = $connection;
398
+	}
399
+
400
+	/**
401
+	 * Get the Database connection the Entity is stored on.
402
+	 *
403
+	 * @return string | null
404
+	 */
405
+	public function getConnection()
406
+	{
407
+		return $this->connection;
408
+	}
409
+
410
+	/**
411
+	 * Get the table associated with the entity.
412
+	 *
413
+	 * @return string
414
+	 */
415
+	public function getTable() : string
416
+	{
417
+		if (!is_null($this->table)) {
418
+			return $this->table;
419
+		}
420
+
421
+		return str_replace('\\', '', snake_case(str_plural(class_basename($this->getClass()))));
422
+	}
423
+
424
+	/**
425
+	 * Set the database table name.
426
+	 *
427
+	 * @param string $table
428
+	 */
429
+	public function setTable($table)
430
+	{
431
+		$this->table = $table;
432
+	}
433
+
434
+	/**
435
+	 * Get the pgSql sequence name.
436
+	 *
437
+	 * @return string
438
+	 */
439
+	public function getSequence()
440
+	{
441
+		if (!is_null($this->sequence)) {
442
+			return $this->sequence;
443
+		} else {
444
+			return $this->getTable().'_id_seq';
445
+		}
446
+	}
447
+
448
+	/**
449
+	 * Get the custom entity class.
450
+	 *
451
+	 * @return string namespaced class name
452
+	 */
453
+	public function getClass() : string
454
+	{
455
+		return isset($this->class) ? $this->class : null;
456
+	}
457
+
458
+	/**
459
+	 * Set the custom entity class.
460
+	 *
461
+	 * @param string $class namespaced class name
462
+	 */
463
+	public function setClass($class)
464
+	{
465
+		$this->class = $class;
466
+	}
467
+
468
+	/**
469
+	 * Get the embedded Value Objects.
470
+	 *
471
+	 * @return array
472
+	 */
473
+	public function getEmbeddables() : array
474
+	{
475
+		return $this->embeddables;
476
+	}
477
+
478
+	/**
479
+	 * Return attributes that should be mapped to class properties.
480
+	 *
481
+	 * @return array
482
+	 */
483
+	public function getProperties() : array
484
+	{
485
+		return $this->properties;
486
+	}
487
+
488
+	/**
489
+	 * Return the array property in which will be mapped all attributes
490
+	 * that are not mapped to class properties.
491
+	 *
492
+	 * @return string
493
+	 */
494
+	public function getAttributesPropertyName() : string
495
+	{
496
+	}
497
+
498
+	/**
499
+	 * Set the embedded Value Objects.
500
+	 *
501
+	 * @param array $embeddables
502
+	 */
503
+	public function setEmbeddables(array $embeddables)
504
+	{
505
+		$this->embeddables = $embeddables;
506
+	}
507
+
508
+	/**
509
+	 * Get the relationships to map on a custom domain
510
+	 * class.
511
+	 *
512
+	 * @return array
513
+	 */
514
+	public function getRelationships() : array
515
+	{
516
+		return $this->relationships;
517
+	}
518
+
519
+	/**
520
+	 * Return all relationships that are not embedded objects.
521
+	 *
522
+	 * @return array
523
+	 */
524
+	public function getNonEmbeddedRelationships() : array
525
+	{
526
+		return array_diff($this->relationships, $this->embeddedRelations);
527
+	}
528
+
529
+	/**
530
+	 * Get the relationships that will not have a proxy
531
+	 * set on them.
532
+	 *
533
+	 * @return array
534
+	 */
535
+	public function getRelationshipsWithoutProxy() : array
536
+	{
537
+		return $this->nonProxyRelationships;
538
+	}
539
+
540
+	/**
541
+	 * Relationships of the Entity type.
542
+	 *
543
+	 * @return array
544
+	 */
545
+	public function getSingleRelationships() : array
546
+	{
547
+		return $this->singleRelations;
548
+	}
549
+
550
+	/**
551
+	 * Relationships of type Collection.
552
+	 *
553
+	 * @return array
554
+	 */
555
+	public function getManyRelationships() : array
556
+	{
557
+		return $this->manyRelations;
558
+	}
559
+
560
+	/**
561
+	 * Relationships with foreign key in the mapped entity record.
562
+	 *
563
+	 * @return array
564
+	 */
565
+	public function getLocalRelationships() : array
566
+	{
567
+		return $this->localRelations;
568
+	}
569
+
570
+	/**
571
+	 * Return the local keys associated to the relationship.
572
+	 *
573
+	 * @param string $relation
574
+	 *
575
+	 * @return string | array | null
576
+	 */
577
+	public function getLocalKeys($relation)
578
+	{
579
+		return isset($this->localForeignKeys[$relation]) ? $this->localForeignKeys[$relation] : null;
580
+	}
581
+
582
+	/**
583
+	 * Relationships with foreign key in the related Entity record.
584
+	 *
585
+	 * @return array
586
+	 */
587
+	public function getForeignRelationships() : array
588
+	{
589
+		return $this->foreignRelations;
590
+	}
591
+
592
+	/**
593
+	 * Relationships which keys are stored in a pivot record.
594
+	 *
595
+	 * @return array
596
+	 */
597
+	public function getPivotRelationships() : array
598
+	{
599
+		return $this->pivotRelations;
600
+	}
601
+
602
+	/**
603
+	 * Return an array containing all embedded relationships.
604
+	 *
605
+	 * @return array
606
+	 */
607
+	public function getEmbeddedRelationships() : array
608
+	{
609
+		return $this->embeddedRelations;
610
+	}
611
+
612
+	/**
613
+	 * Return true if the relationship method is polymorphic.
614
+	 *
615
+	 * @param string $relation
616
+	 *
617
+	 * @return bool
618
+	 */
619
+	public function isPolymorphic($relation) : bool
620
+	{
621
+		return in_array($relation, $this->polymorphicRelations);
622
+	}
623
+
624
+	/**
625
+	 * Get the targetted type for a relationship. Return null if polymorphic.
626
+	 *
627
+	 * @param string $relation
628
+	 *
629
+	 * @return string | null
630
+	 */
631
+	public function getTargettedClass($relation)
632
+	{
633
+		if (!array_key_exists($relation, $this->relatedClasses)) {
634
+			return;
635
+		}
636
+
637
+		return $this->relatedClasses[$relation];
638
+	}
639
+
640
+	/**
641
+	 * Add a Dynamic Relationship method at runtime. This has to be done
642
+	 * by hooking the 'initializing' event, before entityMap is initialized.
643
+	 *
644
+	 * @param string   $name         Relation name
645
+	 * @param \Closure $relationship
646
+	 *
647
+	 * @return void
648
+	 */
649
+	public function addRelationshipMethod($name, \Closure $relationship)
650
+	{
651
+		$this->dynamicRelationships[$name] = $relationship;
652
+	}
653
+
654
+	/**
655
+	 * Get the dynamic relationship method names.
656
+	 *
657
+	 * @return array
658
+	 */
659
+	public function getDynamicRelationships() : array
660
+	{
661
+		return array_keys($this->dynamicRelationships);
662
+	}
663
+
664
+	/**
665
+	 * Get the relationships that have to be eager loaded
666
+	 * on each request.
667
+	 *
668
+	 * @return array
669
+	 */
670
+	public function getEagerloadedRelationships() : array
671
+	{
672
+		return $this->with;
673
+	}
674
+
675
+	/**
676
+	 * Get the primary key attribute for the entity.
677
+	 *
678
+	 * @return string
679
+	 */
680
+	public function getKeyName() : string
681
+	{
682
+		return $this->primaryKey;
683
+	}
684
+
685
+	/**
686
+	 * Set the primary key for the entity.
687
+	 *
688
+	 * @param $key
689
+	 *
690
+	 * @return void
691
+	 */
692
+	public function setKeyName($key)
693
+	{
694
+		$this->primaryKey = $key;
695
+	}
696
+
697
+	/**
698
+	 * Get the table qualified key name.
699
+	 *
700
+	 * @return string
701
+	 */
702
+	public function getQualifiedKeyName() : string
703
+	{
704
+		return $this->getTable().'.'.$this->getKeyName();
705
+	}
706
+
707
+	/**
708
+	 * Get the number of models to return per page.
709
+	 *
710
+	 * @return int
711
+	 */
712
+	public function getPerPage() : int
713
+	{
714
+		return $this->perPage;
715
+	}
716
+
717
+	/**
718
+	 * Set the number of models to return per page.
719
+	 *
720
+	 * @param int $perPage
721
+	 *
722
+	 * @return void
723
+	 */
724
+	public function setPerPage($perPage)
725
+	{
726
+		$this->perPage = $perPage;
727
+	}
728
+
729
+	/**
730
+	 * Determine if the entity uses get.
731
+	 *
732
+	 * @return bool
733
+	 */
734
+	public function usesTimestamps() : bool
735
+	{
736
+		return $this->timestamps;
737
+	}
738
+
739
+	/**
740
+	 * Determine if the entity uses soft deletes.
741
+	 *
742
+	 * @return bool
743
+	 */
744
+	public function usesSoftDeletes() : bool
745
+	{
746
+		return $this->softDeletes;
747
+	}
748
+
749
+	/**
750
+	 * Get the 'created_at' column name.
751
+	 *
752
+	 * @return string
753
+	 */
754
+	public function getCreatedAtColumn() : string
755
+	{
756
+		return $this->createdAtColumn;
757
+	}
758
+
759
+	/**
760
+	 * Get the 'updated_at' column name.
761
+	 *
762
+	 * @return string
763
+	 */
764
+	public function getUpdatedAtColumn() : string
765
+	{
766
+		return $this->updatedAtColumn;
767
+	}
768
+
769
+	/**
770
+	 * Get the deleted_at column.
771
+	 *
772
+	 * @return string
773
+	 */
774
+	public function getQualifiedDeletedAtColumn() : string
775
+	{
776
+		return $this->deletedAtColumn;
777
+	}
778
+
779
+	/**
780
+	 * Get the default foreign key name for the model.
781
+	 *
782
+	 * @return string
783
+	 */
784
+	public function getForeignKey() : string
785
+	{
786
+		return snake_case(class_basename($this->getClass())).'_id';
787
+	}
788
+
789
+	/**
790
+	 * Return the inheritance type used by the entity.
791
+	 *
792
+	 * @return string|null
793
+	 */
794
+	public function getInheritanceType()
795
+	{
796
+		return $this->inheritanceType;
797
+	}
798
+
799
+	/**
800
+	 * Return the discriminator column name on the entity that's
801
+	 * used for table inheritance.
802
+	 *
803
+	 * @return string
804
+	 */
805
+	public function getDiscriminatorColumn() : string
806
+	{
807
+		return $this->discriminatorColumn;
808
+	}
809
+
810
+	/**
811
+	 * Return the mapping of discriminator column values to
812
+	 * entity class names that are used for table inheritance.
813
+	 *
814
+	 * @return array
815
+	 */
816
+	public function getDiscriminatorColumnMap() : array
817
+	{
818
+		return $this->discriminatorColumnMap;
819
+	}
820
+
821
+	/**
822
+	 * Return true if the entity should be instanciated using
823
+	 * the IoC Container.
824
+	 *
825
+	 * @return bool
826
+	 */
827
+	public function useDependencyInjection() : bool
828
+	{
829
+		return $this->dependencyInjection;
830
+	}
831
+
832
+	/**
833
+	 * Add a single relation method name once.
834
+	 *
835
+	 * @param string $relation
836
+	 */
837
+	protected function addSingleRelation($relation)
838
+	{
839
+		if (!in_array($relation, $this->singleRelations)) {
840
+			$this->singleRelations[] = $relation;
841
+		}
842
+	}
843
+
844
+	/**
845
+	 * Add a foreign relation method name once.
846
+	 *
847
+	 * @param string $relation
848
+	 */
849
+	protected function addForeignRelation($relation)
850
+	{
851
+		if (!in_array($relation, $this->foreignRelations)) {
852
+			$this->foreignRelations[] = $relation;
853
+		}
854
+	}
855
+
856
+	/**
857
+	 * Add a polymorphic relation method name once.
858
+	 *
859
+	 * @param string $relation
860
+	 */
861
+	protected function addPolymorphicRelation($relation)
862
+	{
863
+		if (!in_array($relation, $this->polymorphicRelations)) {
864
+			$this->polymorphicRelations[] = $relation;
865
+		}
866
+	}
867
+
868
+	/**
869
+	 * Add a non proxy relation method name once.
870
+	 *
871
+	 * @param string $relation
872
+	 */
873
+	protected function addNonProxyRelation($relation)
874
+	{
875
+		if (!in_array($relation, $this->nonProxyRelationships)) {
876
+			$this->nonProxyRelationships[] = $relation;
877
+		}
878
+	}
879
+
880
+	/**
881
+	 * Add a local relation method name once.
882
+	 *
883
+	 * @param string $relation
884
+	 */
885
+	protected function addLocalRelation($relation)
886
+	{
887
+		if (!in_array($relation, $this->localRelations)) {
888
+			$this->localRelations[] = $relation;
889
+		}
890
+	}
891
+
892
+	/**
893
+	 * Add a many relation method name once.
894
+	 *
895
+	 * @param string $relation
896
+	 */
897
+	protected function addManyRelation($relation)
898
+	{
899
+		if (!in_array($relation, $this->manyRelations)) {
900
+			$this->manyRelations[] = $relation;
901
+		}
902
+	}
903
+
904
+	/**
905
+	 * Add a pivot relation method name once.
906
+	 *
907
+	 * @param string $relation
908
+	 */
909
+	protected function addPivotRelation($relation)
910
+	{
911
+		if (!in_array($relation, $this->pivotRelations)) {
912
+			$this->pivotRelations[] = $relation;
913
+		}
914
+	}
915
+
916
+	/**
917
+	 * Add an embedded relation.
918
+	 *
919
+	 * @param string $relation
920
+	 */
921
+	protected function addEmbeddedRelation($relation)
922
+	{
923
+		if (!in_array($relation, $this->embeddedRelations)) {
924
+			$this->embeddedRelations[] = $relation;
925
+		}
926
+	}
927
+
928
+	/**
929
+	 * Define an Embedded Object.
930
+	 *
931
+	 * @param mixed  $entity
932
+	 * @param string $related
933
+	 *
934
+	 * @return EmbedsOne
935
+	 */
936
+	public function embedsOne($parent, string $relatedClass, $relation = null) : EmbedsOne
937
+	{
938
+		if(is_null($relation)) {
939
+			list(, $caller) = debug_backtrace(false);
940
+			$relation = $caller['function'];
941
+		}
942
+
943
+		$this->addEmbeddedRelation($relation);
944
+		$this->addNonProxyRelation($relation);
945
+
946
+		return new EmbedsOne($parent, $relatedClass, $relation);
947
+	}
948
+
949
+	/**
950
+	 * Define an Embedded Collection.
951
+	 *
952
+	 * @param mixed  $entity
953
+	 * @param string $related
954
+	 *
955
+	 * @return EmbedsOne
956
+	 */
957
+	public function embedsMany($parent, string $relatedClass, $relation = null) : EmbedsMany
958
+	{
959
+		if(is_null($relation)) {
960
+			list(, $caller) = debug_backtrace(false);
961
+			$relation = $caller['function'];
962
+		}
963
+
964
+		$this->addEmbeddedRelation($relation);
965
+		$this->addNonProxyRelation($relation);
966
+
967
+		return new EmbedsMany($parent, $relatedClass, $relation);
968
+	}
969
+
970
+	/**
971
+	 * Define a one-to-one relationship.
972
+	 *
973
+	 * @param mixed  $entity
974
+	 * @param string $related    entity class
975
+	 * @param string $foreignKey
976
+	 * @param string $localKey
977
+	 *
978
+	 * @throws MappingException
979
+	 *
980
+	 * @return \Analogue\ORM\Relationships\HasOne
981
+	 */
982
+	public function hasOne($entity, $related, $foreignKey = null, $localKey = null)
983
+	{
984
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
985
+
986
+		$relatedMapper = Manager::getInstance()->mapper($related);
987
+
988
+		$relatedMap = $relatedMapper->getEntityMap();
989
+
990
+		$localKey = $localKey ?: $this->getKeyName();
991
+
992
+		// Add the relation to the definition in map
993
+		list(, $caller) = debug_backtrace(false);
994
+		$relation = $caller['function'];
995
+		$this->relatedClasses[$relation] = $related;
996
+
997
+		$this->addSingleRelation($relation);
998
+		$this->addForeignRelation($relation);
999
+		$this->addNonProxyRelation($relation);
1000
+
1001
+		// This relationship will always be eager loaded, as proxying it would
1002
+		// mean having an object that doesn't actually exists.
1003
+		if (!in_array($relation, $this->with)) {
1004
+			$this->with[] = $relation;
1005
+		}
1006
+
1007
+		return new HasOne($relatedMapper, $entity, /*$relatedMap->getTable().'.'*/$foreignKey, $localKey);
1008
+	}
1009
+
1010
+	/**
1011
+	 * Define a polymorphic one-to-one relationship.
1012
+	 *
1013
+	 * @param mixed       $entity
1014
+	 * @param string      $related
1015
+	 * @param string      $name
1016
+	 * @param string|null $type
1017
+	 * @param string|null $id
1018
+	 * @param string|null $localKey
1019
+	 *
1020
+	 * @throws MappingException
1021
+	 *
1022
+	 * @return \Analogue\ORM\Relationships\MorphOne
1023
+	 */
1024
+	public function morphOne($entity, $related, $name, $type = null, $id = null, $localKey = null)
1025
+	{
1026
+		list($type, $id) = $this->getMorphs($name, $type, $id);
1027
+
1028
+		$localKey = $localKey ?: $this->getKeyName();
1029
+
1030
+		$relatedMapper = Manager::getInstance()->mapper($related);
1031
+
1032
+		//$table = $relatedMapper->getEntityMap()->getTable();
1033
+
1034
+		// Add the relation to the definition in map
1035
+		list(, $caller) = debug_backtrace(false);
1036
+		$relation = $caller['function'];
1037
+		$this->relatedClasses[$relation] = $related;
1038
+
1039
+		$this->addSingleRelation($relation);
1040
+		$this->addForeignRelation($relation);
1041
+		$this->addNonProxyRelation($relation);
1042
+
1043
+		// This relationship will always be eager loaded, as proxying it would
1044
+		// mean having an object that doesn't actually exists.
1045
+		if (!in_array($relation, $this->with)) {
1046
+			$this->with[] = $relation;
1047
+		}
1048
+
1049
+		return new MorphOne($relatedMapper, $entity, /*$table.'.'.*/$type, /*$table.'.'.*/$id, $localKey);
1050
+	}
1051
+
1052
+	/**
1053
+	 * Define an inverse one-to-one or many relationship.
1054
+	 *
1055
+	 * @param mixed       $entity
1056
+	 * @param string      $related
1057
+	 * @param string|null $foreignKey
1058
+	 * @param string|null $otherKey
1059
+	 * @param string|null $relation
1060
+	 *
1061
+	 * @throws MappingException
1062
+	 *
1063
+	 * @return \Analogue\ORM\Relationships\BelongsTo
1064
+	 */
1065
+	public function belongsTo($entity, $related, $foreignKey = null, $otherKey = null)
1066
+	{
1067
+		// Add the relation to the definition in map
1068
+		list(, $caller) = debug_backtrace(false);
1069
+		$relation = $caller['function'];
1070
+		$this->relatedClasses[$relation] = $related;
1071
+
1072
+		$this->addSingleRelation($relation);
1073
+		$this->addLocalRelation($relation);
1074
+
1075
+		// If no foreign key was supplied, we can use a backtrace to guess the proper
1076
+		// foreign key name by using the name of the relationship function, which
1077
+		// when combined with an "_id" should conventionally match the columns.
1078
+		if (is_null($foreignKey)) {
1079
+			$foreignKey = snake_case($relation).'_id';
1080
+		}
1081
+
1082
+		$this->localForeignKeys[$relation] = $foreignKey;
1083
+
1084
+		$relatedMapper = Manager::getInstance()->mapper($related);
1085
+
1086
+		$otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getKeyName();
1087
+
1088
+		return new BelongsTo($relatedMapper, $entity, $foreignKey, $otherKey, $relation);
1089
+	}
1090
+
1091
+	/**
1092
+	 * Define a polymorphic, inverse one-to-one or many relationship.
1093
+	 *
1094
+	 * @param mixed       $entity
1095
+	 * @param string|null $name
1096
+	 * @param string|null $type
1097
+	 * @param string|null $id
1098
+	 *
1099
+	 * @throws MappingException
1100
+	 *
1101
+	 * @return \Analogue\ORM\Relationships\MorphTo
1102
+	 */
1103
+	public function morphTo($entity, $name = null, $type = null, $id = null)
1104
+	{
1105
+		// If no name is provided, we will use the backtrace to get the function name
1106
+		// since that is most likely the name of the polymorphic interface. We can
1107
+		// use that to get both the class and foreign key that will be utilized.
1108
+		if (is_null($name)) {
1109
+			list(, $caller) = debug_backtrace(false);
1110
+
1111
+			$name = snake_case($caller['function']);
1112
+		}
1113
+		$this->addSingleRelation($name);
1114
+		$this->addLocalRelation($name);
1115
+		$this->addPolymorphicRelation($name);
1116
+
1117
+		$this->relatedClass[$name] = null;
1118
+
1119
+		list($type, $id) = $this->getMorphs($name, $type, $id);
1120
+
1121
+		// Store the foreign key in the entity map.
1122
+		// We might want to store the (key, type) as we might need it
1123
+		// to build a MorphTo proxy
1124
+		$this->localForeignKeys[$name] = [
1125
+			'id'   => $id,
1126
+			'type' => $type,
1127
+		];
1128
+
1129
+		$mapper = Manager::getInstance()->mapper(get_class($entity));
1130
+
1131
+		// If the type value is null it is probably safe to assume we're eager loading
1132
+		// the relationship. When that is the case we will pass in a dummy query as
1133
+		// there are multiple types in the morph and we can't use single queries.
1134
+		$factory = new Factory();
1135
+		$wrapper = $factory->make($entity);
1136
+
1137
+		if (is_null($class = $wrapper->getEntityAttribute($type))) {
1138
+			return new MorphTo(
1139
+				$mapper, $entity, $id, null, $type, $name
1140
+			);
1141
+		}
1142
+
1143
+		// If we are not eager loading the relationship we will essentially treat this
1144
+		// as a belongs-to style relationship since morph-to extends that class and
1145
+		// we will pass in the appropriate values so that it behaves as expected.
1146
+		else {
1147
+			$class = Manager::getInstance()->getInverseMorphMap($class);
1148
+			$relatedMapper = Manager::getInstance()->mapper($class);
1149
+
1150
+			$foreignKey = $relatedMapper->getEntityMap()->getKeyName();
1151
+
1152
+			return new MorphTo(
1153
+				$relatedMapper, $entity, $id, $foreignKey, $type, $name
1154
+			);
1155
+		}
1156
+	}
1157
+
1158
+	/**
1159
+	 * Define a one-to-many relationship.
1160
+	 *
1161
+	 * @param mixed       $entity
1162
+	 * @param string      $related
1163
+	 * @param string|null $foreignKey
1164
+	 * @param string|null $localKey
1165
+	 *
1166
+	 * @throws MappingException
1167
+	 *
1168
+	 * @return \Analogue\ORM\Relationships\HasMany
1169
+	 */
1170
+	public function hasMany($entity, $related, $foreignKey = null, $localKey = null)
1171
+	{
1172
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
1173
+
1174
+		$relatedMapper = Manager::getInstance()->mapper($related);
1175
+
1176
+		$localKey = $localKey ?: $this->getKeyName();
1177
+
1178
+		// Add the relation to the definition in map
1179
+		list(, $caller) = debug_backtrace(false);
1180
+		$relation = $caller['function'];
1181
+		$this->relatedClasses[$relation] = $related;
1182
+
1183
+		$this->addManyRelation($relation);
1184
+		$this->addForeignRelation($relation);
1185
+
1186
+		return new HasMany($relatedMapper, $entity, $foreignKey, $localKey);
1187
+	}
1188
+
1189
+	/**
1190
+	 * Define a has-many-through relationship.
1191
+	 *
1192
+	 * @param mixed       $entity
1193
+	 * @param string      $related
1194
+	 * @param string      $through
1195
+	 * @param string|null $firstKey
1196
+	 * @param string|null $secondKey
1197
+	 *
1198
+	 * @throws MappingException
1199
+	 *
1200
+	 * @return \Analogue\ORM\Relationships\HasManyThrough
1201
+	 */
1202
+	public function hasManyThrough($entity, $related, $through, $firstKey = null, $secondKey = null)
1203
+	{
1204
+		$relatedMapper = Manager::getInstance()->mapper($related);
1205
+		$throughMapper = Manager::getInstance()->mapper($through);
1206
+
1207
+		$firstKey = $firstKey ?: $this->getForeignKey();
1208
+
1209
+		$throughMap = $throughMapper->getEntityMap();
1210
+
1211
+		$secondKey = $secondKey ?: $throughMap->getForeignKey();
1212
+
1213
+		// Add the relation to the definition in map
1214
+		list(, $caller) = debug_backtrace(false);
1215
+		$relation = $caller['function'];
1216
+		$this->relatedClasses[$relation] = $related;
1217
+
1218
+		$this->addManyRelation($relation);
1219
+		$this->addForeignRelation($relation);
1220
+
1221
+		return new HasManyThrough($relatedMapper, $entity, $throughMap, $firstKey, $secondKey);
1222
+	}
1223
+
1224
+	/**
1225
+	 * Define a polymorphic one-to-many relationship.
1226
+	 *
1227
+	 * @param mixed       $entity
1228
+	 * @param string      $related
1229
+	 * @param string      $name
1230
+	 * @param string|null $type
1231
+	 * @param string|null $id
1232
+	 * @param string|null $localKey
1233
+	 *
1234
+	 * @return \Analogue\ORM\Relationships\MorphMany
1235
+	 */
1236
+	public function morphMany($entity, $related, $name, $type = null, $id = null, $localKey = null)
1237
+	{
1238
+		// Here we will gather up the morph type and ID for the relationship so that we
1239
+		// can properly query the intermediate table of a relation. Finally, we will
1240
+		// get the table and create the relationship instances for the developers.
1241
+		list($type, $id) = $this->getMorphs($name, $type, $id);
1242
+
1243
+		$relatedMapper = Manager::getInstance()->mapper($related);
1244
+
1245
+		$table = $relatedMapper->getEntityMap()->getTable();
1246
+
1247
+		$localKey = $localKey ?: $this->getKeyName();
1248
+
1249
+		// Add the relation to the definition in map
1250
+		list(, $caller) = debug_backtrace(false);
1251
+		$relation = $caller['function'];
1252
+		$this->relatedClasses[$relation] = $related;
1253
+
1254
+		$this->addManyRelation($relation);
1255
+		$this->addForeignRelation($relation);
1256
+
1257
+		return new MorphMany($relatedMapper, $entity, /*$table.'.'.*/$type, /*$table.'.'.*/$id, $localKey);
1258
+	}
1259
+
1260
+	/**
1261
+	 * Define a many-to-many relationship.
1262
+	 *
1263
+	 * @param mixed       $entity
1264
+	 * @param string      $relatedClass
1265
+	 * @param string|null $table
1266
+	 * @param string|null $foreignKey
1267
+	 * @param string|null $otherKey
1268
+	 * @param string|null $relation
1269
+	 *
1270
+	 * @throws MappingException
1271
+	 *
1272
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
1273
+	 */
1274
+	public function belongsToMany($entity, $related, $table = null, $foreignKey = null, $otherKey = null)
1275
+	{
1276
+		// Add the relation to the definition in map
1277
+		list(, $caller) = debug_backtrace(false);
1278
+		$relation = $caller['function'];
1279
+		$this->relatedClasses[$relation] = $related;
1280
+
1281
+		$this->addManyRelation($relation);
1282
+		$this->addForeignRelation($relation);
1283
+		$this->addPivotRelation($relation);
1284
+
1285
+		// First, we'll need to determine the foreign key and "other key" for the
1286
+		// relationship. Once we have determined the keys we'll make the query
1287
+		// instances as well as the relationship instances we need for this.
1288
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
1289
+
1290
+		$relatedMapper = Manager::getInstance()->mapper($related);
1291
+
1292
+		$relatedMap = $relatedMapper->getEntityMap();
1293
+
1294
+		$otherKey = $otherKey ?: $relatedMap->getForeignKey();
1295
+
1296
+		// If no table name was provided, we can guess it by concatenating the two
1297
+		// models using underscores in alphabetical order. The two model names
1298
+		// are transformed to snake case from their default CamelCase also.
1299
+		if (is_null($table)) {
1300
+			$table = $this->joiningTable($relatedMap);
1301
+		}
1302
+
1303
+		return new BelongsToMany($relatedMapper, $entity, $table, $foreignKey, $otherKey, $relation);
1304
+	}
1305
+
1306
+	/**
1307
+	 * Define a polymorphic many-to-many relationship.
1308
+	 *
1309
+	 * @param mixed       $entity
1310
+	 * @param string      $related
1311
+	 * @param string      $name
1312
+	 * @param string|null $table
1313
+	 * @param string|null $foreignKey
1314
+	 * @param string|null $otherKey
1315
+	 * @param bool        $inverse
1316
+	 *
1317
+	 * @throws MappingException
1318
+	 *
1319
+	 * @return \Analogue\ORM\Relationships\MorphToMany
1320
+	 */
1321
+	public function morphToMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
1322
+	{
1323
+		// Add the relation to the definition in map
1324
+		list(, $caller) = debug_backtrace(false);
1325
+		$relation = $caller['function'];
1326
+		$this->relatedClasses[$relation] = $related;
1327
+
1328
+		$this->addManyRelation($relation);
1329
+		$this->addForeignRelation($relation);
1330
+		$this->addPivotRelation($relation);
1331
+
1332
+		// First, we will need to determine the foreign key and "other key" for the
1333
+		// relationship. Once we have determined the keys we will make the query
1334
+		// instances, as well as the relationship instances we need for these.
1335
+		$foreignKey = $foreignKey ?: $name.'_id';
1336
+
1337
+		$relatedMapper = Manager::getInstance()->mapper($related);
1338
+
1339
+		$otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getForeignKey();
1340
+
1341
+		$table = $table ?: str_plural($name);
1342
+
1343
+		return new MorphToMany($relatedMapper, $entity, $name, $table, $foreignKey, $otherKey, $caller, $inverse);
1344
+	}
1345
+
1346
+	/**
1347
+	 * Define a polymorphic, inverse many-to-many relationship.
1348
+	 *
1349
+	 * @param mixed       $entity
1350
+	 * @param string      $related
1351
+	 * @param string      $name
1352
+	 * @param string|null $table
1353
+	 * @param string|null $foreignKey
1354
+	 * @param string|null $otherKey
1355
+	 *
1356
+	 * @throws MappingException
1357
+	 *
1358
+	 * @return \Analogue\ORM\Relationships\MorphToMany
1359
+	 */
1360
+	public function morphedByMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null)
1361
+	{
1362
+		// Add the relation to the definition in map
1363
+		list(, $caller) = debug_backtrace(false);
1364
+		$relation = $caller['function'];
1365
+		$this->relatedClasses[$relation] = $related;
1366
+
1367
+		$this->addManyRelation($relation);
1368
+		$this->addForeignRelation($relation);
1369
+
1370
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
1371
+
1372
+		// For the inverse of the polymorphic many-to-many relations, we will change
1373
+		// the way we determine the foreign and other keys, as it is the opposite
1374
+		// of the morph-to-many method since we're figuring out these inverses.
1375
+		$otherKey = $otherKey ?: $name.'_id';
1376
+
1377
+		return $this->morphToMany($entity, $related, $name, $table, $foreignKey, $otherKey, true);
1378
+	}
1379
+
1380
+	/**
1381
+	 * Get the joining table name for a many-to-many relation.
1382
+	 *
1383
+	 * @param EntityMap $relatedMap
1384
+	 *
1385
+	 * @return string
1386
+	 */
1387
+	public function joiningTable($relatedMap)
1388
+	{
1389
+		// The joining table name, by convention, is simply the snake cased models
1390
+		// sorted alphabetically and concatenated with an underscore, so we can
1391
+		// just sort the models and join them together to get the table name.
1392
+		$base = $this->getTable();
1393
+
1394
+		$related = $relatedMap->getTable();
1395
+
1396
+		$tables = [$related, $base];
1397
+
1398
+		// Now that we have the model names in an array we can just sort them and
1399
+		// use the implode function to join them together with an underscores,
1400
+		// which is typically used by convention within the database system.
1401
+		sort($tables);
1402
+
1403
+		return strtolower(implode('_', $tables));
1404
+	}
1405
+
1406
+	/**
1407
+	 * Get the polymorphic relationship columns.
1408
+	 *
1409
+	 * @param string $name
1410
+	 * @param string $type
1411
+	 * @param string $id
1412
+	 *
1413
+	 * @return string[]
1414
+	 */
1415
+	protected function getMorphs($name, $type, $id)
1416
+	{
1417
+		$type = $type ?: $name.'_type';
1418
+
1419
+		$id = $id ?: $name.'_id';
1420
+
1421
+		return [$type, $id];
1422
+	}
1423
+
1424
+	/**
1425
+	 * Get the class name for polymorphic relations.
1426
+	 *
1427
+	 * @return string
1428
+	 */
1429
+	public function getMorphClass()
1430
+	{
1431
+		$morphClass = Manager::getInstance()->getMorphMap($this->getClass());
1432
+
1433
+		return $this->morphClass ?: $morphClass;
1434
+	}
1435
+
1436
+	/**
1437
+	 * Create a new Entity Collection instance.
1438
+	 *
1439
+	 * @param array $entities
1440
+	 *
1441
+	 * @return \Analogue\ORM\EntityCollection
1442
+	 */
1443
+	public function newCollection(array $entities = [])
1444
+	{
1445
+		$collection = new EntityCollection($entities, $this);
1446
+
1447
+		return $collection->keyBy($this->getKeyName());
1448
+	}
1449
+
1450
+	/**
1451
+	 * Process EntityMap parsing at initialization time.
1452
+	 *
1453
+	 * @return void
1454
+	 */
1455
+	public function initialize()
1456
+	{
1457
+		$userMethods = $this->getCustomMethods();
1458
+
1459
+		// Parse EntityMap for method based relationship
1460
+		if (count($userMethods) > 0) {
1461
+			$this->relationships = $this->parseMethodsForRelationship($userMethods);
1462
+		}
1463
+
1464
+		// Parse EntityMap for dynamic relationships
1465
+		if (count($this->dynamicRelationships) > 0) {
1466
+			$this->relationships = $this->relationships + $this->getDynamicRelationships();
1467
+		}
1468
+	}
1469
+
1470
+	/**
1471
+	 * Parse every relationships on the EntityMap and sort
1472
+	 * them by type.
1473
+	 *
1474
+	 * @return void
1475
+	 */
1476
+	public function boot()
1477
+	{
1478
+		if (count($this->relationships > 0)) {
1479
+			$this->sortRelationshipsByType();
1480
+		}
1481
+	}
1482
+
1483
+	/**
1484
+	 * Get Methods that has been added in the child class.
1485
+	 *
1486
+	 * @return array
1487
+	 */
1488
+	protected function getCustomMethods()
1489
+	{
1490
+		$mapMethods = get_class_methods($this);
1491
+
1492
+		$parentsMethods = get_class_methods('Analogue\ORM\EntityMap');
1493
+
1494
+		return array_diff($mapMethods, $parentsMethods);
1495
+	}
1496
+
1497
+	/**
1498
+	 * Parse user's class methods for relationships.
1499
+	 *
1500
+	 * @param array $customMethods
1501
+	 *
1502
+	 * @return array
1503
+	 */
1504
+	protected function parseMethodsForRelationship(array $customMethods)
1505
+	{
1506
+		$relationships = [];
1507
+
1508
+		$class = new ReflectionClass(get_class($this));
1509
+
1510
+		// Get the mapped Entity class, as we will detect relationships
1511
+		// methods by testing that the first argument is type-hinted to
1512
+		// the same class as the mapped Entity.
1513
+		$entityClass = $this->getClass();
1514
+
1515
+		foreach ($customMethods as $methodName) {
1516
+			$method = $class->getMethod($methodName);
1517
+
1518
+			if ($method->getNumberOfParameters() > 0) {
1519
+				$params = $method->getParameters();
1520
+
1521
+				if ($params[0]->getClass() && ($params[0]->getClass()->name == $entityClass || is_subclass_of($entityClass, $params[0]->getClass()->name))) {
1522
+					$relationships[] = $methodName;
1523
+				}
1524
+			}
1525
+		}
1526
+
1527
+		return $relationships;
1528
+	}
1529
+
1530
+	/**
1531
+	 * Sort Relationships methods by type.
1532
+	 *
1533
+	 * TODO : replace this by direclty setting these value
1534
+	 * in the corresponding methods, so we won't need
1535
+	 * the correpondancy tabble
1536
+	 *
1537
+	 * @return void
1538
+	 */
1539
+	protected function sortRelationshipsByType()
1540
+	{
1541
+		$entityClass = $this->getClass();
1542
+
1543
+		// Instantiate a dummy entity which we will pass to relationship methods.
1544
+		$entity = unserialize(sprintf('O:%d:"%s":0:{}', strlen($entityClass), $entityClass));
1545
+
1546
+		foreach ($this->relationships as $relation) {
1547
+			$this->$relation($entity);
1548
+		}
1549
+	}
1550
+
1551
+	/**
1552
+	 * Override this method for custom entity instantiation.
1553
+	 *
1554
+	 * @return null
1555
+	 */
1556
+	public function activator()
1557
+	{
1558
+	}
1559
+
1560
+	/**
1561
+	 * Magic call to dynamic relationships.
1562
+	 *
1563
+	 * @param string $method
1564
+	 * @param array  $parameters
1565
+	 *
1566
+	 * @throws Exception
1567
+	 *
1568
+	 * @return mixed
1569
+	 */
1570
+	public function __call($method, $parameters)
1571
+	{
1572
+		if (!array_key_exists($method, $this->dynamicRelationships)) {
1573
+			throw new Exception(get_class($this)." has no method $method");
1574
+		}
1575
+
1576
+		// Add $this to parameters so the closure can call relationship method on the map.
1577
+		$parameters[] = $this;
1578
+
1579
+		return  call_user_func_array([$this->dynamicRelationships[$method], $parameters]);
1580
+	}
1581 1581
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -935,7 +935,7 @@  discard block
 block discarded – undo
935 935
      */
936 936
     public function embedsOne($parent, string $relatedClass, $relation = null) : EmbedsOne
937 937
     {
938
-        if(is_null($relation)) {
938
+        if (is_null($relation)) {
939 939
             list(, $caller) = debug_backtrace(false);
940 940
             $relation = $caller['function'];
941 941
         }
@@ -956,7 +956,7 @@  discard block
 block discarded – undo
956 956
      */
957 957
     public function embedsMany($parent, string $relatedClass, $relation = null) : EmbedsMany
958 958
     {
959
-        if(is_null($relation)) {
959
+        if (is_null($relation)) {
960 960
             list(, $caller) = debug_backtrace(false);
961 961
             $relation = $caller['function'];
962 962
         }
Please login to merge, or discard this patch.
src/Relationships/EmbeddedRelationship.php 2 patches
Doc Comments   +2 added lines, -3 removed lines patch added patch discarded remove patch
@@ -154,7 +154,6 @@  discard block
 block discarded – undo
154 154
      * Get attribute name from the parent, if a map has been
155 155
      * defined.
156 156
      *
157
-     * @param srring $attributeKey
158 157
      *
159 158
      * @return string
160 159
      */
@@ -217,7 +216,7 @@  discard block
 block discarded – undo
217 216
     /**
218 217
      * Return parent mapper.
219 218
      *
220
-     * @return Analogue\ORM\System\Mapper
219
+     * @return \Analogue\ORM\System\Mapper
221 220
      */
222 221
     protected function getParentMapper()
223 222
     {
@@ -227,7 +226,7 @@  discard block
 block discarded – undo
227 226
     /**
228 227
      * Return embedded relationship mapper.
229 228
      *
230
-     * @return Analogue\ORM\System\Mapper
229
+     * @return \Analogue\ORM\System\Mapper
231 230
      */
232 231
     protected function getRelatedMapper()
233 232
     {
Please login to merge, or discard this patch.
Indentation   +224 added lines, -224 removed lines patch added patch discarded remove patch
@@ -9,228 +9,228 @@
 block discarded – undo
9 9
 
10 10
 abstract class EmbeddedRelationship
11 11
 {
12
-    /**
13
-     * The class that embeds the current relation.
14
-     *
15
-     * @var string
16
-     */
17
-    protected $parentClass;
18
-
19
-    /**
20
-     * The class of the embedded relation.
21
-     *
22
-     * @var string
23
-     */
24
-    protected $relatedClass;
25
-
26
-    /**
27
-     * The relation attribute on the parent object.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $relation;
32
-
33
-    /**
34
-     * If set to true, embedded Object's attributes will
35
-     * be stored as a serialized array in a JSON Column.
36
-     *
37
-     * @var bool
38
-     */
39
-    protected $asArray = false;
40
-
41
-    /**
42
-     * Prefix on which the object's attributes are saved into
43
-     * the parent's table. defaults to "<relatedClass>_".
44
-     *
45
-     * @var string
46
-     */
47
-    protected $prefix;
48
-
49
-    /**
50
-     * Attributes Map allow the calling EntityMap to overrides attributes
51
-     * on the embedded relation.
52
-     *
53
-     * @var array
54
-     */
55
-    protected $columnMap = [];
56
-
57
-    /**
58
-     * Wrapper factory.
59
-     *
60
-     * @var \Analogue\ORM\System\Wrappers\Factory
61
-     */
62
-    protected $factory;
63
-
64
-    public function __construct($parent, string $relatedClass, string $relation)
65
-    {
66
-        $this->parentClass = get_class($parent);
67
-        $this->relatedClass = $relatedClass;
68
-        $this->relation = $relation;
69
-        $this->prefix = $relation.'_';
70
-        $this->factory = new Factory();
71
-    }
72
-
73
-    /**
74
-     * Switch the 'store as array' feature.
75
-     *
76
-     * @param bool $storeAsArray
77
-     *
78
-     * @return static
79
-     */
80
-    public function asArray(bool $storeAsArray = true)
81
-    {
82
-        $this->asArray = $storeAsArray;
83
-
84
-        return $this;
85
-    }
86
-
87
-    /**
88
-     * Set the column map for the embedded relation.
89
-     *
90
-     * @param array $columns
91
-     *
92
-     * @return static
93
-     */
94
-    public function setColumnMap(array $columns)
95
-    {
96
-        $this->columnMap = $columns;
97
-
98
-        return $this;
99
-    }
100
-
101
-    /**
102
-     * Set parent's attribute prefix.
103
-     *
104
-     * @param string $prefix
105
-     *
106
-     * @return static
107
-     */
108
-    public function setPrefix(string $prefix)
109
-    {
110
-        $this->prefix = $prefix;
111
-
112
-        return $this;
113
-    }
114
-
115
-    /**
116
-     * Return parent's attribute prefix.
117
-     *
118
-     * @return string
119
-     */
120
-    public function getPrefix() : string
121
-    {
122
-        return $this->prefix;
123
-    }
124
-
125
-    /**
126
-     * Get the embedded object's attributes that will be
127
-     * hydrated using parent's entity attributes.
128
-     *
129
-     * @return array
130
-     */
131
-    protected function getEmbeddedObjectAttributes() : array
132
-    {
133
-        $entityMap = $this->getRelatedMapper()->getEntityMap();
134
-
135
-        $attributes = $entityMap->getAttributes();
136
-        $properties = $entityMap->getProperties();
137
-
138
-        return array_merge($attributes, $properties);
139
-    }
140
-
141
-    /**
142
-     * Get the corresponding attribute on parent's attributes.
143
-     *
144
-     * @param string $key
145
-     *
146
-     * @return string
147
-     */
148
-    protected function getParentAttributeKey($key) : string
149
-    {
150
-        return $this->getPrefixedAttributeKey($this->getMappedParentAttribute($key));
151
-    }
152
-
153
-    /**
154
-     * Get attribute name from the parent, if a map has been
155
-     * defined.
156
-     *
157
-     * @param srring $attributeKey
158
-     *
159
-     * @return string
160
-     */
161
-    protected function getMappedParentAttribute(string $key) : string
162
-    {
163
-        if (array_key_exists($key, $this->columnMap)) {
164
-            return $this->columnMap[$key];
165
-        } else {
166
-            return $key;
167
-        }
168
-    }
169
-
170
-    /**
171
-     * Return the name of the attribute with key.
172
-     *
173
-     * @param string $attributeKey
174
-     *
175
-     * @return string
176
-     */
177
-    protected function getPrefixedAttributeKey(string $attributeKey) : string
178
-    {
179
-        return $this->prefix.$attributeKey;
180
-    }
181
-
182
-    /**
183
-     * Transform attributes into embedded object(s), and
184
-     * match it into the given resultset.
185
-     *
186
-     * @return array
187
-     */
188
-    abstract public function match(array $results) : array;
189
-
190
-    /**
191
-     * Build an embedded object instance.
192
-     *
193
-     * @param array $attributes
194
-     *
195
-     * @return mixed
196
-     */
197
-    protected function buildEmbeddedObject(array $attributes)
198
-    {
199
-        $resultBuilder = new ResultBuilder($this->getRelatedMapper());
200
-
201
-        // TODO : find a way to support eager load within an embedded
202
-        // object.
203
-        $eagerLoads = [];
204
-
205
-        return $resultBuilder->build([$attributes], $eagerLoads)[0];
206
-    }
207
-
208
-    /**
209
-     * Transform embedded object into db column(s).
210
-     *
211
-     * @param mixed $object
212
-     *
213
-     * @return array $columns
214
-     */
215
-    abstract public function normalize($object) : array;
216
-
217
-    /**
218
-     * Return parent mapper.
219
-     *
220
-     * @return Analogue\ORM\System\Mapper
221
-     */
222
-    protected function getParentMapper()
223
-    {
224
-        return Manager::getInstance()->mapper($this->parentClass);
225
-    }
226
-
227
-    /**
228
-     * Return embedded relationship mapper.
229
-     *
230
-     * @return Analogue\ORM\System\Mapper
231
-     */
232
-    protected function getRelatedMapper()
233
-    {
234
-        return Manager::getInstance()->mapper($this->relatedClass);
235
-    }
12
+	/**
13
+	 * The class that embeds the current relation.
14
+	 *
15
+	 * @var string
16
+	 */
17
+	protected $parentClass;
18
+
19
+	/**
20
+	 * The class of the embedded relation.
21
+	 *
22
+	 * @var string
23
+	 */
24
+	protected $relatedClass;
25
+
26
+	/**
27
+	 * The relation attribute on the parent object.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $relation;
32
+
33
+	/**
34
+	 * If set to true, embedded Object's attributes will
35
+	 * be stored as a serialized array in a JSON Column.
36
+	 *
37
+	 * @var bool
38
+	 */
39
+	protected $asArray = false;
40
+
41
+	/**
42
+	 * Prefix on which the object's attributes are saved into
43
+	 * the parent's table. defaults to "<relatedClass>_".
44
+	 *
45
+	 * @var string
46
+	 */
47
+	protected $prefix;
48
+
49
+	/**
50
+	 * Attributes Map allow the calling EntityMap to overrides attributes
51
+	 * on the embedded relation.
52
+	 *
53
+	 * @var array
54
+	 */
55
+	protected $columnMap = [];
56
+
57
+	/**
58
+	 * Wrapper factory.
59
+	 *
60
+	 * @var \Analogue\ORM\System\Wrappers\Factory
61
+	 */
62
+	protected $factory;
63
+
64
+	public function __construct($parent, string $relatedClass, string $relation)
65
+	{
66
+		$this->parentClass = get_class($parent);
67
+		$this->relatedClass = $relatedClass;
68
+		$this->relation = $relation;
69
+		$this->prefix = $relation.'_';
70
+		$this->factory = new Factory();
71
+	}
72
+
73
+	/**
74
+	 * Switch the 'store as array' feature.
75
+	 *
76
+	 * @param bool $storeAsArray
77
+	 *
78
+	 * @return static
79
+	 */
80
+	public function asArray(bool $storeAsArray = true)
81
+	{
82
+		$this->asArray = $storeAsArray;
83
+
84
+		return $this;
85
+	}
86
+
87
+	/**
88
+	 * Set the column map for the embedded relation.
89
+	 *
90
+	 * @param array $columns
91
+	 *
92
+	 * @return static
93
+	 */
94
+	public function setColumnMap(array $columns)
95
+	{
96
+		$this->columnMap = $columns;
97
+
98
+		return $this;
99
+	}
100
+
101
+	/**
102
+	 * Set parent's attribute prefix.
103
+	 *
104
+	 * @param string $prefix
105
+	 *
106
+	 * @return static
107
+	 */
108
+	public function setPrefix(string $prefix)
109
+	{
110
+		$this->prefix = $prefix;
111
+
112
+		return $this;
113
+	}
114
+
115
+	/**
116
+	 * Return parent's attribute prefix.
117
+	 *
118
+	 * @return string
119
+	 */
120
+	public function getPrefix() : string
121
+	{
122
+		return $this->prefix;
123
+	}
124
+
125
+	/**
126
+	 * Get the embedded object's attributes that will be
127
+	 * hydrated using parent's entity attributes.
128
+	 *
129
+	 * @return array
130
+	 */
131
+	protected function getEmbeddedObjectAttributes() : array
132
+	{
133
+		$entityMap = $this->getRelatedMapper()->getEntityMap();
134
+
135
+		$attributes = $entityMap->getAttributes();
136
+		$properties = $entityMap->getProperties();
137
+
138
+		return array_merge($attributes, $properties);
139
+	}
140
+
141
+	/**
142
+	 * Get the corresponding attribute on parent's attributes.
143
+	 *
144
+	 * @param string $key
145
+	 *
146
+	 * @return string
147
+	 */
148
+	protected function getParentAttributeKey($key) : string
149
+	{
150
+		return $this->getPrefixedAttributeKey($this->getMappedParentAttribute($key));
151
+	}
152
+
153
+	/**
154
+	 * Get attribute name from the parent, if a map has been
155
+	 * defined.
156
+	 *
157
+	 * @param srring $attributeKey
158
+	 *
159
+	 * @return string
160
+	 */
161
+	protected function getMappedParentAttribute(string $key) : string
162
+	{
163
+		if (array_key_exists($key, $this->columnMap)) {
164
+			return $this->columnMap[$key];
165
+		} else {
166
+			return $key;
167
+		}
168
+	}
169
+
170
+	/**
171
+	 * Return the name of the attribute with key.
172
+	 *
173
+	 * @param string $attributeKey
174
+	 *
175
+	 * @return string
176
+	 */
177
+	protected function getPrefixedAttributeKey(string $attributeKey) : string
178
+	{
179
+		return $this->prefix.$attributeKey;
180
+	}
181
+
182
+	/**
183
+	 * Transform attributes into embedded object(s), and
184
+	 * match it into the given resultset.
185
+	 *
186
+	 * @return array
187
+	 */
188
+	abstract public function match(array $results) : array;
189
+
190
+	/**
191
+	 * Build an embedded object instance.
192
+	 *
193
+	 * @param array $attributes
194
+	 *
195
+	 * @return mixed
196
+	 */
197
+	protected function buildEmbeddedObject(array $attributes)
198
+	{
199
+		$resultBuilder = new ResultBuilder($this->getRelatedMapper());
200
+
201
+		// TODO : find a way to support eager load within an embedded
202
+		// object.
203
+		$eagerLoads = [];
204
+
205
+		return $resultBuilder->build([$attributes], $eagerLoads)[0];
206
+	}
207
+
208
+	/**
209
+	 * Transform embedded object into db column(s).
210
+	 *
211
+	 * @param mixed $object
212
+	 *
213
+	 * @return array $columns
214
+	 */
215
+	abstract public function normalize($object) : array;
216
+
217
+	/**
218
+	 * Return parent mapper.
219
+	 *
220
+	 * @return Analogue\ORM\System\Mapper
221
+	 */
222
+	protected function getParentMapper()
223
+	{
224
+		return Manager::getInstance()->mapper($this->parentClass);
225
+	}
226
+
227
+	/**
228
+	 * Return embedded relationship mapper.
229
+	 *
230
+	 * @return Analogue\ORM\System\Mapper
231
+	 */
232
+	protected function getRelatedMapper()
233
+	{
234
+		return Manager::getInstance()->mapper($this->relatedClass);
235
+	}
236 236
 }
Please login to merge, or discard this patch.
src/Relationships/EmbedsMany.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
     /**
71 71
      * Transform embedded object into db column(s).
72 72
      *
73
-     * @param mixed $object
73
+     * @param mixed $objects
74 74
      *
75 75
      * @return array $columns
76 76
      */
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
     /**
87 87
      * Normalize object an array containing raw attributes
88 88
      * 
89
-     * @param  mixed  $object 
89
+     * @param  mixed  $objects 
90 90
      * @return array
91 91
      */
92 92
     protected function normalizeAsArray($objects) : array
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -7,108 +7,108 @@
 block discarded – undo
7 7
 
8 8
 class EmbedsMany extends EmbedsOne
9 9
 {
10
-    /**
11
-     * Match a single database row's attributes to a single
12
-     * object, and return the updated attributes.
13
-     *
14
-     * @param array $attributes
15
-     *
16
-     * @return array
17
-     */
18
-    public function matchSingleResult(array $attributes) : array
19
-    {
20
-        $column = $this->relation;
21
-
22
-        if (!$this->asArray) {
23
-            throw new MappingException("column '$column' should be of type array or json");
24
-        }
25
-
26
-        return $this->matchAsArray($attributes);
27
-    }
28
-
29
-    /**
30
-     * Match array attribute from parent to an embedded object,
31
-     * and return the updated attributes.
32
-     *
33
-     * @param array $attributes
34
-     *
35
-     * @return array
36
-     */
37
-    protected function matchAsArray(array $attributes) : array
38
-    {
39
-        // Extract the attributes with the key of the relation,
40
-        // which should be an array.
41
-        $key = $this->relation;
42
-
43
-        if (!array_key_exists($key, $attributes) && !is_array($key)) {
44
-            throw new MappingException("'$key' column should be an array");
45
-        }
46
-
47
-        $attributes[$key] = $this->buildEmbeddedCollection($attributes[$key]);
48
-
49
-        return $attributes;
50
-    }
51
-
52
-    /**
53
-     * Build an embedded collection and returns it.
54
-     *
55
-     * @param array $rows
56
-     *
57
-     * @return Collection
58
-     */
59
-    protected function buildEmbeddedCollection($rows) : Collection
60
-    {
61
-        $items = [];
62
-
63
-        foreach ($rows as $attributes) {
64
-            $items[] = $this->buildEmbeddedObject($attributes);
65
-        }
66
-
67
-        return collect($items);
68
-    }
69
-
70
-    /**
71
-     * Transform embedded object into db column(s).
72
-     *
73
-     * @param mixed $object
74
-     *
75
-     * @return array $columns
76
-     */
77
-    public function normalize($objects) : array
78
-    {
79
-    	if(! $this->asArray) {
80
-    		throw new MappingException("Cannot normalize an embedsMany relation as row columns");
81
-    	}
82
-
83
-    	return $this->normalizeAsArray($objects);
84
-    }
85
-
86
-    /**
87
-     * Normalize object an array containing raw attributes
88
-     * 
89
-     * @param  mixed  $object 
90
-     * @return array
91
-     */
92
-    protected function normalizeAsArray($objects) : array
93
-    {
94
-    	$key = $this->relation;
95
-
96
-    	if(! is_array($objects) && ! $objects instanceof Collection) {
97
-    		throw new MappingException("column '$key' should be of type array or collection");
98
-    	}
99
-
100
-    	if($objects instanceof Collection ) {
101
-    		$objects = $objects->all();
102
-    	}
10
+	/**
11
+	 * Match a single database row's attributes to a single
12
+	 * object, and return the updated attributes.
13
+	 *
14
+	 * @param array $attributes
15
+	 *
16
+	 * @return array
17
+	 */
18
+	public function matchSingleResult(array $attributes) : array
19
+	{
20
+		$column = $this->relation;
21
+
22
+		if (!$this->asArray) {
23
+			throw new MappingException("column '$column' should be of type array or json");
24
+		}
25
+
26
+		return $this->matchAsArray($attributes);
27
+	}
28
+
29
+	/**
30
+	 * Match array attribute from parent to an embedded object,
31
+	 * and return the updated attributes.
32
+	 *
33
+	 * @param array $attributes
34
+	 *
35
+	 * @return array
36
+	 */
37
+	protected function matchAsArray(array $attributes) : array
38
+	{
39
+		// Extract the attributes with the key of the relation,
40
+		// which should be an array.
41
+		$key = $this->relation;
42
+
43
+		if (!array_key_exists($key, $attributes) && !is_array($key)) {
44
+			throw new MappingException("'$key' column should be an array");
45
+		}
46
+
47
+		$attributes[$key] = $this->buildEmbeddedCollection($attributes[$key]);
48
+
49
+		return $attributes;
50
+	}
51
+
52
+	/**
53
+	 * Build an embedded collection and returns it.
54
+	 *
55
+	 * @param array $rows
56
+	 *
57
+	 * @return Collection
58
+	 */
59
+	protected function buildEmbeddedCollection($rows) : Collection
60
+	{
61
+		$items = [];
62
+
63
+		foreach ($rows as $attributes) {
64
+			$items[] = $this->buildEmbeddedObject($attributes);
65
+		}
66
+
67
+		return collect($items);
68
+	}
69
+
70
+	/**
71
+	 * Transform embedded object into db column(s).
72
+	 *
73
+	 * @param mixed $object
74
+	 *
75
+	 * @return array $columns
76
+	 */
77
+	public function normalize($objects) : array
78
+	{
79
+		if(! $this->asArray) {
80
+			throw new MappingException("Cannot normalize an embedsMany relation as row columns");
81
+		}
82
+
83
+		return $this->normalizeAsArray($objects);
84
+	}
85
+
86
+	/**
87
+	 * Normalize object an array containing raw attributes
88
+	 * 
89
+	 * @param  mixed  $object 
90
+	 * @return array
91
+	 */
92
+	protected function normalizeAsArray($objects) : array
93
+	{
94
+		$key = $this->relation;
95
+
96
+		if(! is_array($objects) && ! $objects instanceof Collection) {
97
+			throw new MappingException("column '$key' should be of type array or collection");
98
+		}
99
+
100
+		if($objects instanceof Collection ) {
101
+			$objects = $objects->all();
102
+		}
103 103
     	
104
-    	$normalizedObjects = [];
104
+		$normalizedObjects = [];
105 105
 
106
-    	foreach($objects as $object) {
107
-    		$wrapper = $this->factory->make($object);	
108
-    		$normalizedObjects[] = $wrapper->getEntityAttributes();
109
-    	}
106
+		foreach($objects as $object) {
107
+			$wrapper = $this->factory->make($object);	
108
+			$normalizedObjects[] = $wrapper->getEntityAttributes();
109
+		}
110 110
         
111 111
 
112
-        return [$key => $normalizedObjects];
113
-    }
112
+		return [$key => $normalizedObjects];
113
+	}
114 114
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
      */
77 77
     public function normalize($objects) : array
78 78
     {
79
-    	if(! $this->asArray) {
79
+    	if (!$this->asArray) {
80 80
     		throw new MappingException("Cannot normalize an embedsMany relation as row columns");
81 81
     	}
82 82
 
@@ -93,17 +93,17 @@  discard block
 block discarded – undo
93 93
     {
94 94
     	$key = $this->relation;
95 95
 
96
-    	if(! is_array($objects) && ! $objects instanceof Collection) {
96
+    	if (!is_array($objects) && !$objects instanceof Collection) {
97 97
     		throw new MappingException("column '$key' should be of type array or collection");
98 98
     	}
99 99
 
100
-    	if($objects instanceof Collection ) {
100
+    	if ($objects instanceof Collection) {
101 101
     		$objects = $objects->all();
102 102
     	}
103 103
     	
104 104
     	$normalizedObjects = [];
105 105
 
106
-    	foreach($objects as $object) {
106
+    	foreach ($objects as $object) {
107 107
     		$wrapper = $this->factory->make($object);	
108 108
     		$normalizedObjects[] = $wrapper->getEntityAttributes();
109 109
     	}
Please login to merge, or discard this patch.
src/System/Query.php 1 patch
Indentation   +673 added lines, -673 removed lines patch added patch discarded remove patch
@@ -20,677 +20,677 @@
 block discarded – undo
20 20
  */
21 21
 class Query
22 22
 {
23
-    /**
24
-     * Mapper Instance.
25
-     *
26
-     * @var \Analogue\ORM\System\Mapper
27
-     */
28
-    protected $mapper;
29
-
30
-    /**
31
-     * DB Adatper.
32
-     *
33
-     * @var \Analogue\ORM\Drivers\DBAdapter
34
-     */
35
-    protected $adapter;
36
-
37
-    /**
38
-     * Query Builder Instance.
39
-     *
40
-     * @var \Analogue\ORM\Drivers\QueryAdapter|\Analogue\ORM\Drivers\IlluminateQueryAdapter
41
-     */
42
-    protected $query;
43
-
44
-    /**
45
-     * Entity Map Instance.
46
-     *
47
-     * @var \Analogue\ORM\EntityMap
48
-     */
49
-    protected $entityMap;
50
-
51
-    /**
52
-     * The relationships that should be eager loaded.
53
-     *
54
-     * @var array
55
-     */
56
-    protected $eagerLoad = [];
57
-
58
-    /**
59
-     * All of the registered builder macros.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $macros = [];
64
-
65
-    /**
66
-     * The methods that should be returned from query builder.
67
-     *
68
-     * @var array
69
-     */
70
-    protected $passthru = [
71
-        'toSql',
72
-        'lists',
73
-        'pluck',
74
-        'count',
75
-        'min',
76
-        'max',
77
-        'avg',
78
-        'sum',
79
-        'exists',
80
-        'getBindings',
81
-    ];
82
-
83
-    /**
84
-     * Query Builder Blacklist.
85
-     */
86
-    protected $blacklist = [
87
-        'insert',
88
-        'insertGetId',
89
-        'lock',
90
-        'lockForUpdate',
91
-        'sharedLock',
92
-        'update',
93
-        'increment',
94
-        'decrement',
95
-        'delete',
96
-        'truncate',
97
-        'raw',
98
-    ];
99
-
100
-    /**
101
-     * Create a new Analogue Query Builder instance.
102
-     *
103
-     * @param Mapper    $mapper
104
-     * @param DBAdapter $adapter
105
-     */
106
-    public function __construct(Mapper $mapper, DBAdapter $adapter)
107
-    {
108
-        $this->mapper = $mapper;
109
-
110
-        $this->adapter = $adapter;
111
-
112
-        $this->entityMap = $mapper->getEntityMap();
113
-
114
-        // Specify the table to work on
115
-        $this->query = $adapter->getQuery()->from($this->entityMap->getTable());
116
-
117
-        $this->with($this->entityMap->getEagerloadedRelationships());
118
-    }
119
-
120
-    /**
121
-     * Run the query and return the result.
122
-     *
123
-     * @param array $columns
124
-     *
125
-     * @return \Analogue\ORM\EntityCollection
126
-     */
127
-    public function get($columns = ['*']) : Collection
128
-    {
129
-        return $this->getEntities($columns);
130
-    }
131
-
132
-    /**
133
-     * Find an entity by its primary key.
134
-     *
135
-     * @param string|int $id
136
-     * @param array      $columns
137
-     *
138
-     * @return \Analogue\ORM\Mappable
139
-     */
140
-    public function find($id, $columns = ['*'])
141
-    {
142
-        if (is_array($id)) {
143
-            return $this->findMany($id, $columns);
144
-        }
145
-
146
-        $this->query->where($this->entityMap->getKeyName(), '=', $id);
147
-
148
-        return $this->first($columns);
149
-    }
150
-
151
-    /**
152
-     * Find many entities by their primary keys.
153
-     *
154
-     * @param array $id
155
-     * @param array $columns
156
-     *
157
-     * @return EntityCollection
158
-     */
159
-    public function findMany($id, $columns = ['*'])
160
-    {
161
-        if (empty($id)) {
162
-            return new EntityCollection();
163
-        }
164
-
165
-        $this->query->whereIn($this->entityMap->getKeyName(), $id);
166
-
167
-        return $this->get($columns);
168
-    }
169
-
170
-    /**
171
-     * Find a model by its primary key or throw an exception.
172
-     *
173
-     * @param mixed $id
174
-     * @param array $columns
175
-     *
176
-     * @throws \Analogue\ORM\Exceptions\EntityNotFoundException
177
-     *
178
-     * @return mixed|self
179
-     */
180
-    public function findOrFail($id, $columns = ['*'])
181
-    {
182
-        if (!is_null($entity = $this->find($id, $columns))) {
183
-            return $entity;
184
-        }
185
-
186
-        throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
187
-    }
188
-
189
-    /**
190
-     * Execute the query and get the first result.
191
-     *
192
-     * @param array $columns
193
-     *
194
-     * @return \Analogue\ORM\Entity
195
-     */
196
-    public function first($columns = ['*'])
197
-    {
198
-        return $this->take(1)->get($columns)->first();
199
-    }
200
-
201
-    /**
202
-     * Execute the query and get the first result or throw an exception.
203
-     *
204
-     * @param array $columns
205
-     *
206
-     * @throws EntityNotFoundException
207
-     *
208
-     * @return \Analogue\ORM\Entity
209
-     */
210
-    public function firstOrFail($columns = ['*'])
211
-    {
212
-        if (!is_null($entity = $this->first($columns))) {
213
-            return $entity;
214
-        }
215
-
216
-        throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
217
-    }
218
-
219
-    /**
220
-     * Pluck a single column from the database.
221
-     *
222
-     * @param string $column
223
-     *
224
-     * @return mixed
225
-     */
226
-    public function pluck($column)
227
-    {
228
-        $result = $this->first([$column]);
229
-
230
-        if ($result) {
231
-            return $result->{$column};
232
-        }
233
-    }
234
-
235
-    /**
236
-     * Chunk the results of the query.
237
-     *
238
-     * @param int      $count
239
-     * @param callable $callback
240
-     *
241
-     * @return void
242
-     */
243
-    public function chunk($count, callable $callback)
244
-    {
245
-        $results = $this->forPage($page = 1, $count)->get();
246
-
247
-        while (count($results) > 0) {
248
-            // On each chunk result set, we will pass them to the callback and then let the
249
-            // developer take care of everything within the callback, which allows us to
250
-            // keep the memory low for spinning through large result sets for working.
251
-            call_user_func($callback, $results);
252
-
253
-            $page++;
254
-
255
-            $results = $this->forPage($page, $count)->get();
256
-        }
257
-    }
258
-
259
-    /**
260
-     * Get an array with the values of a given column.
261
-     *
262
-     * @param string $column
263
-     * @param string $key
264
-     *
265
-     * @return array
266
-     */
267
-    public function lists($column, $key = null)
268
-    {
269
-        return $this->query->pluck($column, $key);
270
-    }
271
-
272
-    /**
273
-     * Get a paginator for the "select" statement.
274
-     *
275
-     * @param int   $perPage
276
-     * @param array $columns
277
-     *
278
-     * @return LengthAwarePaginator
279
-     */
280
-    public function paginate($perPage = null, $columns = ['*'])
281
-    {
282
-        $total = $this->query->getCountForPagination();
283
-
284
-        $this->query->forPage(
285
-            $page = Paginator::resolveCurrentPage(),
286
-            $perPage = $perPage ?: $this->entityMap->getPerPage()
287
-        );
288
-
289
-        return new LengthAwarePaginator($this->get($columns)->all(), $total, $perPage, $page, [
290
-            'path' => Paginator::resolveCurrentPath(),
291
-        ]);
292
-    }
293
-
294
-    /**
295
-     * Get a paginator for a grouped statement.
296
-     *
297
-     * @param \Illuminate\Pagination\Factory $paginator
298
-     * @param int                            $perPage
299
-     * @param array                          $columns
300
-     *
301
-     * @return \Illuminate\Pagination\Paginator
302
-     */
303
-    protected function groupedPaginate($paginator, $perPage, $columns)
304
-    {
305
-        $results = $this->get($columns)->all();
306
-
307
-        return $this->query->buildRawPaginator($paginator, $results, $perPage);
308
-    }
309
-
310
-    /**
311
-     * Get a paginator for an ungrouped statement.
312
-     *
313
-     * @param \Illuminate\Pagination\Factory $paginator
314
-     * @param int                            $perPage
315
-     * @param array                          $columns
316
-     *
317
-     * @return \Illuminate\Pagination\Paginator
318
-     */
319
-    protected function ungroupedPaginate($paginator, $perPage, $columns)
320
-    {
321
-        $total = $this->query->getPaginationCount();
322
-
323
-        // Once we have the paginator we need to set the limit and offset values for
324
-        // the query so we can get the properly paginated items. Once we have an
325
-        // array of items we can create the paginator instances for the items.
326
-        $page = $paginator->getCurrentPage($total);
327
-
328
-        $this->query->forPage($page, $perPage);
329
-
330
-        return $paginator->make($this->get($columns)->all(), $total, $perPage);
331
-    }
332
-
333
-    /**
334
-     * Paginate the given query into a simple paginator.
335
-     *
336
-     * @param int   $perPage
337
-     * @param array $columns
338
-     *
339
-     * @return \Illuminate\Contracts\Pagination\Paginator
340
-     */
341
-    public function simplePaginate($perPage = null, $columns = ['*'])
342
-    {
343
-        $page = Paginator::resolveCurrentPage();
344
-
345
-        $perPage = $perPage ?: $this->entityMap->getPerPage();
346
-
347
-        $this->skip(($page - 1) * $perPage)->take($perPage + 1);
348
-
349
-        return new Paginator($this->get($columns)->all(), $perPage, $page, ['path' => Paginator::resolveCurrentPath()]);
350
-    }
351
-
352
-    /**
353
-     * Add a basic where clause to the query.
354
-     *
355
-     * @param string $column
356
-     * @param string $operator
357
-     * @param mixed  $value
358
-     * @param string $boolean
359
-     *
360
-     * @return $this
361
-     */
362
-    public function where($column, $operator = null, $value = null, $boolean = 'and')
363
-    {
364
-        if ($column instanceof Closure) {
365
-            $query = $this->newQueryWithoutScopes();
366
-
367
-            call_user_func($column, $query);
368
-
369
-            $this->query->addNestedWhereQuery($query->getQuery(), $boolean);
370
-        } else {
371
-            call_user_func_array([$this->query, 'where'], func_get_args());
372
-        }
373
-
374
-        return $this;
375
-    }
376
-
377
-    /**
378
-     * Add an "or where" clause to the query.
379
-     *
380
-     * @param string $column
381
-     * @param string $operator
382
-     * @param mixed  $value
383
-     *
384
-     * @return \Analogue\ORM\System\Query
385
-     */
386
-    public function orWhere($column, $operator = null, $value = null)
387
-    {
388
-        return $this->where($column, $operator, $value, 'or');
389
-    }
390
-
391
-    /**
392
-     * Add a relationship count condition to the query.
393
-     *
394
-     * @param string   $relation
395
-     * @param string   $operator
396
-     * @param int      $count
397
-     * @param string   $boolean
398
-     * @param \Closure $callback
399
-     *
400
-     * @return \Analogue\ORM\System\Query
401
-     */
402
-    public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
403
-    {
404
-        $entity = $this->mapper->newInstance();
405
-
406
-        $relation = $this->getHasRelationQuery($relation, $entity);
407
-
408
-        $query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);
409
-
410
-        if ($callback) {
411
-            call_user_func($callback, $query);
412
-        }
413
-
414
-        return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
415
-    }
416
-
417
-    /**
418
-     * Add a relationship count condition to the query with where clauses.
419
-     *
420
-     * @param string   $relation
421
-     * @param \Closure $callback
422
-     * @param string   $operator
423
-     * @param int      $count
424
-     *
425
-     * @return \Analogue\ORM\System\Query
426
-     */
427
-    public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
428
-    {
429
-        return $this->has($relation, $operator, $count, 'and', $callback);
430
-    }
431
-
432
-    /**
433
-     * Add a relationship count condition to the query with an "or".
434
-     *
435
-     * @param string $relation
436
-     * @param string $operator
437
-     * @param int    $count
438
-     *
439
-     * @return \Analogue\ORM\System\Query
440
-     */
441
-    public function orHas($relation, $operator = '>=', $count = 1)
442
-    {
443
-        return $this->has($relation, $operator, $count, 'or');
444
-    }
445
-
446
-    /**
447
-     * Add a relationship count condition to the query with where clauses and an "or".
448
-     *
449
-     * @param string   $relation
450
-     * @param \Closure $callback
451
-     * @param string   $operator
452
-     * @param int      $count
453
-     *
454
-     * @return \Analogue\ORM\System\Query
455
-     */
456
-    public function orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
457
-    {
458
-        return $this->has($relation, $operator, $count, 'or', $callback);
459
-    }
460
-
461
-    /**
462
-     * Add the "has" condition where clause to the query.
463
-     *
464
-     * @param \Analogue\ORM\System\Query               $hasQuery
465
-     * @param \Analogue\ORM\Relationships\Relationship $relation
466
-     * @param string                                   $operator
467
-     * @param int                                      $count
468
-     * @param string                                   $boolean
469
-     *
470
-     * @return \Analogue\ORM\System\Query
471
-     */
472
-    protected function addHasWhere(Query $hasQuery, Relationship $relation, $operator, $count, $boolean)
473
-    {
474
-        $this->mergeWheresToHas($hasQuery, $relation);
475
-
476
-        if (is_numeric($count)) {
477
-            $count = new Expression($count);
478
-        }
479
-
480
-        return $this->where(new Expression('('.$hasQuery->toSql().')'), $operator, $count, $boolean);
481
-    }
482
-
483
-    /**
484
-     * Merge the "wheres" from a relation query to a has query.
485
-     *
486
-     * @param \Analogue\ORM\System\Query               $hasQuery
487
-     * @param \Analogue\ORM\Relationships\Relationship $relation
488
-     *
489
-     * @return void
490
-     */
491
-    protected function mergeWheresToHas(Query $hasQuery, Relationship $relation)
492
-    {
493
-        // Here we have the "has" query and the original relation. We need to copy over any
494
-        // where clauses the developer may have put in the relationship function over to
495
-        // the has query, and then copy the bindings from the "has" query to the main.
496
-        $relationQuery = $relation->getBaseQuery();
497
-
498
-        $hasQuery->mergeWheres(
499
-            $relationQuery->wheres, $relationQuery->getBindings()
500
-        );
501
-
502
-        $this->query->mergeBindings($hasQuery->getQuery());
503
-    }
504
-
505
-    /**
506
-     * Get the "has relation" base query instance.
507
-     *
508
-     * @param string $relation
509
-     * @param        $entity
510
-     *
511
-     * @return \Analogue\ORM\System\Query
512
-     */
513
-    protected function getHasRelationQuery($relation, $entity)
514
-    {
515
-        return Relationship::noConstraints(function () use ($relation, $entity) {
516
-            return $this->entityMap->$relation($entity);
517
-        });
518
-    }
519
-
520
-    /**
521
-     * Get the table for the current query object.
522
-     *
523
-     * @return string
524
-     */
525
-    public function getTable()
526
-    {
527
-        return $this->entityMap->getTable();
528
-    }
529
-
530
-    /**
531
-     * Set the relationships that should be eager loaded.
532
-     *
533
-     * @param mixed $relations
534
-     *
535
-     * @return $this
536
-     */
537
-    public function with($relations)
538
-    {
539
-        if (is_string($relations)) {
540
-            $relations = func_get_args();
541
-        }
542
-
543
-        $this->eagerLoad = array_merge($this->eagerLoad, $relations);
544
-
545
-        return $this;
546
-    }
547
-
548
-    /**
549
-     * Get the relationships being eagerly loaded.
550
-     *
551
-     * @return array
552
-     */
553
-    public function getEagerLoads()
554
-    {
555
-        return $this->eagerLoad;
556
-    }
557
-
558
-    /**
559
-     * Add the Entity primary key if not in requested columns.
560
-     *
561
-     * @param array $columns
562
-     *
563
-     * @return array
564
-     */
565
-    protected function enforceIdColumn($columns)
566
-    {
567
-        if (!in_array($this->entityMap->getKeyName(), $columns)) {
568
-            $columns[] = $this->entityMap->getKeyName();
569
-        }
570
-
571
-        return $columns;
572
-    }
573
-
574
-    /**
575
-     * Get the hydrated models without eager loading.
576
-     *
577
-     * @param array $columns
578
-     *
579
-     * @return \Analogue\ORM\EntityCollection
580
-     */
581
-    public function getEntities($columns = ['*'])
582
-    {
583
-        // As we need the primary key to feed the
584
-        // entity cache, we need it loaded on each
585
-        // request
586
-        $columns = $this->enforceIdColumn($columns);
587
-
588
-        // Run the query
589
-        $results = $this->query->get($columns);
590
-
591
-        // Pass result set to the mapper and return the EntityCollection
592
-        return $this->mapper->map($results, $this->getEagerLoads());
593
-
594
-        // Create a result builder.
595
-        //$builder = new ResultBuilder($this->mapper);
596
-
597
-        //return $builder->build($results, $this->getEagerLoads());
598
-    }
599
-
600
-    /**
601
-     * Extend the builder with a given callback.
602
-     *
603
-     * @param string   $name
604
-     * @param \Closure $callback
605
-     *
606
-     * @return void
607
-     */
608
-    public function macro($name, Closure $callback)
609
-    {
610
-        $this->macros[$name] = $callback;
611
-    }
612
-
613
-    /**
614
-     * Get the given macro by name.
615
-     *
616
-     * @param string $name
617
-     *
618
-     * @return \Closure
619
-     */
620
-    public function getMacro($name)
621
-    {
622
-        return array_get($this->macros, $name);
623
-    }
624
-
625
-    /**
626
-     * Get a new query builder for the model's table.
627
-     *
628
-     * @return \Analogue\ORM\System\Query
629
-     */
630
-    public function newQuery()
631
-    {
632
-        $builder = new self($this->mapper, $this->adapter);
633
-
634
-        return $this->applyGlobalScopes($builder);
635
-    }
636
-
637
-    /**
638
-     * Get a new query builder without any scope applied.
639
-     *
640
-     * @return \Analogue\ORM\System\Query
641
-     */
642
-    public function newQueryWithoutScopes()
643
-    {
644
-        return new self($this->mapper, $this->adapter);
645
-    }
646
-
647
-    /**
648
-     * Get the Mapper instance for this Query Builder.
649
-     *
650
-     * @return \Analogue\ORM\System\Mapper
651
-     */
652
-    public function getMapper()
653
-    {
654
-        return $this->mapper;
655
-    }
656
-
657
-    /**
658
-     * Get the underlying query adapter.
659
-     *
660
-     * (REFACTOR: this method should move out, we need to provide the client classes
661
-     * with the adapter instead.)
662
-     *
663
-     * @return \Analogue\ORM\Drivers\QueryAdapter|\Analogue\ORM\Drivers\IlluminateQueryAdapter
664
-     */
665
-    public function getQuery()
666
-    {
667
-        return $this->query;
668
-    }
669
-
670
-    /**
671
-     * Dynamically handle calls into the query instance.
672
-     *
673
-     * @param string $method
674
-     * @param array  $parameters
675
-     *
676
-     * @throws Exception
677
-     *
678
-     * @return mixed
679
-     */
680
-    public function __call($method, $parameters)
681
-    {
682
-        if (isset($this->macros[$method])) {
683
-            array_unshift($parameters, $this);
684
-
685
-            return call_user_func_array($this->macros[$method], $parameters);
686
-        }
687
-
688
-        if (in_array($method, $this->blacklist)) {
689
-            throw new Exception("Method $method doesn't exist");
690
-        }
691
-
692
-        $result = call_user_func_array([$this->query, $method], $parameters);
693
-
694
-        return in_array($method, $this->passthru) ? $result : $this;
695
-    }
23
+	/**
24
+	 * Mapper Instance.
25
+	 *
26
+	 * @var \Analogue\ORM\System\Mapper
27
+	 */
28
+	protected $mapper;
29
+
30
+	/**
31
+	 * DB Adatper.
32
+	 *
33
+	 * @var \Analogue\ORM\Drivers\DBAdapter
34
+	 */
35
+	protected $adapter;
36
+
37
+	/**
38
+	 * Query Builder Instance.
39
+	 *
40
+	 * @var \Analogue\ORM\Drivers\QueryAdapter|\Analogue\ORM\Drivers\IlluminateQueryAdapter
41
+	 */
42
+	protected $query;
43
+
44
+	/**
45
+	 * Entity Map Instance.
46
+	 *
47
+	 * @var \Analogue\ORM\EntityMap
48
+	 */
49
+	protected $entityMap;
50
+
51
+	/**
52
+	 * The relationships that should be eager loaded.
53
+	 *
54
+	 * @var array
55
+	 */
56
+	protected $eagerLoad = [];
57
+
58
+	/**
59
+	 * All of the registered builder macros.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $macros = [];
64
+
65
+	/**
66
+	 * The methods that should be returned from query builder.
67
+	 *
68
+	 * @var array
69
+	 */
70
+	protected $passthru = [
71
+		'toSql',
72
+		'lists',
73
+		'pluck',
74
+		'count',
75
+		'min',
76
+		'max',
77
+		'avg',
78
+		'sum',
79
+		'exists',
80
+		'getBindings',
81
+	];
82
+
83
+	/**
84
+	 * Query Builder Blacklist.
85
+	 */
86
+	protected $blacklist = [
87
+		'insert',
88
+		'insertGetId',
89
+		'lock',
90
+		'lockForUpdate',
91
+		'sharedLock',
92
+		'update',
93
+		'increment',
94
+		'decrement',
95
+		'delete',
96
+		'truncate',
97
+		'raw',
98
+	];
99
+
100
+	/**
101
+	 * Create a new Analogue Query Builder instance.
102
+	 *
103
+	 * @param Mapper    $mapper
104
+	 * @param DBAdapter $adapter
105
+	 */
106
+	public function __construct(Mapper $mapper, DBAdapter $adapter)
107
+	{
108
+		$this->mapper = $mapper;
109
+
110
+		$this->adapter = $adapter;
111
+
112
+		$this->entityMap = $mapper->getEntityMap();
113
+
114
+		// Specify the table to work on
115
+		$this->query = $adapter->getQuery()->from($this->entityMap->getTable());
116
+
117
+		$this->with($this->entityMap->getEagerloadedRelationships());
118
+	}
119
+
120
+	/**
121
+	 * Run the query and return the result.
122
+	 *
123
+	 * @param array $columns
124
+	 *
125
+	 * @return \Analogue\ORM\EntityCollection
126
+	 */
127
+	public function get($columns = ['*']) : Collection
128
+	{
129
+		return $this->getEntities($columns);
130
+	}
131
+
132
+	/**
133
+	 * Find an entity by its primary key.
134
+	 *
135
+	 * @param string|int $id
136
+	 * @param array      $columns
137
+	 *
138
+	 * @return \Analogue\ORM\Mappable
139
+	 */
140
+	public function find($id, $columns = ['*'])
141
+	{
142
+		if (is_array($id)) {
143
+			return $this->findMany($id, $columns);
144
+		}
145
+
146
+		$this->query->where($this->entityMap->getKeyName(), '=', $id);
147
+
148
+		return $this->first($columns);
149
+	}
150
+
151
+	/**
152
+	 * Find many entities by their primary keys.
153
+	 *
154
+	 * @param array $id
155
+	 * @param array $columns
156
+	 *
157
+	 * @return EntityCollection
158
+	 */
159
+	public function findMany($id, $columns = ['*'])
160
+	{
161
+		if (empty($id)) {
162
+			return new EntityCollection();
163
+		}
164
+
165
+		$this->query->whereIn($this->entityMap->getKeyName(), $id);
166
+
167
+		return $this->get($columns);
168
+	}
169
+
170
+	/**
171
+	 * Find a model by its primary key or throw an exception.
172
+	 *
173
+	 * @param mixed $id
174
+	 * @param array $columns
175
+	 *
176
+	 * @throws \Analogue\ORM\Exceptions\EntityNotFoundException
177
+	 *
178
+	 * @return mixed|self
179
+	 */
180
+	public function findOrFail($id, $columns = ['*'])
181
+	{
182
+		if (!is_null($entity = $this->find($id, $columns))) {
183
+			return $entity;
184
+		}
185
+
186
+		throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
187
+	}
188
+
189
+	/**
190
+	 * Execute the query and get the first result.
191
+	 *
192
+	 * @param array $columns
193
+	 *
194
+	 * @return \Analogue\ORM\Entity
195
+	 */
196
+	public function first($columns = ['*'])
197
+	{
198
+		return $this->take(1)->get($columns)->first();
199
+	}
200
+
201
+	/**
202
+	 * Execute the query and get the first result or throw an exception.
203
+	 *
204
+	 * @param array $columns
205
+	 *
206
+	 * @throws EntityNotFoundException
207
+	 *
208
+	 * @return \Analogue\ORM\Entity
209
+	 */
210
+	public function firstOrFail($columns = ['*'])
211
+	{
212
+		if (!is_null($entity = $this->first($columns))) {
213
+			return $entity;
214
+		}
215
+
216
+		throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
217
+	}
218
+
219
+	/**
220
+	 * Pluck a single column from the database.
221
+	 *
222
+	 * @param string $column
223
+	 *
224
+	 * @return mixed
225
+	 */
226
+	public function pluck($column)
227
+	{
228
+		$result = $this->first([$column]);
229
+
230
+		if ($result) {
231
+			return $result->{$column};
232
+		}
233
+	}
234
+
235
+	/**
236
+	 * Chunk the results of the query.
237
+	 *
238
+	 * @param int      $count
239
+	 * @param callable $callback
240
+	 *
241
+	 * @return void
242
+	 */
243
+	public function chunk($count, callable $callback)
244
+	{
245
+		$results = $this->forPage($page = 1, $count)->get();
246
+
247
+		while (count($results) > 0) {
248
+			// On each chunk result set, we will pass them to the callback and then let the
249
+			// developer take care of everything within the callback, which allows us to
250
+			// keep the memory low for spinning through large result sets for working.
251
+			call_user_func($callback, $results);
252
+
253
+			$page++;
254
+
255
+			$results = $this->forPage($page, $count)->get();
256
+		}
257
+	}
258
+
259
+	/**
260
+	 * Get an array with the values of a given column.
261
+	 *
262
+	 * @param string $column
263
+	 * @param string $key
264
+	 *
265
+	 * @return array
266
+	 */
267
+	public function lists($column, $key = null)
268
+	{
269
+		return $this->query->pluck($column, $key);
270
+	}
271
+
272
+	/**
273
+	 * Get a paginator for the "select" statement.
274
+	 *
275
+	 * @param int   $perPage
276
+	 * @param array $columns
277
+	 *
278
+	 * @return LengthAwarePaginator
279
+	 */
280
+	public function paginate($perPage = null, $columns = ['*'])
281
+	{
282
+		$total = $this->query->getCountForPagination();
283
+
284
+		$this->query->forPage(
285
+			$page = Paginator::resolveCurrentPage(),
286
+			$perPage = $perPage ?: $this->entityMap->getPerPage()
287
+		);
288
+
289
+		return new LengthAwarePaginator($this->get($columns)->all(), $total, $perPage, $page, [
290
+			'path' => Paginator::resolveCurrentPath(),
291
+		]);
292
+	}
293
+
294
+	/**
295
+	 * Get a paginator for a grouped statement.
296
+	 *
297
+	 * @param \Illuminate\Pagination\Factory $paginator
298
+	 * @param int                            $perPage
299
+	 * @param array                          $columns
300
+	 *
301
+	 * @return \Illuminate\Pagination\Paginator
302
+	 */
303
+	protected function groupedPaginate($paginator, $perPage, $columns)
304
+	{
305
+		$results = $this->get($columns)->all();
306
+
307
+		return $this->query->buildRawPaginator($paginator, $results, $perPage);
308
+	}
309
+
310
+	/**
311
+	 * Get a paginator for an ungrouped statement.
312
+	 *
313
+	 * @param \Illuminate\Pagination\Factory $paginator
314
+	 * @param int                            $perPage
315
+	 * @param array                          $columns
316
+	 *
317
+	 * @return \Illuminate\Pagination\Paginator
318
+	 */
319
+	protected function ungroupedPaginate($paginator, $perPage, $columns)
320
+	{
321
+		$total = $this->query->getPaginationCount();
322
+
323
+		// Once we have the paginator we need to set the limit and offset values for
324
+		// the query so we can get the properly paginated items. Once we have an
325
+		// array of items we can create the paginator instances for the items.
326
+		$page = $paginator->getCurrentPage($total);
327
+
328
+		$this->query->forPage($page, $perPage);
329
+
330
+		return $paginator->make($this->get($columns)->all(), $total, $perPage);
331
+	}
332
+
333
+	/**
334
+	 * Paginate the given query into a simple paginator.
335
+	 *
336
+	 * @param int   $perPage
337
+	 * @param array $columns
338
+	 *
339
+	 * @return \Illuminate\Contracts\Pagination\Paginator
340
+	 */
341
+	public function simplePaginate($perPage = null, $columns = ['*'])
342
+	{
343
+		$page = Paginator::resolveCurrentPage();
344
+
345
+		$perPage = $perPage ?: $this->entityMap->getPerPage();
346
+
347
+		$this->skip(($page - 1) * $perPage)->take($perPage + 1);
348
+
349
+		return new Paginator($this->get($columns)->all(), $perPage, $page, ['path' => Paginator::resolveCurrentPath()]);
350
+	}
351
+
352
+	/**
353
+	 * Add a basic where clause to the query.
354
+	 *
355
+	 * @param string $column
356
+	 * @param string $operator
357
+	 * @param mixed  $value
358
+	 * @param string $boolean
359
+	 *
360
+	 * @return $this
361
+	 */
362
+	public function where($column, $operator = null, $value = null, $boolean = 'and')
363
+	{
364
+		if ($column instanceof Closure) {
365
+			$query = $this->newQueryWithoutScopes();
366
+
367
+			call_user_func($column, $query);
368
+
369
+			$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
370
+		} else {
371
+			call_user_func_array([$this->query, 'where'], func_get_args());
372
+		}
373
+
374
+		return $this;
375
+	}
376
+
377
+	/**
378
+	 * Add an "or where" clause to the query.
379
+	 *
380
+	 * @param string $column
381
+	 * @param string $operator
382
+	 * @param mixed  $value
383
+	 *
384
+	 * @return \Analogue\ORM\System\Query
385
+	 */
386
+	public function orWhere($column, $operator = null, $value = null)
387
+	{
388
+		return $this->where($column, $operator, $value, 'or');
389
+	}
390
+
391
+	/**
392
+	 * Add a relationship count condition to the query.
393
+	 *
394
+	 * @param string   $relation
395
+	 * @param string   $operator
396
+	 * @param int      $count
397
+	 * @param string   $boolean
398
+	 * @param \Closure $callback
399
+	 *
400
+	 * @return \Analogue\ORM\System\Query
401
+	 */
402
+	public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
403
+	{
404
+		$entity = $this->mapper->newInstance();
405
+
406
+		$relation = $this->getHasRelationQuery($relation, $entity);
407
+
408
+		$query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);
409
+
410
+		if ($callback) {
411
+			call_user_func($callback, $query);
412
+		}
413
+
414
+		return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
415
+	}
416
+
417
+	/**
418
+	 * Add a relationship count condition to the query with where clauses.
419
+	 *
420
+	 * @param string   $relation
421
+	 * @param \Closure $callback
422
+	 * @param string   $operator
423
+	 * @param int      $count
424
+	 *
425
+	 * @return \Analogue\ORM\System\Query
426
+	 */
427
+	public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
428
+	{
429
+		return $this->has($relation, $operator, $count, 'and', $callback);
430
+	}
431
+
432
+	/**
433
+	 * Add a relationship count condition to the query with an "or".
434
+	 *
435
+	 * @param string $relation
436
+	 * @param string $operator
437
+	 * @param int    $count
438
+	 *
439
+	 * @return \Analogue\ORM\System\Query
440
+	 */
441
+	public function orHas($relation, $operator = '>=', $count = 1)
442
+	{
443
+		return $this->has($relation, $operator, $count, 'or');
444
+	}
445
+
446
+	/**
447
+	 * Add a relationship count condition to the query with where clauses and an "or".
448
+	 *
449
+	 * @param string   $relation
450
+	 * @param \Closure $callback
451
+	 * @param string   $operator
452
+	 * @param int      $count
453
+	 *
454
+	 * @return \Analogue\ORM\System\Query
455
+	 */
456
+	public function orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
457
+	{
458
+		return $this->has($relation, $operator, $count, 'or', $callback);
459
+	}
460
+
461
+	/**
462
+	 * Add the "has" condition where clause to the query.
463
+	 *
464
+	 * @param \Analogue\ORM\System\Query               $hasQuery
465
+	 * @param \Analogue\ORM\Relationships\Relationship $relation
466
+	 * @param string                                   $operator
467
+	 * @param int                                      $count
468
+	 * @param string                                   $boolean
469
+	 *
470
+	 * @return \Analogue\ORM\System\Query
471
+	 */
472
+	protected function addHasWhere(Query $hasQuery, Relationship $relation, $operator, $count, $boolean)
473
+	{
474
+		$this->mergeWheresToHas($hasQuery, $relation);
475
+
476
+		if (is_numeric($count)) {
477
+			$count = new Expression($count);
478
+		}
479
+
480
+		return $this->where(new Expression('('.$hasQuery->toSql().')'), $operator, $count, $boolean);
481
+	}
482
+
483
+	/**
484
+	 * Merge the "wheres" from a relation query to a has query.
485
+	 *
486
+	 * @param \Analogue\ORM\System\Query               $hasQuery
487
+	 * @param \Analogue\ORM\Relationships\Relationship $relation
488
+	 *
489
+	 * @return void
490
+	 */
491
+	protected function mergeWheresToHas(Query $hasQuery, Relationship $relation)
492
+	{
493
+		// Here we have the "has" query and the original relation. We need to copy over any
494
+		// where clauses the developer may have put in the relationship function over to
495
+		// the has query, and then copy the bindings from the "has" query to the main.
496
+		$relationQuery = $relation->getBaseQuery();
497
+
498
+		$hasQuery->mergeWheres(
499
+			$relationQuery->wheres, $relationQuery->getBindings()
500
+		);
501
+
502
+		$this->query->mergeBindings($hasQuery->getQuery());
503
+	}
504
+
505
+	/**
506
+	 * Get the "has relation" base query instance.
507
+	 *
508
+	 * @param string $relation
509
+	 * @param        $entity
510
+	 *
511
+	 * @return \Analogue\ORM\System\Query
512
+	 */
513
+	protected function getHasRelationQuery($relation, $entity)
514
+	{
515
+		return Relationship::noConstraints(function () use ($relation, $entity) {
516
+			return $this->entityMap->$relation($entity);
517
+		});
518
+	}
519
+
520
+	/**
521
+	 * Get the table for the current query object.
522
+	 *
523
+	 * @return string
524
+	 */
525
+	public function getTable()
526
+	{
527
+		return $this->entityMap->getTable();
528
+	}
529
+
530
+	/**
531
+	 * Set the relationships that should be eager loaded.
532
+	 *
533
+	 * @param mixed $relations
534
+	 *
535
+	 * @return $this
536
+	 */
537
+	public function with($relations)
538
+	{
539
+		if (is_string($relations)) {
540
+			$relations = func_get_args();
541
+		}
542
+
543
+		$this->eagerLoad = array_merge($this->eagerLoad, $relations);
544
+
545
+		return $this;
546
+	}
547
+
548
+	/**
549
+	 * Get the relationships being eagerly loaded.
550
+	 *
551
+	 * @return array
552
+	 */
553
+	public function getEagerLoads()
554
+	{
555
+		return $this->eagerLoad;
556
+	}
557
+
558
+	/**
559
+	 * Add the Entity primary key if not in requested columns.
560
+	 *
561
+	 * @param array $columns
562
+	 *
563
+	 * @return array
564
+	 */
565
+	protected function enforceIdColumn($columns)
566
+	{
567
+		if (!in_array($this->entityMap->getKeyName(), $columns)) {
568
+			$columns[] = $this->entityMap->getKeyName();
569
+		}
570
+
571
+		return $columns;
572
+	}
573
+
574
+	/**
575
+	 * Get the hydrated models without eager loading.
576
+	 *
577
+	 * @param array $columns
578
+	 *
579
+	 * @return \Analogue\ORM\EntityCollection
580
+	 */
581
+	public function getEntities($columns = ['*'])
582
+	{
583
+		// As we need the primary key to feed the
584
+		// entity cache, we need it loaded on each
585
+		// request
586
+		$columns = $this->enforceIdColumn($columns);
587
+
588
+		// Run the query
589
+		$results = $this->query->get($columns);
590
+
591
+		// Pass result set to the mapper and return the EntityCollection
592
+		return $this->mapper->map($results, $this->getEagerLoads());
593
+
594
+		// Create a result builder.
595
+		//$builder = new ResultBuilder($this->mapper);
596
+
597
+		//return $builder->build($results, $this->getEagerLoads());
598
+	}
599
+
600
+	/**
601
+	 * Extend the builder with a given callback.
602
+	 *
603
+	 * @param string   $name
604
+	 * @param \Closure $callback
605
+	 *
606
+	 * @return void
607
+	 */
608
+	public function macro($name, Closure $callback)
609
+	{
610
+		$this->macros[$name] = $callback;
611
+	}
612
+
613
+	/**
614
+	 * Get the given macro by name.
615
+	 *
616
+	 * @param string $name
617
+	 *
618
+	 * @return \Closure
619
+	 */
620
+	public function getMacro($name)
621
+	{
622
+		return array_get($this->macros, $name);
623
+	}
624
+
625
+	/**
626
+	 * Get a new query builder for the model's table.
627
+	 *
628
+	 * @return \Analogue\ORM\System\Query
629
+	 */
630
+	public function newQuery()
631
+	{
632
+		$builder = new self($this->mapper, $this->adapter);
633
+
634
+		return $this->applyGlobalScopes($builder);
635
+	}
636
+
637
+	/**
638
+	 * Get a new query builder without any scope applied.
639
+	 *
640
+	 * @return \Analogue\ORM\System\Query
641
+	 */
642
+	public function newQueryWithoutScopes()
643
+	{
644
+		return new self($this->mapper, $this->adapter);
645
+	}
646
+
647
+	/**
648
+	 * Get the Mapper instance for this Query Builder.
649
+	 *
650
+	 * @return \Analogue\ORM\System\Mapper
651
+	 */
652
+	public function getMapper()
653
+	{
654
+		return $this->mapper;
655
+	}
656
+
657
+	/**
658
+	 * Get the underlying query adapter.
659
+	 *
660
+	 * (REFACTOR: this method should move out, we need to provide the client classes
661
+	 * with the adapter instead.)
662
+	 *
663
+	 * @return \Analogue\ORM\Drivers\QueryAdapter|\Analogue\ORM\Drivers\IlluminateQueryAdapter
664
+	 */
665
+	public function getQuery()
666
+	{
667
+		return $this->query;
668
+	}
669
+
670
+	/**
671
+	 * Dynamically handle calls into the query instance.
672
+	 *
673
+	 * @param string $method
674
+	 * @param array  $parameters
675
+	 *
676
+	 * @throws Exception
677
+	 *
678
+	 * @return mixed
679
+	 */
680
+	public function __call($method, $parameters)
681
+	{
682
+		if (isset($this->macros[$method])) {
683
+			array_unshift($parameters, $this);
684
+
685
+			return call_user_func_array($this->macros[$method], $parameters);
686
+		}
687
+
688
+		if (in_array($method, $this->blacklist)) {
689
+			throw new Exception("Method $method doesn't exist");
690
+		}
691
+
692
+		$result = call_user_func_array([$this->query, $method], $parameters);
693
+
694
+		return in_array($method, $this->passthru) ? $result : $this;
695
+	}
696 696
 }
Please login to merge, or discard this patch.
src/System/Wrappers/ObjectWrapper.php 1 patch
Indentation   +221 added lines, -221 removed lines patch added patch discarded remove patch
@@ -10,226 +10,226 @@
 block discarded – undo
10 10
  */
11 11
 class ObjectWrapper extends Wrapper
12 12
 {
13
-    /**
14
-     * Internal Representation of analogue's entity attributes.
15
-     *
16
-     * @var array
17
-     */
18
-    protected $attributes = [];
19
-
20
-    /**
21
-     * Object properties that are not a part of the entity attributes,
22
-     * but which are needed to correctly hydrate the Object.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $unmanagedProperties = [];
27
-
28
-    /**
29
-     * The hydrator for the wrapped object.
30
-     *
31
-     * @var HydratorInterface
32
-     */
33
-    protected $hydrator;
34
-
35
-    /**
36
-     * Object Wrapper constructor.
37
-     *
38
-     * @param mixed                  $object
39
-     * @param Analogue\ORM\EntityMap $entityMap
40
-     *
41
-     * @return void
42
-     */
43
-    public function __construct($entity, $entityMap, HydratorInterface $hydrator)
44
-    {
45
-        $this->hydrator = $hydrator;
46
-        parent::__construct($entity, $entityMap);
47
-        $this->attributes = $this->dehydrate($entity);
48
-    }
49
-
50
-    /**
51
-     * Returns the wrapped entity.
52
-     *
53
-     * @return mixed
54
-     */
55
-    public function getObject()
56
-    {
57
-        $this->hydrate();
58
-
59
-        return $this->entity;
60
-    }
61
-
62
-    /**
63
-     * Extract entity attributes / properties to an array of attributes.
64
-     *
65
-     * @param mixed $entity
66
-     *
67
-     * @return array
68
-     */
69
-    protected function dehydrate($entity) : array
70
-    {
71
-        $properties = $this->hydrator->extract($entity);
72
-
73
-        $this->unmanagedProperties = array_except($properties, $this->getManagedProperties());
74
-
75
-        return $this->attributesFromProperties($properties);
76
-    }
77
-
78
-    /**
79
-     * Hydrate object's properties/attribute from the internal array representation.
80
-     *
81
-     * @return mixed
82
-     */
83
-    public function hydrate()
84
-    {
85
-        $properties = $this->propertiesFromAttributes($this->attributes) + $this->unmanagedProperties;
13
+	/**
14
+	 * Internal Representation of analogue's entity attributes.
15
+	 *
16
+	 * @var array
17
+	 */
18
+	protected $attributes = [];
19
+
20
+	/**
21
+	 * Object properties that are not a part of the entity attributes,
22
+	 * but which are needed to correctly hydrate the Object.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $unmanagedProperties = [];
27
+
28
+	/**
29
+	 * The hydrator for the wrapped object.
30
+	 *
31
+	 * @var HydratorInterface
32
+	 */
33
+	protected $hydrator;
34
+
35
+	/**
36
+	 * Object Wrapper constructor.
37
+	 *
38
+	 * @param mixed                  $object
39
+	 * @param Analogue\ORM\EntityMap $entityMap
40
+	 *
41
+	 * @return void
42
+	 */
43
+	public function __construct($entity, $entityMap, HydratorInterface $hydrator)
44
+	{
45
+		$this->hydrator = $hydrator;
46
+		parent::__construct($entity, $entityMap);
47
+		$this->attributes = $this->dehydrate($entity);
48
+	}
49
+
50
+	/**
51
+	 * Returns the wrapped entity.
52
+	 *
53
+	 * @return mixed
54
+	 */
55
+	public function getObject()
56
+	{
57
+		$this->hydrate();
58
+
59
+		return $this->entity;
60
+	}
61
+
62
+	/**
63
+	 * Extract entity attributes / properties to an array of attributes.
64
+	 *
65
+	 * @param mixed $entity
66
+	 *
67
+	 * @return array
68
+	 */
69
+	protected function dehydrate($entity) : array
70
+	{
71
+		$properties = $this->hydrator->extract($entity);
72
+
73
+		$this->unmanagedProperties = array_except($properties, $this->getManagedProperties());
74
+
75
+		return $this->attributesFromProperties($properties);
76
+	}
77
+
78
+	/**
79
+	 * Hydrate object's properties/attribute from the internal array representation.
80
+	 *
81
+	 * @return mixed
82
+	 */
83
+	public function hydrate()
84
+	{
85
+		$properties = $this->propertiesFromAttributes($this->attributes) + $this->unmanagedProperties;
86 86
         
87
-        $this->hydrator->hydrate($properties, $this->entity);
88
-    }
89
-
90
-    /**
91
-     * Return properties that will be extracted from the entity.
92
-     *
93
-     * @return array
94
-     */
95
-    protected function getManagedProperties() : array
96
-    {
97
-        $properties = $this->entityMap->getProperties();
98
-
99
-        $attributesName = $this->entityMap->getAttributesArrayName();
100
-
101
-        return $attributesName == null ? $properties : array_merge($properties, [$attributesName]);
102
-    }
103
-
104
-    /**
105
-     * Convert object's properties to analogue's internal attributes representation.
106
-     *
107
-     * @param array $properties
108
-     *
109
-     * @return array
110
-     */
111
-    protected function attributesFromProperties(array $properties) : array
112
-    {
113
-        // First, we'll only keep the entities that are part of the Entity's
114
-        // attributes
115
-        $managedProperties = $this->getManagedProperties();
116
-
117
-        $properties = array_only($properties, $managedProperties);
118
-
119
-        // If the entity does not uses the attributes array to store
120
-        // part of its attributes, we'll directly return the properties
121
-        if (!$this->entityMap->usesAttributesArray()) {
122
-            return $properties;
123
-        }
124
-
125
-        $arrayName = $this->entityMap->getAttributesArrayName();
126
-
127
-        if (!array_key_exists($arrayName, $properties)) {
128
-            throw new MappingException("Property $arrayName not set on object of type ".$this->getEntityClass());
129
-        }
130
-
131
-        if (!is_array($properties[$arrayName])) {
132
-            throw new MappingException("Property $arrayName should be an array.");
133
-        }
134
-
135
-        $attributes = $properties[$arrayName];
136
-
137
-        unset($properties[$arrayName]);
138
-
139
-        return $properties + $attributes;
140
-    }
141
-
142
-    /**
143
-     * Convert internal representation of attributes to an array of properties
144
-     * that can hydrate the actual object.
145
-     *
146
-     * @param array $attributes
147
-     *
148
-     * @return array
149
-     */
150
-    protected function propertiesFromAttributes(array $attributes) : array
151
-    {
152
-        $attributes = $this->attributes;
153
-
154
-        // Get all managed properties
155
-        $propertyNames = $this->entityMap->getProperties();
156
-
157
-        $propertyAttributes = array_only($attributes, $propertyNames);
158
-        $attributesArray = array_except($attributes, $propertyNames);
159
-
160
-        $attributesArrayName = $this->entityMap->getAttributesArrayName();
161
-
162
-        if ($attributesArrayName) {
163
-            $propertyAttributes[$attributesArrayName] = $attributesArray;
164
-        }
165
-
166
-        return $propertyAttributes;
167
-    }
168
-
169
-    /**
170
-     * Method used by the mapper to set the object
171
-     * attribute raw values (hydration).
172
-     *
173
-     * @param array $attributes
174
-     *
175
-     * @return void
176
-     */
177
-    public function setEntityAttributes(array $attributes)
178
-    {
179
-        $this->attributes = $attributes;
180
-    }
181
-
182
-    /**
183
-     * Method used by the mapper to get the
184
-     * raw object's values.
185
-     *
186
-     * @return array
187
-     */
188
-    public function getEntityAttributes() : array
189
-    {
190
-        return $this->attributes;
191
-    }
192
-
193
-    /**
194
-     * Method used by the mapper to set raw
195
-     * key-value pair.
196
-     *
197
-     * @param string $key
198
-     * @param string $value
199
-     *
200
-     * @return void
201
-     */
202
-    public function setEntityAttribute($key, $value)
203
-    {
204
-        $this->attributes[$key] = $value;
205
-    }
206
-
207
-    /**
208
-     * Method used by the mapper to get single
209
-     * key-value pair.
210
-     *
211
-     * @param string $key
212
-     *
213
-     * @return mixed|null
214
-     */
215
-    public function getEntityAttribute($key)
216
-    {
217
-        if ($this->hasAttribute($key)) {
218
-            return $this->attributes[$key];
219
-        } else {
220
-            return;
221
-        }
222
-    }
223
-
224
-    /**
225
-     * Test if a given attribute exists.
226
-     *
227
-     * @param string $key
228
-     *
229
-     * @return bool
230
-     */
231
-    public function hasAttribute($key) : bool
232
-    {
233
-        return array_key_exists($key, $this->attributes) ? true : false;
234
-    }
87
+		$this->hydrator->hydrate($properties, $this->entity);
88
+	}
89
+
90
+	/**
91
+	 * Return properties that will be extracted from the entity.
92
+	 *
93
+	 * @return array
94
+	 */
95
+	protected function getManagedProperties() : array
96
+	{
97
+		$properties = $this->entityMap->getProperties();
98
+
99
+		$attributesName = $this->entityMap->getAttributesArrayName();
100
+
101
+		return $attributesName == null ? $properties : array_merge($properties, [$attributesName]);
102
+	}
103
+
104
+	/**
105
+	 * Convert object's properties to analogue's internal attributes representation.
106
+	 *
107
+	 * @param array $properties
108
+	 *
109
+	 * @return array
110
+	 */
111
+	protected function attributesFromProperties(array $properties) : array
112
+	{
113
+		// First, we'll only keep the entities that are part of the Entity's
114
+		// attributes
115
+		$managedProperties = $this->getManagedProperties();
116
+
117
+		$properties = array_only($properties, $managedProperties);
118
+
119
+		// If the entity does not uses the attributes array to store
120
+		// part of its attributes, we'll directly return the properties
121
+		if (!$this->entityMap->usesAttributesArray()) {
122
+			return $properties;
123
+		}
124
+
125
+		$arrayName = $this->entityMap->getAttributesArrayName();
126
+
127
+		if (!array_key_exists($arrayName, $properties)) {
128
+			throw new MappingException("Property $arrayName not set on object of type ".$this->getEntityClass());
129
+		}
130
+
131
+		if (!is_array($properties[$arrayName])) {
132
+			throw new MappingException("Property $arrayName should be an array.");
133
+		}
134
+
135
+		$attributes = $properties[$arrayName];
136
+
137
+		unset($properties[$arrayName]);
138
+
139
+		return $properties + $attributes;
140
+	}
141
+
142
+	/**
143
+	 * Convert internal representation of attributes to an array of properties
144
+	 * that can hydrate the actual object.
145
+	 *
146
+	 * @param array $attributes
147
+	 *
148
+	 * @return array
149
+	 */
150
+	protected function propertiesFromAttributes(array $attributes) : array
151
+	{
152
+		$attributes = $this->attributes;
153
+
154
+		// Get all managed properties
155
+		$propertyNames = $this->entityMap->getProperties();
156
+
157
+		$propertyAttributes = array_only($attributes, $propertyNames);
158
+		$attributesArray = array_except($attributes, $propertyNames);
159
+
160
+		$attributesArrayName = $this->entityMap->getAttributesArrayName();
161
+
162
+		if ($attributesArrayName) {
163
+			$propertyAttributes[$attributesArrayName] = $attributesArray;
164
+		}
165
+
166
+		return $propertyAttributes;
167
+	}
168
+
169
+	/**
170
+	 * Method used by the mapper to set the object
171
+	 * attribute raw values (hydration).
172
+	 *
173
+	 * @param array $attributes
174
+	 *
175
+	 * @return void
176
+	 */
177
+	public function setEntityAttributes(array $attributes)
178
+	{
179
+		$this->attributes = $attributes;
180
+	}
181
+
182
+	/**
183
+	 * Method used by the mapper to get the
184
+	 * raw object's values.
185
+	 *
186
+	 * @return array
187
+	 */
188
+	public function getEntityAttributes() : array
189
+	{
190
+		return $this->attributes;
191
+	}
192
+
193
+	/**
194
+	 * Method used by the mapper to set raw
195
+	 * key-value pair.
196
+	 *
197
+	 * @param string $key
198
+	 * @param string $value
199
+	 *
200
+	 * @return void
201
+	 */
202
+	public function setEntityAttribute($key, $value)
203
+	{
204
+		$this->attributes[$key] = $value;
205
+	}
206
+
207
+	/**
208
+	 * Method used by the mapper to get single
209
+	 * key-value pair.
210
+	 *
211
+	 * @param string $key
212
+	 *
213
+	 * @return mixed|null
214
+	 */
215
+	public function getEntityAttribute($key)
216
+	{
217
+		if ($this->hasAttribute($key)) {
218
+			return $this->attributes[$key];
219
+		} else {
220
+			return;
221
+		}
222
+	}
223
+
224
+	/**
225
+	 * Test if a given attribute exists.
226
+	 *
227
+	 * @param string $key
228
+	 *
229
+	 * @return bool
230
+	 */
231
+	public function hasAttribute($key) : bool
232
+	{
233
+		return array_key_exists($key, $this->attributes) ? true : false;
234
+	}
235 235
 }
Please login to merge, or discard this patch.
src/System/Wrappers/Wrapper.php 1 patch
Indentation   +236 added lines, -236 removed lines patch added patch discarded remove patch
@@ -10,240 +10,240 @@
 block discarded – undo
10 10
  */
11 11
 abstract class Wrapper implements InternallyMappable
12 12
 {
13
-    /**
14
-     * Original Entity Object.
15
-     *
16
-     * @var mixed
17
-     */
18
-    protected $entity;
19
-
20
-    /**
21
-     * Corresponding EntityMap.
22
-     *
23
-     * @var \Analogue\ORM\EntityMap
24
-     */
25
-    protected $entityMap;
26
-
27
-    /**
28
-     * @var \Analogue\ORM\System\Proxirs\ProxyFactory
29
-     */
30
-    protected $proxyFactory;
31
-
32
-    /**
33
-     * Wrapper constructor.
34
-     *
35
-     * @param $entity
36
-     * @param $entityMap
37
-     */
38
-    public function __construct($entity, $entityMap)
39
-    {
40
-        $this->entity = $entity;
41
-        $this->entityMap = $entityMap;
42
-        $this->proxyFactory = new ProxyFactory();
43
-    }
44
-
45
-    /**
46
-     * Return the wrapped entity class.
47
-     *
48
-     * @return mixed
49
-     */
50
-    public function getEntityClass()
51
-    {
52
-        return get_class($this->entity);
53
-    }
54
-
55
-    /**
56
-     * Return the entity's primary key valuye.
57
-     *
58
-     * @return string
59
-     */
60
-    public function getEntityKey()
61
-    {
62
-        return $this->getEntityAttribute($this->entityMap->getKeyName());
63
-    }
64
-
65
-    /**
66
-     * Return the Entity class/primary key couple,
67
-     * which is used for internall operations.
68
-     *
69
-     * @return string
70
-     */
71
-    public function getEntityHash()
72
-    {
73
-        return $this->getEntityClass().'.'.$this->getEntityKey();
74
-    }
75
-
76
-    /**
77
-     * Returns the wrapped entity.
78
-     *
79
-     * @return mixed
80
-     */
81
-    public function getObject()
82
-    {
83
-        return $this->entity;
84
-    }
85
-
86
-    /**
87
-     * Returns the wrapped entity's map.
88
-     *
89
-     * @return mixed
90
-     */
91
-    public function getMap()
92
-    {
93
-        return $this->entityMap;
94
-    }
95
-
96
-    /**
97
-     * Set the lazyloading proxies on the wrapped entity objet.
98
-     *
99
-     * @param array $relations list of relations to be lazy loaded
100
-     *
101
-     * @return void
102
-     */
103
-    public function setProxies(array $relations = null)
104
-    {
105
-        $attributes = $this->getEntityAttributes();
106
-        $proxies = [];
107
-
108
-        //if (is_null($relations)) {
109
-            $relations = $this->getRelationsToProxy();
110
-        //}
111
-        //dump($relations);
112
-        // Before calling the relationship methods, we'll set the relationship
113
-        // method to null, to avoid hydration error on class properties
114
-        foreach ($relations as $relation) {
115
-            $this->setEntityAttribute($relation, null);
116
-        }
117
-
118
-        foreach ($relations as $relation) {
119
-
120
-            // First, we check that the relation has not been already
121
-            // set, in which case, we'll just pass.
122
-            if (array_key_exists($relation, $attributes) && !is_null($attributes[$relation])) {
123
-                continue;
124
-            }
125
-
126
-            // If the key is handled locally and we know it not to be set,
127
-            // we'll set the relationship to null
128
-            if (!$this->relationNeedsProxy($relation, $attributes)) {
129
-                $proxies[$relation] = null;
130
-            } else {
131
-                $targetClass = $this->getClassToProxy($relation, $attributes);
132
-                $proxies[$relation] = $this->proxyFactory->make($this->getObject(), $relation, $targetClass);
133
-            }
134
-        }
135
-
136
-        foreach ($proxies as $key => $value) {
137
-            $this->setEntityAttribute($key, $value);
138
-        }
139
-
140
-    }
141
-
142
-    /**
143
-     * Get Target class to proxy for a one to one.
144
-     *
145
-     * @param string $relation
146
-     * @param array  $attributes
147
-     *
148
-     * @return string
149
-     */
150
-    protected function getClassToProxy($relation, array $attributes)
151
-    {
152
-        if ($this->entityMap->isPolymorphic($relation)) {
153
-            $localTypeAttribute = $this->entityMap->getLocalKeys($relation)['type'];
154
-
155
-            return $attributes[$localTypeAttribute];
156
-        }
157
-
158
-        return $this->entityMap->getTargettedClass($relation);
159
-    }
160
-
161
-    /**
162
-     * Determine which relations we have to build proxy for, by parsing
163
-     * attributes and finding methods that aren't set.
164
-     *
165
-     * @return array
166
-     */
167
-    protected function getRelationsToProxy()
168
-    {
169
-        $proxies = [];
170
-        $attributes = $this->getEntityAttributes();
171
-
172
-        foreach ($this->entityMap->getRelationships() as $relation) {
173
-            if (!array_key_exists($relation, $attributes)) {
174
-                $proxies[] = $relation;
175
-            }
176
-        }
177
-
178
-        return $proxies;
179
-    }
180
-
181
-    /**
182
-     * Determine if the relation needs a proxy or not.
183
-     *
184
-     * @param string $relation
185
-     * @param array  $attributes
186
-     *
187
-     * @return bool
188
-     */
189
-    protected function relationNeedsProxy($relation, $attributes)
190
-    {
191
-        if (in_array($relation, $this->entityMap->getRelationshipsWithoutProxy())) {
192
-            return false;
193
-        }
194
-
195
-        $localKey = $this->entityMap->getLocalKeys($relation);
196
-
197
-        if (is_null($localKey)) {
198
-            return true;
199
-        }
200
-
201
-        if (is_array($localKey)) {
202
-            $localKey = $localKey['id'];
203
-        }
204
-
205
-        if (!isset($attributes[$localKey])) {
206
-            return false;
207
-        }
208
-
209
-        if (is_null($attributes[$localKey])) {
210
-            return false;
211
-        }
212
-
213
-        return true;
214
-    }
215
-
216
-    /**
217
-     * @param string $key
218
-     * @param string $value
219
-     *
220
-     * @return mixed
221
-     */
222
-    abstract public function setEntityAttribute($key, $value);
223
-
224
-    /**
225
-     * @param string $key
226
-     *
227
-     * @return mixed
228
-     */
229
-    abstract public function getEntityAttribute($key);
230
-
231
-    /**
232
-     * @param array $attributes
233
-     *
234
-     * @return mixed
235
-     */
236
-    abstract public function setEntityAttributes(array $attributes);
237
-
238
-    /**
239
-     * @return mixed
240
-     */
241
-    abstract public function getEntityAttributes();
242
-
243
-    /**
244
-     * @param string $key
245
-     *
246
-     * @return mixed
247
-     */
248
-    abstract public function hasAttribute($key);
13
+	/**
14
+	 * Original Entity Object.
15
+	 *
16
+	 * @var mixed
17
+	 */
18
+	protected $entity;
19
+
20
+	/**
21
+	 * Corresponding EntityMap.
22
+	 *
23
+	 * @var \Analogue\ORM\EntityMap
24
+	 */
25
+	protected $entityMap;
26
+
27
+	/**
28
+	 * @var \Analogue\ORM\System\Proxirs\ProxyFactory
29
+	 */
30
+	protected $proxyFactory;
31
+
32
+	/**
33
+	 * Wrapper constructor.
34
+	 *
35
+	 * @param $entity
36
+	 * @param $entityMap
37
+	 */
38
+	public function __construct($entity, $entityMap)
39
+	{
40
+		$this->entity = $entity;
41
+		$this->entityMap = $entityMap;
42
+		$this->proxyFactory = new ProxyFactory();
43
+	}
44
+
45
+	/**
46
+	 * Return the wrapped entity class.
47
+	 *
48
+	 * @return mixed
49
+	 */
50
+	public function getEntityClass()
51
+	{
52
+		return get_class($this->entity);
53
+	}
54
+
55
+	/**
56
+	 * Return the entity's primary key valuye.
57
+	 *
58
+	 * @return string
59
+	 */
60
+	public function getEntityKey()
61
+	{
62
+		return $this->getEntityAttribute($this->entityMap->getKeyName());
63
+	}
64
+
65
+	/**
66
+	 * Return the Entity class/primary key couple,
67
+	 * which is used for internall operations.
68
+	 *
69
+	 * @return string
70
+	 */
71
+	public function getEntityHash()
72
+	{
73
+		return $this->getEntityClass().'.'.$this->getEntityKey();
74
+	}
75
+
76
+	/**
77
+	 * Returns the wrapped entity.
78
+	 *
79
+	 * @return mixed
80
+	 */
81
+	public function getObject()
82
+	{
83
+		return $this->entity;
84
+	}
85
+
86
+	/**
87
+	 * Returns the wrapped entity's map.
88
+	 *
89
+	 * @return mixed
90
+	 */
91
+	public function getMap()
92
+	{
93
+		return $this->entityMap;
94
+	}
95
+
96
+	/**
97
+	 * Set the lazyloading proxies on the wrapped entity objet.
98
+	 *
99
+	 * @param array $relations list of relations to be lazy loaded
100
+	 *
101
+	 * @return void
102
+	 */
103
+	public function setProxies(array $relations = null)
104
+	{
105
+		$attributes = $this->getEntityAttributes();
106
+		$proxies = [];
107
+
108
+		//if (is_null($relations)) {
109
+			$relations = $this->getRelationsToProxy();
110
+		//}
111
+		//dump($relations);
112
+		// Before calling the relationship methods, we'll set the relationship
113
+		// method to null, to avoid hydration error on class properties
114
+		foreach ($relations as $relation) {
115
+			$this->setEntityAttribute($relation, null);
116
+		}
117
+
118
+		foreach ($relations as $relation) {
119
+
120
+			// First, we check that the relation has not been already
121
+			// set, in which case, we'll just pass.
122
+			if (array_key_exists($relation, $attributes) && !is_null($attributes[$relation])) {
123
+				continue;
124
+			}
125
+
126
+			// If the key is handled locally and we know it not to be set,
127
+			// we'll set the relationship to null
128
+			if (!$this->relationNeedsProxy($relation, $attributes)) {
129
+				$proxies[$relation] = null;
130
+			} else {
131
+				$targetClass = $this->getClassToProxy($relation, $attributes);
132
+				$proxies[$relation] = $this->proxyFactory->make($this->getObject(), $relation, $targetClass);
133
+			}
134
+		}
135
+
136
+		foreach ($proxies as $key => $value) {
137
+			$this->setEntityAttribute($key, $value);
138
+		}
139
+
140
+	}
141
+
142
+	/**
143
+	 * Get Target class to proxy for a one to one.
144
+	 *
145
+	 * @param string $relation
146
+	 * @param array  $attributes
147
+	 *
148
+	 * @return string
149
+	 */
150
+	protected function getClassToProxy($relation, array $attributes)
151
+	{
152
+		if ($this->entityMap->isPolymorphic($relation)) {
153
+			$localTypeAttribute = $this->entityMap->getLocalKeys($relation)['type'];
154
+
155
+			return $attributes[$localTypeAttribute];
156
+		}
157
+
158
+		return $this->entityMap->getTargettedClass($relation);
159
+	}
160
+
161
+	/**
162
+	 * Determine which relations we have to build proxy for, by parsing
163
+	 * attributes and finding methods that aren't set.
164
+	 *
165
+	 * @return array
166
+	 */
167
+	protected function getRelationsToProxy()
168
+	{
169
+		$proxies = [];
170
+		$attributes = $this->getEntityAttributes();
171
+
172
+		foreach ($this->entityMap->getRelationships() as $relation) {
173
+			if (!array_key_exists($relation, $attributes)) {
174
+				$proxies[] = $relation;
175
+			}
176
+		}
177
+
178
+		return $proxies;
179
+	}
180
+
181
+	/**
182
+	 * Determine if the relation needs a proxy or not.
183
+	 *
184
+	 * @param string $relation
185
+	 * @param array  $attributes
186
+	 *
187
+	 * @return bool
188
+	 */
189
+	protected function relationNeedsProxy($relation, $attributes)
190
+	{
191
+		if (in_array($relation, $this->entityMap->getRelationshipsWithoutProxy())) {
192
+			return false;
193
+		}
194
+
195
+		$localKey = $this->entityMap->getLocalKeys($relation);
196
+
197
+		if (is_null($localKey)) {
198
+			return true;
199
+		}
200
+
201
+		if (is_array($localKey)) {
202
+			$localKey = $localKey['id'];
203
+		}
204
+
205
+		if (!isset($attributes[$localKey])) {
206
+			return false;
207
+		}
208
+
209
+		if (is_null($attributes[$localKey])) {
210
+			return false;
211
+		}
212
+
213
+		return true;
214
+	}
215
+
216
+	/**
217
+	 * @param string $key
218
+	 * @param string $value
219
+	 *
220
+	 * @return mixed
221
+	 */
222
+	abstract public function setEntityAttribute($key, $value);
223
+
224
+	/**
225
+	 * @param string $key
226
+	 *
227
+	 * @return mixed
228
+	 */
229
+	abstract public function getEntityAttribute($key);
230
+
231
+	/**
232
+	 * @param array $attributes
233
+	 *
234
+	 * @return mixed
235
+	 */
236
+	abstract public function setEntityAttributes(array $attributes);
237
+
238
+	/**
239
+	 * @return mixed
240
+	 */
241
+	abstract public function getEntityAttributes();
242
+
243
+	/**
244
+	 * @param string $key
245
+	 *
246
+	 * @return mixed
247
+	 */
248
+	abstract public function hasAttribute($key);
249 249
 }
Please login to merge, or discard this patch.
src/System/Mapper.php 2 patches
Indentation   +630 added lines, -630 removed lines patch added patch discarded remove patch
@@ -25,634 +25,634 @@
 block discarded – undo
25 25
  */
26 26
 class Mapper
27 27
 {
28
-    /**
29
-     * The Manager instance.
30
-     *
31
-     * @var \Analogue\ORM\System\Manager
32
-     */
33
-    protected $manager;
34
-
35
-    /**
36
-     * Instance of EntityMapper Object.
37
-     *
38
-     * @var \Analogue\ORM\EntityMap
39
-     */
40
-    protected $entityMap;
41
-
42
-    /**
43
-     * The instance of db adapter.
44
-     *
45
-     * @var \Analogue\ORM\Drivers\DBAdapter
46
-     */
47
-    protected $adapter;
48
-
49
-    /**
50
-     * Event dispatcher instance.
51
-     *
52
-     * @var \Illuminate\Contracts\Events\Dispatcher
53
-     */
54
-    protected $dispatcher;
55
-
56
-    /**
57
-     * Entity Cache.
58
-     *
59
-     * @var \Analogue\ORM\System\EntityCache
60
-     */
61
-    protected $cache;
62
-
63
-    /**
64
-     * Global scopes.
65
-     *
66
-     * @var array
67
-     */
68
-    protected $globalScopes = [];
69
-
70
-    /**
71
-     * Custom Commands.
72
-     *
73
-     * @var array
74
-     */
75
-    protected $customCommands = [];
76
-
77
-    /**
78
-     * @param EntityMap  $entityMap
79
-     * @param DBAdapter  $adapter
80
-     * @param Dispatcher $dispatcher
81
-     * @param Manager    $manager
82
-     */
83
-    public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
84
-    {
85
-        $this->entityMap = $entityMap;
86
-
87
-        $this->adapter = $adapter;
88
-
89
-        $this->dispatcher = $dispatcher;
90
-
91
-        $this->manager = $manager;
92
-
93
-        $this->cache = new EntityCache($entityMap);
94
-    }
95
-
96
-    /**
97
-     * Map results to a Collection.
98
-     *
99
-     * @param array|Collection $results
100
-     *
101
-     * @return Collection
102
-     */
103
-    public function map($results, array $eagerLoads = []) : Collection
104
-    {
105
-        $builder = new ResultBuilder($this);
106
-
107
-        if ($results instanceof collection) {
108
-            // Get underlying collection array
109
-            $results = $results->all();
110
-        }
111
-
112
-        if (!is_array($results)) {
113
-            throw new InvalidArgumentException("'results' should be an array or collection.");
114
-        }
115
-
116
-        // First, we'll cast every single result to array
117
-        $results = array_map(function ($item) {
118
-            return (array) $item;
119
-        }, $results);
120
-
121
-        // Then, we'll cache every single results as raw attributes, before
122
-        // adding relationships, which will be cached when the relationship's
123
-        // query takes place.
124
-        $this->getEntityCache()->add($results);
125
-
126
-        $entities = $builder->build($results, $eagerLoads);
127
-
128
-        return $this->entityMap->newCollection($entities);
129
-    }
130
-
131
-    /**
132
-     * Return all records for a mapped object.
133
-     *
134
-     * @return EntityCollection
135
-     */
136
-    public function all()
137
-    {
138
-        return $this->query()->get();
139
-    }
140
-
141
-    /**
142
-     * Persist an entity or an entity collection into the database.
143
-     *
144
-     * @param Mappable|\Traversable|array $entity
145
-     *
146
-     * @throws \InvalidArgumentException
147
-     * @throws MappingException
148
-     *
149
-     * @return Mappable|\Traversable|array
150
-     */
151
-    public function store($entity)
152
-    {
153
-        if ($this->manager->isTraversable($entity)) {
154
-            return $this->storeCollection($entity);
155
-        } else {
156
-            return $this->storeEntity($entity);
157
-        }
158
-    }
159
-
160
-    /**
161
-     * Store an entity collection inside a single DB Transaction.
162
-     *
163
-     * @param \Traversable|array $entities
164
-     *
165
-     * @throws \InvalidArgumentException
166
-     * @throws MappingException
167
-     *
168
-     * @return \Traversable|array
169
-     */
170
-    protected function storeCollection($entities)
171
-    {
172
-        $this->adapter->beginTransaction();
173
-
174
-        foreach ($entities as $entity) {
175
-            $this->storeEntity($entity);
176
-        }
177
-
178
-        $this->adapter->commit();
179
-
180
-        return $entities;
181
-    }
182
-
183
-    /**
184
-     * Store a single entity into the database.
185
-     *
186
-     * @param Mappable $entity
187
-     *
188
-     * @throws \InvalidArgumentException
189
-     * @throws MappingException
190
-     *
191
-     * @return \Analogue\ORM\Entity
192
-     */
193
-    protected function storeEntity($entity)
194
-    {   
195
-        $this->checkEntityType($entity);
196
-
197
-        $store = new Store($this->aggregate($entity), $this->newQueryBuilder());
198
-
199
-        return $store->execute();
200
-    }
201
-
202
-    /**
203
-     * Check that the entity correspond to the current mapper.
204
-     *
205
-     * @param mixed $entity
206
-     *
207
-     * @throws InvalidArgumentException
208
-     *
209
-     * @return void
210
-     */
211
-    protected function checkEntityType($entity)
212
-    {
213
-        if (get_class($entity) != $this->entityMap->getClass() && !is_subclass_of($entity, $this->entityMap->getClass())) {
214
-            $expected = $this->entityMap->getClass();
215
-            $actual = get_class($entity);
216
-            throw new InvalidArgumentException("Expected : $expected, got $actual.");
217
-        }
218
-    }
219
-
220
-    /**
221
-     * Convert an entity into an aggregate root.
222
-     *
223
-     * @param mixed $entity
224
-     *
225
-     * @throws MappingException
226
-     *
227
-     * @return \Analogue\ORM\System\Aggregate
228
-     */
229
-    protected function aggregate($entity)
230
-    {
231
-        return new Aggregate($entity);
232
-    }
233
-
234
-    /**
235
-     * Get a the Underlying QueryAdapter.
236
-     *
237
-     * @return \Analogue\ORM\Drivers\QueryAdapter
238
-     */
239
-    public function newQueryBuilder()
240
-    {
241
-        return $this->adapter->getQuery();
242
-    }
243
-
244
-    /**
245
-     * Delete an entity or an entity collection from the database.
246
-     *
247
-     * @param  Mappable|\Traversable|array
248
-     *
249
-     * @throws MappingException
250
-     * @throws \InvalidArgumentException
251
-     *
252
-     * @return \Traversable|array
253
-     */
254
-    public function delete($entity)
255
-    {
256
-        if ($this->manager->isTraversable($entity)) {
257
-            return $this->deleteCollection($entity);
258
-        } else {
259
-            $this->deleteEntity($entity);
260
-        }
261
-    }
262
-
263
-    /**
264
-     * Delete an Entity Collection inside a single db transaction.
265
-     *
266
-     * @param \Traversable|array $entities
267
-     *
268
-     * @throws \InvalidArgumentException
269
-     * @throws MappingException
270
-     *
271
-     * @return \Traversable|array
272
-     */
273
-    protected function deleteCollection($entities)
274
-    {
275
-        $this->adapter->beginTransaction();
276
-
277
-        foreach ($entities as $entity) {
278
-            $this->deleteEntity($entity);
279
-        }
280
-
281
-        $this->adapter->commit();
282
-
283
-        return $entities;
284
-    }
285
-
286
-    /**
287
-     * Delete a single entity from the database.
288
-     *
289
-     * @param Mappable $entity
290
-     *
291
-     * @throws \InvalidArgumentException
292
-     * @throws MappingException
293
-     *
294
-     * @return void
295
-     */
296
-    protected function deleteEntity($entity)
297
-    {
298
-        $this->checkEntityType($entity);
299
-
300
-        $delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
301
-
302
-        $delete->execute();
303
-    }
304
-
305
-    /**
306
-     * Return the entity map for this mapper.
307
-     *
308
-     * @return EntityMap
309
-     */
310
-    public function getEntityMap()
311
-    {
312
-        return $this->entityMap;
313
-    }
314
-
315
-    /**
316
-     * Get the entity cache for the current mapper.
317
-     *
318
-     * @return EntityCache $entityCache
319
-     */
320
-    public function getEntityCache()
321
-    {
322
-        return $this->cache;
323
-    }
324
-
325
-    /**
326
-     * Fire the given event for the entity.
327
-     *
328
-     * @param string               $event
329
-     * @param \Analogue\ORM\Entity $entity
330
-     * @param bool                 $halt
331
-     *
332
-     * @throws InvalidArgumentException
333
-     *
334
-     * @return mixed
335
-     */
336
-    public function fireEvent($event, $entity, $halt = true)
337
-    {
338
-        if ($entity instanceof Wrapper) {
339
-            throw new InvalidArgumentException('Fired Event with invalid Entity Object');
340
-        }
341
-
342
-        $event = "analogue.{$event}.".$this->entityMap->getClass();
343
-
344
-        $method = $halt ? 'until' : 'fire';
345
-
346
-        return $this->dispatcher->$method($event, $entity);
347
-    }
348
-
349
-    /**
350
-     * Register an entity event with the dispatcher.
351
-     *
352
-     * @param string   $event
353
-     * @param \Closure $callback
354
-     *
355
-     * @return void
356
-     */
357
-    public function registerEvent($event, $callback)
358
-    {
359
-        $name = $this->entityMap->getClass();
360
-
361
-        $this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
362
-    }
363
-
364
-    /**
365
-     * Add a global scope to this mapper query builder.
366
-     *
367
-     * @param ScopeInterface $scope
368
-     *
369
-     * @return void
370
-     */
371
-    public function addGlobalScope(ScopeInterface $scope)
372
-    {
373
-        $this->globalScopes[get_class($scope)] = $scope;
374
-    }
375
-
376
-    /**
377
-     * Determine if the mapper has a global scope.
378
-     *
379
-     * @param \Analogue\ORM\System\ScopeInterface $scope
380
-     *
381
-     * @return bool
382
-     */
383
-    public function hasGlobalScope($scope)
384
-    {
385
-        return !is_null($this->getGlobalScope($scope));
386
-    }
387
-
388
-    /**
389
-     * Get a global scope registered with the modal.
390
-     *
391
-     * @param \Analogue\ORM\System\ScopeInterface $scope
392
-     *
393
-     * @return \Analogue\ORM\System\ScopeInterface|null
394
-     */
395
-    public function getGlobalScope($scope)
396
-    {
397
-        return array_first($this->globalScopes, function ($key, $value) use ($scope) {
398
-            return $scope instanceof $value;
399
-        });
400
-    }
401
-
402
-    /**
403
-     * Get a new query instance without a given scope.
404
-     *
405
-     * @param \Analogue\ORM\System\ScopeInterface $scope
406
-     *
407
-     * @return \Analogue\ORM\System\Query
408
-     */
409
-    public function newQueryWithoutScope($scope)
410
-    {
411
-        $this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
412
-
413
-        return $query;
414
-    }
415
-
416
-    /**
417
-     * Get the Analogue Query Builder for this instance.
418
-     *
419
-     * @return \Analogue\ORM\System\Query
420
-     */
421
-    public function getQuery()
422
-    {
423
-        $query = new Query($this, $this->adapter);
424
-
425
-        return $this->applyGlobalScopes($query);
426
-    }
427
-
428
-    /**
429
-     * Apply all of the global scopes to an Analogue Query builder.
430
-     *
431
-     * @param Query $query
432
-     *
433
-     * @return \Analogue\ORM\System\Query
434
-     */
435
-    public function applyGlobalScopes($query)
436
-    {
437
-        foreach ($this->getGlobalScopes() as $scope) {
438
-            $scope->apply($query, $this);
439
-        }
440
-
441
-        return $query;
442
-    }
443
-
444
-    /**
445
-     * Get the global scopes for this class instance.
446
-     *
447
-     * @return \Analogue\ORM\System\ScopeInterface
448
-     */
449
-    public function getGlobalScopes()
450
-    {
451
-        return $this->globalScopes;
452
-    }
453
-
454
-    /**
455
-     * Add a dynamic method that extends the mapper/repository.
456
-     *
457
-     * @param string $command
458
-     */
459
-    public function addCustomCommand($command)
460
-    {
461
-        $name = lcfirst(class_basename($command));
462
-
463
-        $this->customCommands[$name] = $command;
464
-    }
465
-
466
-    /**
467
-     * Create a new instance of the mapped entity class.
468
-     *
469
-     * @return mixed
470
-     */
471
-    public function newInstance()
472
-    {
473
-        $class = $this->entityMap->getClass();
474
-
475
-        if ($this->entityMap->useDependencyInjection()) {
476
-            return $this->newInstanceUsingDependencyInjection($class);
477
-        }
478
-
479
-        return $this->newInstanceUsingInstantiator($class);
480
-    }
481
-
482
-    /**
483
-     * Return a new object instance using dependency injection.
484
-     *
485
-     * @param string $class
486
-     *
487
-     * @return mixed
488
-     */
489
-    protected function newInstanceUsingDependencyInjection($class)
490
-    {
491
-        if (!class_exists(Container::class)) {
492
-            throw new ErrorException("Illuminate\Container\Container is required to use Dependency Injection");
493
-        }
494
-
495
-        return Container::getInstance()->make($class);
496
-    }
497
-
498
-    /**
499
-     * Return a new object instance using doctrine's instantiator.
500
-     *
501
-     * @param string $class
502
-     *
503
-     * @return mixed
504
-     */
505
-    protected function newInstanceUsingInstantiator($class)
506
-    {
507
-        $instantiator = new \Doctrine\Instantiator\Instantiator();
508
-
509
-        return $instantiator->instantiate($class);
510
-    }
511
-
512
-    /**
513
-     * Get an unscoped Analogue Query Builder for this instance.
514
-     *
515
-     * @return \Analogue\ORM\System\Query
516
-     */
517
-    public function globalQuery()
518
-    {
519
-        return $this->newQueryWithoutScopes();
520
-    }
521
-
522
-    /**
523
-     * Get a new query builder that doesn't have any global scopes.
524
-     *
525
-     * @return Query
526
-     */
527
-    public function newQueryWithoutScopes()
528
-    {
529
-        return $this->removeGlobalScopes($this->getQuery());
530
-    }
531
-
532
-    /**
533
-     * Remove all of the global scopes from an Analogue Query builder.
534
-     *
535
-     * @param Query $query
536
-     *
537
-     * @return \Analogue\ORM\System\Query
538
-     */
539
-    public function removeGlobalScopes($query)
540
-    {
541
-        foreach ($this->getGlobalScopes() as $scope) {
542
-            $scope->remove($query, $this);
543
-        }
544
-
545
-        return $query;
546
-    }
547
-
548
-    /**
549
-     * Return the manager instance.
550
-     *
551
-     * @return \Analogue\ORM\System\Manager
552
-     */
553
-    public function getManager()
554
-    {
555
-        return $this->manager;
556
-    }
557
-
558
-    /**
559
-     * Dynamically handle calls to custom commands, or Redirects to query().
560
-     *
561
-     * @param string $method
562
-     * @param array  $parameters
563
-     *
564
-     * @throws \Exception
565
-     *
566
-     * @return mixed
567
-     */
568
-    public function __call($method, $parameters)
569
-    {
570
-        // Check if method is a custom command on the mapper
571
-        if ($this->hasCustomCommand($method)) {
572
-            if (count($parameters) == 0) {
573
-                throw new \Exception("$method must at least have 1 argument");
574
-            }
575
-
576
-            return $this->executeCustomCommand($method, $parameters[0]);
577
-        }
578
-
579
-        // Redirect call on a new query instance
580
-        return call_user_func_array([$this->query(), $method], $parameters);
581
-    }
582
-
583
-    /**
584
-     * Check if this mapper supports this command.
585
-     *
586
-     * @param string $command
587
-     *
588
-     * @return bool
589
-     */
590
-    public function hasCustomCommand($command)
591
-    {
592
-        return in_array($command, $this->getCustomCommands());
593
-    }
594
-
595
-    /**
596
-     * Get all the custom commands registered on this mapper.
597
-     *
598
-     * @return array
599
-     */
600
-    public function getCustomCommands()
601
-    {
602
-        return array_keys($this->customCommands);
603
-    }
604
-
605
-    /**
606
-     * Execute a custom command on an Entity.
607
-     *
608
-     * @param string                 $command
609
-     * @param mixed|Collection|array $entity
610
-     *
611
-     * @throws \InvalidArgumentException
612
-     * @throws MappingException
613
-     *
614
-     * @return mixed
615
-     */
616
-    public function executeCustomCommand($command, $entity)
617
-    {
618
-        $commandClass = $this->customCommands[$command];
619
-
620
-        if ($this->manager->isTraversable($entity)) {
621
-            foreach ($entity as $instance) {
622
-                $this->executeSingleCustomCommand($commandClass, $instance);
623
-            }
624
-        } else {
625
-            return $this->executeSingleCustomCommand($commandClass, $entity);
626
-        }
627
-    }
628
-
629
-    /**
630
-     * Execute a single command instance.
631
-     *
632
-     * @param string $commandClass
633
-     * @param mixed  $entity
634
-     *
635
-     * @throws \InvalidArgumentException
636
-     * @throws MappingException
637
-     *
638
-     * @return mixed
639
-     */
640
-    protected function executeSingleCustomCommand($commandClass, $entity)
641
-    {
642
-        $this->checkEntityType($entity);
643
-
644
-        $instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
645
-
646
-        return $instance->execute();
647
-    }
648
-
649
-    /**
650
-     * Get the Analogue Query Builder for this instance.
651
-     *
652
-     * @return \Analogue\ORM\System\Query
653
-     */
654
-    public function query()
655
-    {
656
-        return $this->getQuery();
657
-    }
28
+	/**
29
+	 * The Manager instance.
30
+	 *
31
+	 * @var \Analogue\ORM\System\Manager
32
+	 */
33
+	protected $manager;
34
+
35
+	/**
36
+	 * Instance of EntityMapper Object.
37
+	 *
38
+	 * @var \Analogue\ORM\EntityMap
39
+	 */
40
+	protected $entityMap;
41
+
42
+	/**
43
+	 * The instance of db adapter.
44
+	 *
45
+	 * @var \Analogue\ORM\Drivers\DBAdapter
46
+	 */
47
+	protected $adapter;
48
+
49
+	/**
50
+	 * Event dispatcher instance.
51
+	 *
52
+	 * @var \Illuminate\Contracts\Events\Dispatcher
53
+	 */
54
+	protected $dispatcher;
55
+
56
+	/**
57
+	 * Entity Cache.
58
+	 *
59
+	 * @var \Analogue\ORM\System\EntityCache
60
+	 */
61
+	protected $cache;
62
+
63
+	/**
64
+	 * Global scopes.
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $globalScopes = [];
69
+
70
+	/**
71
+	 * Custom Commands.
72
+	 *
73
+	 * @var array
74
+	 */
75
+	protected $customCommands = [];
76
+
77
+	/**
78
+	 * @param EntityMap  $entityMap
79
+	 * @param DBAdapter  $adapter
80
+	 * @param Dispatcher $dispatcher
81
+	 * @param Manager    $manager
82
+	 */
83
+	public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
84
+	{
85
+		$this->entityMap = $entityMap;
86
+
87
+		$this->adapter = $adapter;
88
+
89
+		$this->dispatcher = $dispatcher;
90
+
91
+		$this->manager = $manager;
92
+
93
+		$this->cache = new EntityCache($entityMap);
94
+	}
95
+
96
+	/**
97
+	 * Map results to a Collection.
98
+	 *
99
+	 * @param array|Collection $results
100
+	 *
101
+	 * @return Collection
102
+	 */
103
+	public function map($results, array $eagerLoads = []) : Collection
104
+	{
105
+		$builder = new ResultBuilder($this);
106
+
107
+		if ($results instanceof collection) {
108
+			// Get underlying collection array
109
+			$results = $results->all();
110
+		}
111
+
112
+		if (!is_array($results)) {
113
+			throw new InvalidArgumentException("'results' should be an array or collection.");
114
+		}
115
+
116
+		// First, we'll cast every single result to array
117
+		$results = array_map(function ($item) {
118
+			return (array) $item;
119
+		}, $results);
120
+
121
+		// Then, we'll cache every single results as raw attributes, before
122
+		// adding relationships, which will be cached when the relationship's
123
+		// query takes place.
124
+		$this->getEntityCache()->add($results);
125
+
126
+		$entities = $builder->build($results, $eagerLoads);
127
+
128
+		return $this->entityMap->newCollection($entities);
129
+	}
130
+
131
+	/**
132
+	 * Return all records for a mapped object.
133
+	 *
134
+	 * @return EntityCollection
135
+	 */
136
+	public function all()
137
+	{
138
+		return $this->query()->get();
139
+	}
140
+
141
+	/**
142
+	 * Persist an entity or an entity collection into the database.
143
+	 *
144
+	 * @param Mappable|\Traversable|array $entity
145
+	 *
146
+	 * @throws \InvalidArgumentException
147
+	 * @throws MappingException
148
+	 *
149
+	 * @return Mappable|\Traversable|array
150
+	 */
151
+	public function store($entity)
152
+	{
153
+		if ($this->manager->isTraversable($entity)) {
154
+			return $this->storeCollection($entity);
155
+		} else {
156
+			return $this->storeEntity($entity);
157
+		}
158
+	}
159
+
160
+	/**
161
+	 * Store an entity collection inside a single DB Transaction.
162
+	 *
163
+	 * @param \Traversable|array $entities
164
+	 *
165
+	 * @throws \InvalidArgumentException
166
+	 * @throws MappingException
167
+	 *
168
+	 * @return \Traversable|array
169
+	 */
170
+	protected function storeCollection($entities)
171
+	{
172
+		$this->adapter->beginTransaction();
173
+
174
+		foreach ($entities as $entity) {
175
+			$this->storeEntity($entity);
176
+		}
177
+
178
+		$this->adapter->commit();
179
+
180
+		return $entities;
181
+	}
182
+
183
+	/**
184
+	 * Store a single entity into the database.
185
+	 *
186
+	 * @param Mappable $entity
187
+	 *
188
+	 * @throws \InvalidArgumentException
189
+	 * @throws MappingException
190
+	 *
191
+	 * @return \Analogue\ORM\Entity
192
+	 */
193
+	protected function storeEntity($entity)
194
+	{   
195
+		$this->checkEntityType($entity);
196
+
197
+		$store = new Store($this->aggregate($entity), $this->newQueryBuilder());
198
+
199
+		return $store->execute();
200
+	}
201
+
202
+	/**
203
+	 * Check that the entity correspond to the current mapper.
204
+	 *
205
+	 * @param mixed $entity
206
+	 *
207
+	 * @throws InvalidArgumentException
208
+	 *
209
+	 * @return void
210
+	 */
211
+	protected function checkEntityType($entity)
212
+	{
213
+		if (get_class($entity) != $this->entityMap->getClass() && !is_subclass_of($entity, $this->entityMap->getClass())) {
214
+			$expected = $this->entityMap->getClass();
215
+			$actual = get_class($entity);
216
+			throw new InvalidArgumentException("Expected : $expected, got $actual.");
217
+		}
218
+	}
219
+
220
+	/**
221
+	 * Convert an entity into an aggregate root.
222
+	 *
223
+	 * @param mixed $entity
224
+	 *
225
+	 * @throws MappingException
226
+	 *
227
+	 * @return \Analogue\ORM\System\Aggregate
228
+	 */
229
+	protected function aggregate($entity)
230
+	{
231
+		return new Aggregate($entity);
232
+	}
233
+
234
+	/**
235
+	 * Get a the Underlying QueryAdapter.
236
+	 *
237
+	 * @return \Analogue\ORM\Drivers\QueryAdapter
238
+	 */
239
+	public function newQueryBuilder()
240
+	{
241
+		return $this->adapter->getQuery();
242
+	}
243
+
244
+	/**
245
+	 * Delete an entity or an entity collection from the database.
246
+	 *
247
+	 * @param  Mappable|\Traversable|array
248
+	 *
249
+	 * @throws MappingException
250
+	 * @throws \InvalidArgumentException
251
+	 *
252
+	 * @return \Traversable|array
253
+	 */
254
+	public function delete($entity)
255
+	{
256
+		if ($this->manager->isTraversable($entity)) {
257
+			return $this->deleteCollection($entity);
258
+		} else {
259
+			$this->deleteEntity($entity);
260
+		}
261
+	}
262
+
263
+	/**
264
+	 * Delete an Entity Collection inside a single db transaction.
265
+	 *
266
+	 * @param \Traversable|array $entities
267
+	 *
268
+	 * @throws \InvalidArgumentException
269
+	 * @throws MappingException
270
+	 *
271
+	 * @return \Traversable|array
272
+	 */
273
+	protected function deleteCollection($entities)
274
+	{
275
+		$this->adapter->beginTransaction();
276
+
277
+		foreach ($entities as $entity) {
278
+			$this->deleteEntity($entity);
279
+		}
280
+
281
+		$this->adapter->commit();
282
+
283
+		return $entities;
284
+	}
285
+
286
+	/**
287
+	 * Delete a single entity from the database.
288
+	 *
289
+	 * @param Mappable $entity
290
+	 *
291
+	 * @throws \InvalidArgumentException
292
+	 * @throws MappingException
293
+	 *
294
+	 * @return void
295
+	 */
296
+	protected function deleteEntity($entity)
297
+	{
298
+		$this->checkEntityType($entity);
299
+
300
+		$delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
301
+
302
+		$delete->execute();
303
+	}
304
+
305
+	/**
306
+	 * Return the entity map for this mapper.
307
+	 *
308
+	 * @return EntityMap
309
+	 */
310
+	public function getEntityMap()
311
+	{
312
+		return $this->entityMap;
313
+	}
314
+
315
+	/**
316
+	 * Get the entity cache for the current mapper.
317
+	 *
318
+	 * @return EntityCache $entityCache
319
+	 */
320
+	public function getEntityCache()
321
+	{
322
+		return $this->cache;
323
+	}
324
+
325
+	/**
326
+	 * Fire the given event for the entity.
327
+	 *
328
+	 * @param string               $event
329
+	 * @param \Analogue\ORM\Entity $entity
330
+	 * @param bool                 $halt
331
+	 *
332
+	 * @throws InvalidArgumentException
333
+	 *
334
+	 * @return mixed
335
+	 */
336
+	public function fireEvent($event, $entity, $halt = true)
337
+	{
338
+		if ($entity instanceof Wrapper) {
339
+			throw new InvalidArgumentException('Fired Event with invalid Entity Object');
340
+		}
341
+
342
+		$event = "analogue.{$event}.".$this->entityMap->getClass();
343
+
344
+		$method = $halt ? 'until' : 'fire';
345
+
346
+		return $this->dispatcher->$method($event, $entity);
347
+	}
348
+
349
+	/**
350
+	 * Register an entity event with the dispatcher.
351
+	 *
352
+	 * @param string   $event
353
+	 * @param \Closure $callback
354
+	 *
355
+	 * @return void
356
+	 */
357
+	public function registerEvent($event, $callback)
358
+	{
359
+		$name = $this->entityMap->getClass();
360
+
361
+		$this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
362
+	}
363
+
364
+	/**
365
+	 * Add a global scope to this mapper query builder.
366
+	 *
367
+	 * @param ScopeInterface $scope
368
+	 *
369
+	 * @return void
370
+	 */
371
+	public function addGlobalScope(ScopeInterface $scope)
372
+	{
373
+		$this->globalScopes[get_class($scope)] = $scope;
374
+	}
375
+
376
+	/**
377
+	 * Determine if the mapper has a global scope.
378
+	 *
379
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
380
+	 *
381
+	 * @return bool
382
+	 */
383
+	public function hasGlobalScope($scope)
384
+	{
385
+		return !is_null($this->getGlobalScope($scope));
386
+	}
387
+
388
+	/**
389
+	 * Get a global scope registered with the modal.
390
+	 *
391
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
392
+	 *
393
+	 * @return \Analogue\ORM\System\ScopeInterface|null
394
+	 */
395
+	public function getGlobalScope($scope)
396
+	{
397
+		return array_first($this->globalScopes, function ($key, $value) use ($scope) {
398
+			return $scope instanceof $value;
399
+		});
400
+	}
401
+
402
+	/**
403
+	 * Get a new query instance without a given scope.
404
+	 *
405
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
406
+	 *
407
+	 * @return \Analogue\ORM\System\Query
408
+	 */
409
+	public function newQueryWithoutScope($scope)
410
+	{
411
+		$this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
412
+
413
+		return $query;
414
+	}
415
+
416
+	/**
417
+	 * Get the Analogue Query Builder for this instance.
418
+	 *
419
+	 * @return \Analogue\ORM\System\Query
420
+	 */
421
+	public function getQuery()
422
+	{
423
+		$query = new Query($this, $this->adapter);
424
+
425
+		return $this->applyGlobalScopes($query);
426
+	}
427
+
428
+	/**
429
+	 * Apply all of the global scopes to an Analogue Query builder.
430
+	 *
431
+	 * @param Query $query
432
+	 *
433
+	 * @return \Analogue\ORM\System\Query
434
+	 */
435
+	public function applyGlobalScopes($query)
436
+	{
437
+		foreach ($this->getGlobalScopes() as $scope) {
438
+			$scope->apply($query, $this);
439
+		}
440
+
441
+		return $query;
442
+	}
443
+
444
+	/**
445
+	 * Get the global scopes for this class instance.
446
+	 *
447
+	 * @return \Analogue\ORM\System\ScopeInterface
448
+	 */
449
+	public function getGlobalScopes()
450
+	{
451
+		return $this->globalScopes;
452
+	}
453
+
454
+	/**
455
+	 * Add a dynamic method that extends the mapper/repository.
456
+	 *
457
+	 * @param string $command
458
+	 */
459
+	public function addCustomCommand($command)
460
+	{
461
+		$name = lcfirst(class_basename($command));
462
+
463
+		$this->customCommands[$name] = $command;
464
+	}
465
+
466
+	/**
467
+	 * Create a new instance of the mapped entity class.
468
+	 *
469
+	 * @return mixed
470
+	 */
471
+	public function newInstance()
472
+	{
473
+		$class = $this->entityMap->getClass();
474
+
475
+		if ($this->entityMap->useDependencyInjection()) {
476
+			return $this->newInstanceUsingDependencyInjection($class);
477
+		}
478
+
479
+		return $this->newInstanceUsingInstantiator($class);
480
+	}
481
+
482
+	/**
483
+	 * Return a new object instance using dependency injection.
484
+	 *
485
+	 * @param string $class
486
+	 *
487
+	 * @return mixed
488
+	 */
489
+	protected function newInstanceUsingDependencyInjection($class)
490
+	{
491
+		if (!class_exists(Container::class)) {
492
+			throw new ErrorException("Illuminate\Container\Container is required to use Dependency Injection");
493
+		}
494
+
495
+		return Container::getInstance()->make($class);
496
+	}
497
+
498
+	/**
499
+	 * Return a new object instance using doctrine's instantiator.
500
+	 *
501
+	 * @param string $class
502
+	 *
503
+	 * @return mixed
504
+	 */
505
+	protected function newInstanceUsingInstantiator($class)
506
+	{
507
+		$instantiator = new \Doctrine\Instantiator\Instantiator();
508
+
509
+		return $instantiator->instantiate($class);
510
+	}
511
+
512
+	/**
513
+	 * Get an unscoped Analogue Query Builder for this instance.
514
+	 *
515
+	 * @return \Analogue\ORM\System\Query
516
+	 */
517
+	public function globalQuery()
518
+	{
519
+		return $this->newQueryWithoutScopes();
520
+	}
521
+
522
+	/**
523
+	 * Get a new query builder that doesn't have any global scopes.
524
+	 *
525
+	 * @return Query
526
+	 */
527
+	public function newQueryWithoutScopes()
528
+	{
529
+		return $this->removeGlobalScopes($this->getQuery());
530
+	}
531
+
532
+	/**
533
+	 * Remove all of the global scopes from an Analogue Query builder.
534
+	 *
535
+	 * @param Query $query
536
+	 *
537
+	 * @return \Analogue\ORM\System\Query
538
+	 */
539
+	public function removeGlobalScopes($query)
540
+	{
541
+		foreach ($this->getGlobalScopes() as $scope) {
542
+			$scope->remove($query, $this);
543
+		}
544
+
545
+		return $query;
546
+	}
547
+
548
+	/**
549
+	 * Return the manager instance.
550
+	 *
551
+	 * @return \Analogue\ORM\System\Manager
552
+	 */
553
+	public function getManager()
554
+	{
555
+		return $this->manager;
556
+	}
557
+
558
+	/**
559
+	 * Dynamically handle calls to custom commands, or Redirects to query().
560
+	 *
561
+	 * @param string $method
562
+	 * @param array  $parameters
563
+	 *
564
+	 * @throws \Exception
565
+	 *
566
+	 * @return mixed
567
+	 */
568
+	public function __call($method, $parameters)
569
+	{
570
+		// Check if method is a custom command on the mapper
571
+		if ($this->hasCustomCommand($method)) {
572
+			if (count($parameters) == 0) {
573
+				throw new \Exception("$method must at least have 1 argument");
574
+			}
575
+
576
+			return $this->executeCustomCommand($method, $parameters[0]);
577
+		}
578
+
579
+		// Redirect call on a new query instance
580
+		return call_user_func_array([$this->query(), $method], $parameters);
581
+	}
582
+
583
+	/**
584
+	 * Check if this mapper supports this command.
585
+	 *
586
+	 * @param string $command
587
+	 *
588
+	 * @return bool
589
+	 */
590
+	public function hasCustomCommand($command)
591
+	{
592
+		return in_array($command, $this->getCustomCommands());
593
+	}
594
+
595
+	/**
596
+	 * Get all the custom commands registered on this mapper.
597
+	 *
598
+	 * @return array
599
+	 */
600
+	public function getCustomCommands()
601
+	{
602
+		return array_keys($this->customCommands);
603
+	}
604
+
605
+	/**
606
+	 * Execute a custom command on an Entity.
607
+	 *
608
+	 * @param string                 $command
609
+	 * @param mixed|Collection|array $entity
610
+	 *
611
+	 * @throws \InvalidArgumentException
612
+	 * @throws MappingException
613
+	 *
614
+	 * @return mixed
615
+	 */
616
+	public function executeCustomCommand($command, $entity)
617
+	{
618
+		$commandClass = $this->customCommands[$command];
619
+
620
+		if ($this->manager->isTraversable($entity)) {
621
+			foreach ($entity as $instance) {
622
+				$this->executeSingleCustomCommand($commandClass, $instance);
623
+			}
624
+		} else {
625
+			return $this->executeSingleCustomCommand($commandClass, $entity);
626
+		}
627
+	}
628
+
629
+	/**
630
+	 * Execute a single command instance.
631
+	 *
632
+	 * @param string $commandClass
633
+	 * @param mixed  $entity
634
+	 *
635
+	 * @throws \InvalidArgumentException
636
+	 * @throws MappingException
637
+	 *
638
+	 * @return mixed
639
+	 */
640
+	protected function executeSingleCustomCommand($commandClass, $entity)
641
+	{
642
+		$this->checkEntityType($entity);
643
+
644
+		$instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
645
+
646
+		return $instance->execute();
647
+	}
648
+
649
+	/**
650
+	 * Get the Analogue Query Builder for this instance.
651
+	 *
652
+	 * @return \Analogue\ORM\System\Query
653
+	 */
654
+	public function query()
655
+	{
656
+		return $this->getQuery();
657
+	}
658 658
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
         }
115 115
 
116 116
         // First, we'll cast every single result to array
117
-        $results = array_map(function ($item) {
117
+        $results = array_map(function($item) {
118 118
             return (array) $item;
119 119
         }, $results);
120 120
 
@@ -394,7 +394,7 @@  discard block
 block discarded – undo
394 394
      */
395 395
     public function getGlobalScope($scope)
396 396
     {
397
-        return array_first($this->globalScopes, function ($key, $value) use ($scope) {
397
+        return array_first($this->globalScopes, function($key, $value) use ($scope) {
398 398
             return $scope instanceof $value;
399 399
         });
400 400
     }
Please login to merge, or discard this patch.
src/System/Proxies/CollectionProxy.php 1 patch
Indentation   +1310 added lines, -1310 removed lines patch added patch discarded remove patch
@@ -9,1314 +9,1314 @@
 block discarded – undo
9 9
 
10 10
 class CollectionProxy extends EntityCollection implements ProxyInterface
11 11
 {
12
-    /**
13
-     * Indicate if the relationship has been lazy loaded.
14
-     *
15
-     * @var bool
16
-     */
17
-    protected $relationshipLoaded = false;
18
-
19
-    protected $addedItems = [];
20
-
21
-    /**
22
-     * Create a new collection.
23
-     *
24
-     * @param mixed  $entity
25
-     * @param string $relation
26
-     *
27
-     * @return void
28
-     */
29
-    public function __construct($entity, $relation)
30
-    {
31
-        $this->parentEntity = $entity;
32
-        $this->relationshipMethod = $relation;
33
-    }
34
-
35
-    /**
36
-     * Return Items that has been added without lady loading
37
-     * the underlying collection.
38
-     *
39
-     * @return array
40
-     */
41
-    public function getAddedItems()
42
-    {
43
-        return $this->addedItems;
44
-    }
45
-
46
-    /**
47
-     * Force initialization of the proxy.
48
-     *
49
-     * @return bool true if the proxy could be initialized
50
-     */
51
-    public function initializeProxy() : bool
52
-    {
53
-        if ($this->isProxyInitialized()) {
54
-            return true;
55
-        }
56
-
57
-        $relation = $this->relationshipMethod;
58
-        $entity = $this->parentEntity;
59
-
60
-        $entityMap = Manager::getMapper($entity)->getEntityMap();
61
-
62
-        $this->items = $entityMap->$relation($entity)->getResults($relation)->all() + $this->addedItems;
63
-
64
-        $this->relationshipLoaded = true;
65
-
66
-        return true;
67
-    }
68
-
69
-    /**
70
-     * Retrieves current initialization status of the proxy.
71
-     *
72
-     * @return bool
73
-     */
74
-    public function isProxyInitialized() : bool
75
-    {
76
-        return $this->relationshipLoaded;
77
-    }
78
-
79
-    /**
80
-     * Get all of the items in the collection.
81
-     *
82
-     * @return array
83
-     */
84
-    public function all()
85
-    {
86
-        $this->initializeProxy();
87
-
88
-        return parent::all();
89
-    }
90
-
91
-    /**
92
-     * Get the average value of a given key.
93
-     *
94
-     * @param callable|string|null $callback
95
-     *
96
-     * @return mixed
97
-     */
98
-    public function avg($callback = null)
99
-    {
100
-        $this->initializeProxy();
101
-
102
-        return parent::avg($callback);
103
-    }
104
-
105
-    /**
106
-     * Get the median of a given key.
107
-     *
108
-     * @param null $key
109
-     *
110
-     * @return mixed|null
111
-     */
112
-    public function median($key = null)
113
-    {
114
-        $this->initializeProxy();
115
-
116
-        return parent::median($key);
117
-    }
118
-
119
-    /**
120
-     * Get the mode of a given key.
121
-     *
122
-     * @param mixed $key
123
-     *
124
-     * @return array
125
-     */
126
-    public function mode($key = null)
127
-    {
128
-        $this->initializeProxy();
129
-
130
-        return parent::mode($key);
131
-    }
132
-
133
-    /**
134
-     * Collapse the collection of items into a single array.
135
-     *
136
-     * @return static
137
-     */
138
-    public function collapse()
139
-    {
140
-        $this->initializeProxy();
141
-
142
-        return parent::collapse();
143
-    }
144
-
145
-    /**
146
-     * Determine if an item exists in the collection.
147
-     *
148
-     * @param mixed $key
149
-     * @param mixed $value
150
-     *
151
-     * @return bool
152
-     */
153
-    public function contains($key, $operator = null, $value = null)
154
-    {
155
-        $this->initializeProxy();
156
-
157
-        return parent::contains($key, $operator, $value);
158
-    }
159
-
160
-    /**
161
-     * Determine if an item exists in the collection using strict comparison.
162
-     *
163
-     * @param mixed $key
164
-     * @param mixed $value
165
-     *
166
-     * @return bool
167
-     */
168
-    public function containsStrict($key, $value = null)
169
-    {
170
-        $this->initializeProxy();
171
-
172
-        return parent::containsStrict($key, $value);
173
-    }
174
-
175
-    /**
176
-     * Get the items in the collection that are not present in the given items.
177
-     *
178
-     * @param mixed $items
179
-     *
180
-     * @return static
181
-     */
182
-    public function diff($items)
183
-    {
184
-        $this->initializeProxy();
185
-
186
-        return parent::diff($items);
187
-    }
188
-
189
-    /**
190
-     * Get the items in the collection whose keys are not present in the given items.
191
-     *
192
-     * @param mixed $items
193
-     *
194
-     * @return static
195
-     */
196
-    public function diffKeys($items)
197
-    {
198
-        $this->initializeProxy();
199
-
200
-        return parent::diffKeys($items);
201
-    }
202
-
203
-    /**
204
-     * Execute a callback over each item.
205
-     *
206
-     * @param callable $callback
207
-     *
208
-     * @return $this
209
-     */
210
-    public function each(callable $callback)
211
-    {
212
-        $this->initializeProxy();
213
-
214
-        return parent::each($callback);
215
-    }
216
-
217
-    /**
218
-     * Create a new collection consisting of every n-th element.
219
-     *
220
-     * @param int $step
221
-     * @param int $offset
222
-     *
223
-     * @return static
224
-     */
225
-    public function every($key, $operator = null, $value = null)
226
-    {
227
-        $this->initializeProxy();
228
-
229
-        return parent::every($key, $operator, $value);
230
-    }
231
-
232
-    /**
233
-     * Get all items except for those with the specified keys.
234
-     *
235
-     * @param mixed $keys
236
-     *
237
-     * @return static
238
-     */
239
-    public function except($keys)
240
-    {
241
-        $this->initializeProxy();
242
-
243
-        return parent::except($keys);
244
-    }
245
-
246
-    /**
247
-     * Run a filter over each of the items.
248
-     *
249
-     * @param callable|null $callback
250
-     *
251
-     * @return static
252
-     */
253
-    public function filter(callable $callback = null)
254
-    {
255
-        $this->initializeProxy();
256
-
257
-        return parent::filter($callback);
258
-    }
259
-
260
-    /**
261
-     * Filter items by the given key value pair.
262
-     *
263
-     * @param string $key
264
-     * @param mixed  $operator
265
-     * @param mixed  $value
266
-     *
267
-     * @return static
268
-     */
269
-    public function where($key, $operator, $value = null)
270
-    {
271
-        $this->initializeProxy();
272
-
273
-        return parent::where($key, $operator, $value);
274
-    }
275
-
276
-    /**
277
-     * Filter items by the given key value pair using strict comparison.
278
-     *
279
-     * @param string $key
280
-     * @param mixed  $value
281
-     *
282
-     * @return static
283
-     */
284
-    public function whereStrict($key, $value)
285
-    {
286
-        $this->initializeProxy();
287
-
288
-        return parent::whereStrict($key, $value);
289
-    }
290
-
291
-    /**
292
-     * Filter items by the given key value pair.
293
-     *
294
-     * @param string $key
295
-     * @param mixed  $values
296
-     * @param bool   $strict
297
-     *
298
-     * @return static
299
-     */
300
-    public function whereIn($key, $values, $strict = false)
301
-    {
302
-        $this->initializeProxy();
303
-
304
-        return parent::whereIn($key, $values, $strict);
305
-    }
306
-
307
-    /**
308
-     * Filter items by the given key value pair using strict comparison.
309
-     *
310
-     * @param string $key
311
-     * @param mixed  $values
312
-     *
313
-     * @return static
314
-     */
315
-    public function whereInStrict($key, $values)
316
-    {
317
-        $this->initializeProxy();
318
-
319
-        return parent::whereInStrict($key, $values);
320
-    }
321
-
322
-    /**
323
-     * Get the first item from the collection.
324
-     *
325
-     * @param callable|null $callback
326
-     * @param mixed         $default
327
-     *
328
-     * @return mixed
329
-     */
330
-    public function first(callable $callback = null, $default = null)
331
-    {
332
-        // TODO Consider partial loading
333
-        $this->initializeProxy();
334
-
335
-        return parent::first($callback, $default);
336
-    }
337
-
338
-    /**
339
-     * Get a flattened array of the items in the collection.
340
-     *
341
-     * @param int $depth
342
-     *
343
-     * @return static
344
-     */
345
-    public function flatten($depth = INF)
346
-    {
347
-        $this->initializeProxy();
348
-
349
-        return parent::flatten($depth);
350
-    }
351
-
352
-    /**
353
-     * Flip the items in the collection.
354
-     *
355
-     * @return static
356
-     */
357
-    public function flip()
358
-    {
359
-        $this->initializeProxy();
360
-
361
-        return parent::flip();
362
-    }
363
-
364
-    /**
365
-     * Remove an item from the collection by key.
366
-     *
367
-     * @param string|array $keys
368
-     *
369
-     * @return $this
370
-     */
371
-    public function forget($keys)
372
-    {
373
-        // TODO, we could consider these as
374
-        // 'pending deletion', the same way that
375
-        // we treat added items
376
-        $this->initializeProxy();
377
-
378
-        return parent::forget($keys);
379
-    }
380
-
381
-    /**
382
-     * Get an item from the collection by key.
383
-     *
384
-     * @param mixed $key
385
-     * @param mixed $default
386
-     *
387
-     * @return mixed
388
-     */
389
-    public function get($key, $default = null)
390
-    {
391
-        // TODO : We could also consider partial loading
392
-        // here
393
-        $this->initializeProxy();
394
-
395
-        return parent::get($key, $default);
396
-    }
397
-
398
-    /**
399
-     * Group an associative array by a field or using a callback.
400
-     *
401
-     * @param callable|string $groupBy
402
-     * @param bool            $preserveKeys
403
-     *
404
-     * @return static
405
-     */
406
-    public function groupBy($groupBy, $preserveKeys = false)
407
-    {
408
-        $this->initializeProxy();
409
-
410
-        return parent::groupBy($groupBy, $preserveKeys);
411
-    }
412
-
413
-    /**
414
-     * Key an associative array by a field or using a callback.
415
-     *
416
-     * @param callable|string $keyBy
417
-     *
418
-     * @return static
419
-     */
420
-    public function keyBy($keyBy)
421
-    {
422
-        $this->initializeProxy();
423
-
424
-        return parent::keyBy($keyBy);
425
-    }
426
-
427
-    /**
428
-     * Determine if an item exists in the collection by key.
429
-     *
430
-     * @param mixed $key
431
-     *
432
-     * @return bool
433
-     */
434
-    public function has($key)
435
-    {
436
-        // TODO : we could do automagic here by directly
437
-        // calling the database if the collection hasn't
438
-        // been initialized yet.
439
-        // Potential issue is that several calls to this
440
-        // could cause a lot queries vs a single get query.
441
-        $this->initializeProxy();
442
-
443
-        return parent::has($key);
444
-    }
445
-
446
-    /**
447
-     * Concatenate values of a given key as a string.
448
-     *
449
-     * @param string $value
450
-     * @param string $glue
451
-     *
452
-     * @return string
453
-     */
454
-    public function implode($value, $glue = null)
455
-    {
456
-        $this->initializeProxy();
457
-
458
-        return parent::implode($value, $glue);
459
-    }
460
-
461
-    /**
462
-     * Intersect the collection with the given items.
463
-     *
464
-     * @param mixed $items
465
-     *
466
-     * @return static
467
-     */
468
-    public function intersect($items)
469
-    {
470
-        $this->initializeProxy();
471
-
472
-        return parent::intersect($items);
473
-    }
474
-
475
-    /**
476
-     * Determine if the collection is empty or not.
477
-     *
478
-     * @return bool
479
-     */
480
-    public function isEmpty()
481
-    {
482
-        $this->initializeProxy();
483
-
484
-        return parent::isEmpty();
485
-    }
486
-
487
-    /**
488
-     * Get the keys of the collection items.
489
-     *
490
-     * @return static
491
-     */
492
-    public function keys()
493
-    {
494
-        $this->initializeProxy();
495
-
496
-        return parent::keys();
497
-    }
498
-
499
-    /**
500
-     * Get the last item from the collection.
501
-     *
502
-     * @param callable|null $callback
503
-     * @param mixed         $default
504
-     *
505
-     * @return mixed
506
-     */
507
-    public function last(callable $callback = null, $default = null)
508
-    {
509
-        // TODO : we could do partial loading there as well
510
-        $this->initializeProxy();
511
-
512
-        return parent::last($callback, $default);
513
-    }
514
-
515
-    /**
516
-     * Get the values of a given key.
517
-     *
518
-     * @param string      $value
519
-     * @param string|null $key
520
-     *
521
-     * @return static
522
-     */
523
-    public function pluck($value, $key = null)
524
-    {
525
-        // TODO : automagic call to QB if not initialized
526
-        $this->initializeProxy();
527
-
528
-        return parent::pluck($value, $key);
529
-    }
530
-
531
-    /**
532
-     * Run a map over each of the items.
533
-     *
534
-     * @param callable $callback
535
-     *
536
-     * @return static
537
-     */
538
-    public function map(callable $callback)
539
-    {
540
-        $this->initializeProxy();
541
-
542
-        return parent::map($callback);
543
-    }
544
-
545
-    /**
546
-     * Run an associative map over each of the items.
547
-     *
548
-     * The callback should return an associative array with a single key/value pair.
549
-     *
550
-     * @param callable $callback
551
-     *
552
-     * @return static
553
-     */
554
-    public function mapWithKeys(callable $callback)
555
-    {
556
-        $this->initializeProxy();
557
-
558
-        return parent::mapWithKeys($callback);
559
-    }
560
-
561
-    /**
562
-     * Map a collection and flatten the result by a single level.
563
-     *
564
-     * @param callable $callback
565
-     *
566
-     * @return static
567
-     */
568
-    public function flatMap(callable $callback)
569
-    {
570
-        $this->initializeProxy();
571
-
572
-        return parent::flatMap($callback);
573
-    }
574
-
575
-    /**
576
-     * Get the max value of a given key.
577
-     *
578
-     * @param callable|string|null $callback
579
-     *
580
-     * @return mixed
581
-     */
582
-    public function max($callback = null)
583
-    {
584
-        $this->initializeProxy();
585
-
586
-        return parent::max($callback);
587
-    }
588
-
589
-    /**
590
-     * Merge the collection with the given items.
591
-     *
592
-     * @param mixed $items
593
-     *
594
-     * @return static
595
-     */
596
-    public function merge($items)
597
-    {
598
-        // TODO : Check if the EntityCollection
599
-        // returns a native Collection, as it
600
-        // is what we want here
601
-        $this->initializeProxy();
602
-
603
-        return parent::merge($items);
604
-    }
605
-
606
-    /**
607
-     * Create a collection by using this collection for keys and another for its values.
608
-     *
609
-     * @param mixed $values
610
-     *
611
-     * @return static
612
-     */
613
-    public function combine($values)
614
-    {
615
-        // TODO : Check if the EntityCollection
616
-        // returns a native Collection, as it
617
-        // is what we want here
618
-        $this->initializeProxy();
619
-
620
-        return parent::combine($values);
621
-    }
622
-
623
-    /**
624
-     * Union the collection with the given items.
625
-     *
626
-     * @param mixed $items
627
-     *
628
-     * @return static
629
-     */
630
-    public function union($items)
631
-    {
632
-        // TODO : Check if the EntityCollection
633
-        // returns a native Collection, as it
634
-        // is what we want here
635
-        $this->initializeProxy();
636
-
637
-        return parent::union($items);
638
-    }
639
-
640
-    /**
641
-     * Get the min value of a given key.
642
-     *
643
-     * @param callable|string|null $callback
644
-     *
645
-     * @return mixed
646
-     */
647
-    public function min($callback = null)
648
-    {
649
-        // TODO : we could rely on the QB
650
-        // for thos, if initialization has not
651
-        // take place yet
652
-        $this->initializeProxy();
653
-
654
-        return parent::min($callback);
655
-    }
656
-
657
-    /**
658
-     * Create a new collection consisting of every n-th element.
659
-     *
660
-     * @param int $step
661
-     * @param int $offset
662
-     *
663
-     * @return static
664
-     */
665
-    public function nth($step, $offset = 0)
666
-    {
667
-        $this->initializeProxy();
668
-
669
-        return parent::nth($step, $offset);
670
-    }
671
-
672
-    /**
673
-     * Get the items with the specified keys.
674
-     *
675
-     * @param mixed $keys
676
-     *
677
-     * @return static
678
-     */
679
-    public function only($keys)
680
-    {
681
-        // TODO : we could rely on the QB if
682
-        // the collection hasn't been initialized yet
683
-        $this->initializeProxy();
684
-
685
-        return parent::only($keys);
686
-    }
687
-
688
-    /**
689
-     * "Paginate" the collection by slicing it into a smaller collection.
690
-     *
691
-     * @param int $page
692
-     * @param int $perPage
693
-     *
694
-     * @return static
695
-     */
696
-    public function forPage($page, $perPage)
697
-    {
698
-        // TODO : check possibility of partial loading
699
-        // if not initialized
700
-        $this->initializeProxy();
701
-
702
-        return parent::forPage($page, $perPage);
703
-    }
704
-
705
-    /**
706
-     * Partition the collection into two arrays using the given callback or key.
707
-     *
708
-     * @param callable|string $callback
709
-     *
710
-     * @return static
711
-     */
712
-    public function partition($callback)
713
-    {
714
-        $this->initializeProxy();
715
-
716
-        return parent::partition($callback);
717
-    }
718
-
719
-    /**
720
-     * Pass the collection to the given callback and return the result.
721
-     *
722
-     * @param callable $callback
723
-     *
724
-     * @return mixed
725
-     */
726
-    public function pipe(callable $callback)
727
-    {
728
-        $this->initializeProxy();
729
-
730
-        return parent::pipe($callback);
731
-    }
732
-
733
-    /**
734
-     * Get and remove the last item from the collection.
735
-     *
736
-     * @return mixed
737
-     */
738
-    public function pop()
739
-    {
740
-        $this->initializeProxy();
741
-
742
-        return parent::pop();
743
-    }
744
-
745
-    /**
746
-     * Push an item onto the beginning of the collection.
747
-     *
748
-     * @param mixed $value
749
-     * @param mixed $key
750
-     *
751
-     * @return $this
752
-     */
753
-    public function prepend($value, $key = null)
754
-    {
755
-        // TODO : partial adding of values.
756
-        // we could have a $prepended , and $pushed arrays
757
-        // which we would combine at full initialization
758
-
759
-        $this->initializeProxy();
760
-
761
-        return parent::prepend($value, $key);
762
-    }
763
-
764
-    /**
765
-     * Push an item onto the end of the collection.
766
-     *
767
-     * @param mixed $value
768
-     *
769
-     * @return $this
770
-     */
771
-    public function push($value)
772
-    {
773
-        // TODO : partial adding of values.
774
-        // we could have a $prepended , and $pushed arrays
775
-        // which we would combine at full initialization
776
-
777
-        $this->initializeProxy();
778
-
779
-        return parent::push($value);
780
-    }
781
-
782
-    /**
783
-     * Get and remove an item from the collection.
784
-     *
785
-     * @param mixed $key
786
-     * @param mixed $default
787
-     *
788
-     * @return mixed
789
-     */
790
-    public function pull($key, $default = null)
791
-    {
792
-        // TODO : QB query if the collection
793
-        // hasn't been initialized yet
794
-
795
-        $this->initializeProxy();
796
-
797
-        return parent::pull($key, $default);
798
-    }
799
-
800
-    /**
801
-     * Put an item in the collection by key.
802
-     *
803
-     * @param mixed $key
804
-     * @param mixed $value
805
-     *
806
-     * @return $this
807
-     */
808
-    public function put($key, $value)
809
-    {
810
-        // TODO : Partial loading ?
811
-
812
-        $this->initializeProxy();
813
-
814
-        return parent::put($key, $value);
815
-    }
816
-
817
-    /**
818
-     * Get one or more items randomly from the collection.
819
-     *
820
-     * @param int $amount
821
-     *
822
-     * @throws \InvalidArgumentException
823
-     *
824
-     * @return mixed
825
-     */
826
-    public function random($amount = 1)
827
-    {
828
-        // TODO : we could optimize this by only
829
-        // fetching the keys from the database
830
-        // and performing partial loading
831
-
832
-        $this->initializeProxy();
833
-
834
-        return parent::random($amount);
835
-    }
836
-
837
-    /**
838
-     * Reduce the collection to a single value.
839
-     *
840
-     * @param callable $callback
841
-     * @param mixed    $initial
842
-     *
843
-     * @return mixed
844
-     */
845
-    public function reduce(callable $callback, $initial = null)
846
-    {
847
-        $this->initializeProxy();
848
-
849
-        return parent::reduce($callback, $initial);
850
-    }
851
-
852
-    /**
853
-     * Create a collection of all elements that do not pass a given truth test.
854
-     *
855
-     * @param callable|mixed $callback
856
-     *
857
-     * @return static
858
-     */
859
-    public function reject($callback)
860
-    {
861
-        $this->initializeProxy();
862
-
863
-        return parent::reject($callback);
864
-    }
865
-
866
-    /**
867
-     * Reverse items order.
868
-     *
869
-     * @return static
870
-     */
871
-    public function reverse()
872
-    {
873
-        $this->initializeProxy();
874
-
875
-        return parent::reverse();
876
-    }
877
-
878
-    /**
879
-     * Search the collection for a given value and return the corresponding key if successful.
880
-     *
881
-     * @param mixed $value
882
-     * @param bool  $strict
883
-     *
884
-     * @return mixed
885
-     */
886
-    public function search($value, $strict = false)
887
-    {
888
-        $this->initializeProxy();
889
-
890
-        return parent::search($value, $strict);
891
-    }
892
-
893
-    /**
894
-     * Get and remove the first item from the collection.
895
-     *
896
-     * @return mixed
897
-     */
898
-    public function shift()
899
-    {
900
-        // Todo : Partial Removing
901
-        // we could have a pending removal array
902
-        $this->initializeProxy();
903
-
904
-        return parent::shift();
905
-    }
906
-
907
-    /**
908
-     * Shuffle the items in the collection.
909
-     *
910
-     * @param int $seed
911
-     *
912
-     * @return static
913
-     */
914
-    public function shuffle($seed = null)
915
-    {
916
-        $this->initializeProxy();
917
-
918
-        return parent::shuffle($seed);
919
-    }
920
-
921
-    /**
922
-     * Slice the underlying collection array.
923
-     *
924
-     * @param int $offset
925
-     * @param int $length
926
-     *
927
-     * @return static
928
-     */
929
-    public function slice($offset, $length = null)
930
-    {
931
-        $this->initializeProxy();
932
-
933
-        return parent::slice($offset, $length);
934
-    }
935
-
936
-    /**
937
-     * Split a collection into a certain number of groups.
938
-     *
939
-     * @param int $numberOfGroups
940
-     *
941
-     * @return static
942
-     */
943
-    public function split($numberOfGroups)
944
-    {
945
-        $this->initializeProxy();
946
-
947
-        return parent::split($numberOfGroups);
948
-    }
949
-
950
-    /**
951
-     * Chunk the underlying collection array.
952
-     *
953
-     * @param int $size
954
-     *
955
-     * @return static
956
-     */
957
-    public function chunk($size)
958
-    {
959
-        // TODO : partial loading ?
960
-        $this->initializeProxy();
961
-
962
-        return parent::chunk($size);
963
-    }
964
-
965
-    /**
966
-     * Sort through each item with a callback.
967
-     *
968
-     * @param callable|null $callback
969
-     *
970
-     * @return static
971
-     */
972
-    public function sort(callable $callback = null)
973
-    {
974
-        $this->initializeProxy();
975
-
976
-        return parent::sort($callback);
977
-    }
978
-
979
-    /**
980
-     * Sort the collection using the given callback.
981
-     *
982
-     * @param callable|string $callback
983
-     * @param int             $options
984
-     * @param bool            $descending
985
-     *
986
-     * @return static
987
-     */
988
-    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
989
-    {
990
-        $this->initializeProxy();
991
-
992
-        return parent::sort($callback, $options, $descending);
993
-    }
994
-
995
-    /**
996
-     * Splice a portion of the underlying collection array.
997
-     *
998
-     * @param int      $offset
999
-     * @param int|null $length
1000
-     * @param mixed    $replacement
1001
-     *
1002
-     * @return static
1003
-     */
1004
-    public function splice($offset, $length = null, $replacement = [])
1005
-    {
1006
-        $this->initializeProxy();
1007
-
1008
-        return parent::splice($offset, $length, $replacement);
1009
-    }
1010
-
1011
-    /**
1012
-     * Get the sum of the given values.
1013
-     *
1014
-     * @param callable|string|null $callback
1015
-     *
1016
-     * @return mixed
1017
-     */
1018
-    public function sum($callback = null)
1019
-    {
1020
-        $this->initializeProxy();
1021
-
1022
-        return parent::sum($callback);
1023
-    }
1024
-
1025
-    /**
1026
-     * Take the first or last {$limit} items.
1027
-     *
1028
-     * @param int $limit
1029
-     *
1030
-     * @return static
1031
-     */
1032
-    public function take($limit)
1033
-    {
1034
-        // TODO: partial loading
1035
-        $this->initializeProxy();
1036
-
1037
-        return parent::take($limit);
1038
-    }
1039
-
1040
-    /**
1041
-     * Pass the collection to the given callback and then return it.
1042
-     *
1043
-     * @param callable $callback
1044
-     *
1045
-     * @return $this
1046
-     */
1047
-    public function tap(callable $callback)
1048
-    {
1049
-        $this->initializeProxy();
1050
-
1051
-        return parent::tap($this);
1052
-    }
1053
-
1054
-    /**
1055
-     * Transform each item in the collection using a callback.
1056
-     *
1057
-     * @param callable $callback
1058
-     *
1059
-     * @return $this
1060
-     */
1061
-    public function transform(callable $callback)
1062
-    {
1063
-        $this->initializeProxy();
1064
-
1065
-        return parent::transform($callback);
1066
-    }
1067
-
1068
-    /**
1069
-     * Return only unique items from the collection array.
1070
-     *
1071
-     * @param string|callable|null $key
1072
-     * @param bool                 $strict
1073
-     *
1074
-     * @return static
1075
-     */
1076
-    public function unique($key = null, $strict = false)
1077
-    {
1078
-        $this->initializeProxy();
1079
-
1080
-        return parent::unique($key, $strict);
1081
-    }
1082
-
1083
-    /**
1084
-     * Reset the keys on the underlying array.
1085
-     *
1086
-     * @return static
1087
-     */
1088
-    public function values()
1089
-    {
1090
-        $this->initializeProxy();
1091
-
1092
-        return parent::values();
1093
-    }
1094
-
1095
-    /**
1096
-     * Apply the callback if the value is truthy.
1097
-     *
1098
-     * @param  bool  $value
1099
-     * @param  callable  $callback
1100
-     * @return mixed
1101
-     */
1102
-    public function when($value, callable $callback)
1103
-    {
1104
-        $this->initializeProxy();
1105
-
1106
-        return parent::when($value, $callback);
1107
-    }
1108
-
1109
-    /**
1110
-     * Zip the collection together with one or more arrays.
1111
-     *
1112
-     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1113
-     *      => [[1, 4], [2, 5], [3, 6]]
1114
-     *
1115
-     * @param mixed ...$items
1116
-     *
1117
-     * @return static
1118
-     */
1119
-    public function zip($items)
1120
-    {
1121
-        $this->initializeProxy();
1122
-
1123
-        return parent::zip($items);
1124
-    }
1125
-
1126
-    /**
1127
-     * Get the collection of items as a plain array.
1128
-     *
1129
-     * @return array
1130
-     */
1131
-    public function toArray()
1132
-    {
1133
-        // If this is called on all subsequent proxy,
1134
-        // this would eventually trigger all lazy loading,
1135
-        // which is NOT what we would expect...
1136
-        // TODO : must think of this.
1137
-        $this->initializeProxy();
1138
-
1139
-        return parent::toArray();
1140
-    }
1141
-
1142
-    /**
1143
-     * Convert the object into something JSON serializable.
1144
-     *
1145
-     * @return array
1146
-     */
1147
-    public function jsonSerialize()
1148
-    {
1149
-        // If this is called on all subsequent proxy,
1150
-        // this would eventually trigger all lazy loading,
1151
-        // which is NOT what we would expect...
1152
-        // TODO : must think of this.
1153
-        $this->initializeProxy();
1154
-
1155
-        return parent::jsonSerialize();
1156
-    }
1157
-
1158
-    /**
1159
-     * Get the collection of items as JSON.
1160
-     *
1161
-     * @param int $options
1162
-     *
1163
-     * @return string
1164
-     */
1165
-    public function toJson($options = 0)
1166
-    {
1167
-        // If this is called on all subsequent proxy,
1168
-        // this would eventually trigger all lazy loading,
1169
-        // which is NOT what we would expect...
1170
-        // TODO : must think of this.
1171
-        $this->initializeProxy();
1172
-
1173
-        return parent::toJson($options);
1174
-    }
1175
-
1176
-    /**
1177
-     * Get an iterator for the items.
1178
-     *
1179
-     * @return \ArrayIterator
1180
-     */
1181
-    public function getIterator()
1182
-    {
1183
-        $this->initializeProxy();
1184
-
1185
-        return parent::getIterator();
1186
-    }
1187
-
1188
-    /**
1189
-     * Get a CachingIterator instance.
1190
-     *
1191
-     * @param int $flags
1192
-     *
1193
-     * @return \CachingIterator
1194
-     */
1195
-    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1196
-    {
1197
-        $this->initializeProxy();
1198
-
1199
-        return parent::getCachingIterator($flags);
1200
-    }
1201
-
1202
-    /**
1203
-     * Count the number of items in the collection.
1204
-     *
1205
-     * @return int
1206
-     */
1207
-    public function count()
1208
-    {
1209
-        // TODO rely on QB if not initialized
1210
-        $this->initializeProxy();
1211
-
1212
-        return parent::count();
1213
-    }
1214
-
1215
-    /**
1216
-     * Get a base Support collection instance from this collection.
1217
-     *
1218
-     * @return \Illuminate\Support\Collection
1219
-     */
1220
-    public function toBase()
1221
-    {
1222
-        $this->initializeProxy();
1223
-
1224
-        return parent::toBase();
1225
-    }
1226
-
1227
-    /**
1228
-     * Determine if an item exists at an offset.
1229
-     *
1230
-     * @param mixed $key
1231
-     *
1232
-     * @return bool
1233
-     */
1234
-    public function offsetExists($key)
1235
-    {
1236
-        // TODO rely on QB if no collection
1237
-        // initialized
1238
-        $this->initializeProxy();
1239
-
1240
-        return parent::offsetExists($key);
1241
-    }
1242
-
1243
-    /**
1244
-     * Get an item at a given offset.
1245
-     *
1246
-     * @param mixed $key
1247
-     *
1248
-     * @return mixed
1249
-     */
1250
-    public function offsetGet($key)
1251
-    {
1252
-        // TODO rely on partial init if no collection
1253
-        // initialized
1254
-        $this->initializeProxy();
1255
-
1256
-        return parent::offsetGet($key);
1257
-    }
1258
-
1259
-    /**
1260
-     * Set the item at a given offset.
1261
-     *
1262
-     * @param mixed $key
1263
-     * @param mixed $value
1264
-     *
1265
-     * @return void
1266
-     */
1267
-    public function offsetSet($key, $value)
1268
-    {
1269
-        // TODO : think of the use of it into a ProxyCollection
1270
-        // context
1271
-        $this->initializeProxy();
1272
-
1273
-        return parent::offsetSet($key, $value);
1274
-    }
1275
-
1276
-    /**
1277
-     * Unset the item at a given offset.
1278
-     *
1279
-     * @param string $key
1280
-     *
1281
-     * @return void
1282
-     */
1283
-    public function offsetUnset($key)
1284
-    {
1285
-        // TODO : think of the use of it into a ProxyCollection
1286
-        // context
1287
-        $this->initializeProxy();
1288
-
1289
-        return parent::offsetUnset($key);
1290
-    }
1291
-
1292
-    /**
1293
-     * Dynamically access collection proxies.
1294
-     *
1295
-     * @param string $key
1296
-     *
1297
-     * @throws \Exception
1298
-     *
1299
-     * @return mixed
1300
-     */
1301
-    public function __get($key)
1302
-    {
1303
-        parent::__get($key);
1304
-    }
1305
-
1306
-    /**
1307
-     * Dynamically handle calls to the class.
1308
-     *
1309
-     * @param string $method
1310
-     * @param array  $parameters
1311
-     *
1312
-     * @throws \BadMethodCallException
1313
-     *
1314
-     * @return mixed
1315
-     */
1316
-    public function __call($method, $parameters)
1317
-    {
1318
-        $this->initializeProxy();
1319
-
1320
-        return parent::__call($method, $parameters);
1321
-    }
12
+	/**
13
+	 * Indicate if the relationship has been lazy loaded.
14
+	 *
15
+	 * @var bool
16
+	 */
17
+	protected $relationshipLoaded = false;
18
+
19
+	protected $addedItems = [];
20
+
21
+	/**
22
+	 * Create a new collection.
23
+	 *
24
+	 * @param mixed  $entity
25
+	 * @param string $relation
26
+	 *
27
+	 * @return void
28
+	 */
29
+	public function __construct($entity, $relation)
30
+	{
31
+		$this->parentEntity = $entity;
32
+		$this->relationshipMethod = $relation;
33
+	}
34
+
35
+	/**
36
+	 * Return Items that has been added without lady loading
37
+	 * the underlying collection.
38
+	 *
39
+	 * @return array
40
+	 */
41
+	public function getAddedItems()
42
+	{
43
+		return $this->addedItems;
44
+	}
45
+
46
+	/**
47
+	 * Force initialization of the proxy.
48
+	 *
49
+	 * @return bool true if the proxy could be initialized
50
+	 */
51
+	public function initializeProxy() : bool
52
+	{
53
+		if ($this->isProxyInitialized()) {
54
+			return true;
55
+		}
56
+
57
+		$relation = $this->relationshipMethod;
58
+		$entity = $this->parentEntity;
59
+
60
+		$entityMap = Manager::getMapper($entity)->getEntityMap();
61
+
62
+		$this->items = $entityMap->$relation($entity)->getResults($relation)->all() + $this->addedItems;
63
+
64
+		$this->relationshipLoaded = true;
65
+
66
+		return true;
67
+	}
68
+
69
+	/**
70
+	 * Retrieves current initialization status of the proxy.
71
+	 *
72
+	 * @return bool
73
+	 */
74
+	public function isProxyInitialized() : bool
75
+	{
76
+		return $this->relationshipLoaded;
77
+	}
78
+
79
+	/**
80
+	 * Get all of the items in the collection.
81
+	 *
82
+	 * @return array
83
+	 */
84
+	public function all()
85
+	{
86
+		$this->initializeProxy();
87
+
88
+		return parent::all();
89
+	}
90
+
91
+	/**
92
+	 * Get the average value of a given key.
93
+	 *
94
+	 * @param callable|string|null $callback
95
+	 *
96
+	 * @return mixed
97
+	 */
98
+	public function avg($callback = null)
99
+	{
100
+		$this->initializeProxy();
101
+
102
+		return parent::avg($callback);
103
+	}
104
+
105
+	/**
106
+	 * Get the median of a given key.
107
+	 *
108
+	 * @param null $key
109
+	 *
110
+	 * @return mixed|null
111
+	 */
112
+	public function median($key = null)
113
+	{
114
+		$this->initializeProxy();
115
+
116
+		return parent::median($key);
117
+	}
118
+
119
+	/**
120
+	 * Get the mode of a given key.
121
+	 *
122
+	 * @param mixed $key
123
+	 *
124
+	 * @return array
125
+	 */
126
+	public function mode($key = null)
127
+	{
128
+		$this->initializeProxy();
129
+
130
+		return parent::mode($key);
131
+	}
132
+
133
+	/**
134
+	 * Collapse the collection of items into a single array.
135
+	 *
136
+	 * @return static
137
+	 */
138
+	public function collapse()
139
+	{
140
+		$this->initializeProxy();
141
+
142
+		return parent::collapse();
143
+	}
144
+
145
+	/**
146
+	 * Determine if an item exists in the collection.
147
+	 *
148
+	 * @param mixed $key
149
+	 * @param mixed $value
150
+	 *
151
+	 * @return bool
152
+	 */
153
+	public function contains($key, $operator = null, $value = null)
154
+	{
155
+		$this->initializeProxy();
156
+
157
+		return parent::contains($key, $operator, $value);
158
+	}
159
+
160
+	/**
161
+	 * Determine if an item exists in the collection using strict comparison.
162
+	 *
163
+	 * @param mixed $key
164
+	 * @param mixed $value
165
+	 *
166
+	 * @return bool
167
+	 */
168
+	public function containsStrict($key, $value = null)
169
+	{
170
+		$this->initializeProxy();
171
+
172
+		return parent::containsStrict($key, $value);
173
+	}
174
+
175
+	/**
176
+	 * Get the items in the collection that are not present in the given items.
177
+	 *
178
+	 * @param mixed $items
179
+	 *
180
+	 * @return static
181
+	 */
182
+	public function diff($items)
183
+	{
184
+		$this->initializeProxy();
185
+
186
+		return parent::diff($items);
187
+	}
188
+
189
+	/**
190
+	 * Get the items in the collection whose keys are not present in the given items.
191
+	 *
192
+	 * @param mixed $items
193
+	 *
194
+	 * @return static
195
+	 */
196
+	public function diffKeys($items)
197
+	{
198
+		$this->initializeProxy();
199
+
200
+		return parent::diffKeys($items);
201
+	}
202
+
203
+	/**
204
+	 * Execute a callback over each item.
205
+	 *
206
+	 * @param callable $callback
207
+	 *
208
+	 * @return $this
209
+	 */
210
+	public function each(callable $callback)
211
+	{
212
+		$this->initializeProxy();
213
+
214
+		return parent::each($callback);
215
+	}
216
+
217
+	/**
218
+	 * Create a new collection consisting of every n-th element.
219
+	 *
220
+	 * @param int $step
221
+	 * @param int $offset
222
+	 *
223
+	 * @return static
224
+	 */
225
+	public function every($key, $operator = null, $value = null)
226
+	{
227
+		$this->initializeProxy();
228
+
229
+		return parent::every($key, $operator, $value);
230
+	}
231
+
232
+	/**
233
+	 * Get all items except for those with the specified keys.
234
+	 *
235
+	 * @param mixed $keys
236
+	 *
237
+	 * @return static
238
+	 */
239
+	public function except($keys)
240
+	{
241
+		$this->initializeProxy();
242
+
243
+		return parent::except($keys);
244
+	}
245
+
246
+	/**
247
+	 * Run a filter over each of the items.
248
+	 *
249
+	 * @param callable|null $callback
250
+	 *
251
+	 * @return static
252
+	 */
253
+	public function filter(callable $callback = null)
254
+	{
255
+		$this->initializeProxy();
256
+
257
+		return parent::filter($callback);
258
+	}
259
+
260
+	/**
261
+	 * Filter items by the given key value pair.
262
+	 *
263
+	 * @param string $key
264
+	 * @param mixed  $operator
265
+	 * @param mixed  $value
266
+	 *
267
+	 * @return static
268
+	 */
269
+	public function where($key, $operator, $value = null)
270
+	{
271
+		$this->initializeProxy();
272
+
273
+		return parent::where($key, $operator, $value);
274
+	}
275
+
276
+	/**
277
+	 * Filter items by the given key value pair using strict comparison.
278
+	 *
279
+	 * @param string $key
280
+	 * @param mixed  $value
281
+	 *
282
+	 * @return static
283
+	 */
284
+	public function whereStrict($key, $value)
285
+	{
286
+		$this->initializeProxy();
287
+
288
+		return parent::whereStrict($key, $value);
289
+	}
290
+
291
+	/**
292
+	 * Filter items by the given key value pair.
293
+	 *
294
+	 * @param string $key
295
+	 * @param mixed  $values
296
+	 * @param bool   $strict
297
+	 *
298
+	 * @return static
299
+	 */
300
+	public function whereIn($key, $values, $strict = false)
301
+	{
302
+		$this->initializeProxy();
303
+
304
+		return parent::whereIn($key, $values, $strict);
305
+	}
306
+
307
+	/**
308
+	 * Filter items by the given key value pair using strict comparison.
309
+	 *
310
+	 * @param string $key
311
+	 * @param mixed  $values
312
+	 *
313
+	 * @return static
314
+	 */
315
+	public function whereInStrict($key, $values)
316
+	{
317
+		$this->initializeProxy();
318
+
319
+		return parent::whereInStrict($key, $values);
320
+	}
321
+
322
+	/**
323
+	 * Get the first item from the collection.
324
+	 *
325
+	 * @param callable|null $callback
326
+	 * @param mixed         $default
327
+	 *
328
+	 * @return mixed
329
+	 */
330
+	public function first(callable $callback = null, $default = null)
331
+	{
332
+		// TODO Consider partial loading
333
+		$this->initializeProxy();
334
+
335
+		return parent::first($callback, $default);
336
+	}
337
+
338
+	/**
339
+	 * Get a flattened array of the items in the collection.
340
+	 *
341
+	 * @param int $depth
342
+	 *
343
+	 * @return static
344
+	 */
345
+	public function flatten($depth = INF)
346
+	{
347
+		$this->initializeProxy();
348
+
349
+		return parent::flatten($depth);
350
+	}
351
+
352
+	/**
353
+	 * Flip the items in the collection.
354
+	 *
355
+	 * @return static
356
+	 */
357
+	public function flip()
358
+	{
359
+		$this->initializeProxy();
360
+
361
+		return parent::flip();
362
+	}
363
+
364
+	/**
365
+	 * Remove an item from the collection by key.
366
+	 *
367
+	 * @param string|array $keys
368
+	 *
369
+	 * @return $this
370
+	 */
371
+	public function forget($keys)
372
+	{
373
+		// TODO, we could consider these as
374
+		// 'pending deletion', the same way that
375
+		// we treat added items
376
+		$this->initializeProxy();
377
+
378
+		return parent::forget($keys);
379
+	}
380
+
381
+	/**
382
+	 * Get an item from the collection by key.
383
+	 *
384
+	 * @param mixed $key
385
+	 * @param mixed $default
386
+	 *
387
+	 * @return mixed
388
+	 */
389
+	public function get($key, $default = null)
390
+	{
391
+		// TODO : We could also consider partial loading
392
+		// here
393
+		$this->initializeProxy();
394
+
395
+		return parent::get($key, $default);
396
+	}
397
+
398
+	/**
399
+	 * Group an associative array by a field or using a callback.
400
+	 *
401
+	 * @param callable|string $groupBy
402
+	 * @param bool            $preserveKeys
403
+	 *
404
+	 * @return static
405
+	 */
406
+	public function groupBy($groupBy, $preserveKeys = false)
407
+	{
408
+		$this->initializeProxy();
409
+
410
+		return parent::groupBy($groupBy, $preserveKeys);
411
+	}
412
+
413
+	/**
414
+	 * Key an associative array by a field or using a callback.
415
+	 *
416
+	 * @param callable|string $keyBy
417
+	 *
418
+	 * @return static
419
+	 */
420
+	public function keyBy($keyBy)
421
+	{
422
+		$this->initializeProxy();
423
+
424
+		return parent::keyBy($keyBy);
425
+	}
426
+
427
+	/**
428
+	 * Determine if an item exists in the collection by key.
429
+	 *
430
+	 * @param mixed $key
431
+	 *
432
+	 * @return bool
433
+	 */
434
+	public function has($key)
435
+	{
436
+		// TODO : we could do automagic here by directly
437
+		// calling the database if the collection hasn't
438
+		// been initialized yet.
439
+		// Potential issue is that several calls to this
440
+		// could cause a lot queries vs a single get query.
441
+		$this->initializeProxy();
442
+
443
+		return parent::has($key);
444
+	}
445
+
446
+	/**
447
+	 * Concatenate values of a given key as a string.
448
+	 *
449
+	 * @param string $value
450
+	 * @param string $glue
451
+	 *
452
+	 * @return string
453
+	 */
454
+	public function implode($value, $glue = null)
455
+	{
456
+		$this->initializeProxy();
457
+
458
+		return parent::implode($value, $glue);
459
+	}
460
+
461
+	/**
462
+	 * Intersect the collection with the given items.
463
+	 *
464
+	 * @param mixed $items
465
+	 *
466
+	 * @return static
467
+	 */
468
+	public function intersect($items)
469
+	{
470
+		$this->initializeProxy();
471
+
472
+		return parent::intersect($items);
473
+	}
474
+
475
+	/**
476
+	 * Determine if the collection is empty or not.
477
+	 *
478
+	 * @return bool
479
+	 */
480
+	public function isEmpty()
481
+	{
482
+		$this->initializeProxy();
483
+
484
+		return parent::isEmpty();
485
+	}
486
+
487
+	/**
488
+	 * Get the keys of the collection items.
489
+	 *
490
+	 * @return static
491
+	 */
492
+	public function keys()
493
+	{
494
+		$this->initializeProxy();
495
+
496
+		return parent::keys();
497
+	}
498
+
499
+	/**
500
+	 * Get the last item from the collection.
501
+	 *
502
+	 * @param callable|null $callback
503
+	 * @param mixed         $default
504
+	 *
505
+	 * @return mixed
506
+	 */
507
+	public function last(callable $callback = null, $default = null)
508
+	{
509
+		// TODO : we could do partial loading there as well
510
+		$this->initializeProxy();
511
+
512
+		return parent::last($callback, $default);
513
+	}
514
+
515
+	/**
516
+	 * Get the values of a given key.
517
+	 *
518
+	 * @param string      $value
519
+	 * @param string|null $key
520
+	 *
521
+	 * @return static
522
+	 */
523
+	public function pluck($value, $key = null)
524
+	{
525
+		// TODO : automagic call to QB if not initialized
526
+		$this->initializeProxy();
527
+
528
+		return parent::pluck($value, $key);
529
+	}
530
+
531
+	/**
532
+	 * Run a map over each of the items.
533
+	 *
534
+	 * @param callable $callback
535
+	 *
536
+	 * @return static
537
+	 */
538
+	public function map(callable $callback)
539
+	{
540
+		$this->initializeProxy();
541
+
542
+		return parent::map($callback);
543
+	}
544
+
545
+	/**
546
+	 * Run an associative map over each of the items.
547
+	 *
548
+	 * The callback should return an associative array with a single key/value pair.
549
+	 *
550
+	 * @param callable $callback
551
+	 *
552
+	 * @return static
553
+	 */
554
+	public function mapWithKeys(callable $callback)
555
+	{
556
+		$this->initializeProxy();
557
+
558
+		return parent::mapWithKeys($callback);
559
+	}
560
+
561
+	/**
562
+	 * Map a collection and flatten the result by a single level.
563
+	 *
564
+	 * @param callable $callback
565
+	 *
566
+	 * @return static
567
+	 */
568
+	public function flatMap(callable $callback)
569
+	{
570
+		$this->initializeProxy();
571
+
572
+		return parent::flatMap($callback);
573
+	}
574
+
575
+	/**
576
+	 * Get the max value of a given key.
577
+	 *
578
+	 * @param callable|string|null $callback
579
+	 *
580
+	 * @return mixed
581
+	 */
582
+	public function max($callback = null)
583
+	{
584
+		$this->initializeProxy();
585
+
586
+		return parent::max($callback);
587
+	}
588
+
589
+	/**
590
+	 * Merge the collection with the given items.
591
+	 *
592
+	 * @param mixed $items
593
+	 *
594
+	 * @return static
595
+	 */
596
+	public function merge($items)
597
+	{
598
+		// TODO : Check if the EntityCollection
599
+		// returns a native Collection, as it
600
+		// is what we want here
601
+		$this->initializeProxy();
602
+
603
+		return parent::merge($items);
604
+	}
605
+
606
+	/**
607
+	 * Create a collection by using this collection for keys and another for its values.
608
+	 *
609
+	 * @param mixed $values
610
+	 *
611
+	 * @return static
612
+	 */
613
+	public function combine($values)
614
+	{
615
+		// TODO : Check if the EntityCollection
616
+		// returns a native Collection, as it
617
+		// is what we want here
618
+		$this->initializeProxy();
619
+
620
+		return parent::combine($values);
621
+	}
622
+
623
+	/**
624
+	 * Union the collection with the given items.
625
+	 *
626
+	 * @param mixed $items
627
+	 *
628
+	 * @return static
629
+	 */
630
+	public function union($items)
631
+	{
632
+		// TODO : Check if the EntityCollection
633
+		// returns a native Collection, as it
634
+		// is what we want here
635
+		$this->initializeProxy();
636
+
637
+		return parent::union($items);
638
+	}
639
+
640
+	/**
641
+	 * Get the min value of a given key.
642
+	 *
643
+	 * @param callable|string|null $callback
644
+	 *
645
+	 * @return mixed
646
+	 */
647
+	public function min($callback = null)
648
+	{
649
+		// TODO : we could rely on the QB
650
+		// for thos, if initialization has not
651
+		// take place yet
652
+		$this->initializeProxy();
653
+
654
+		return parent::min($callback);
655
+	}
656
+
657
+	/**
658
+	 * Create a new collection consisting of every n-th element.
659
+	 *
660
+	 * @param int $step
661
+	 * @param int $offset
662
+	 *
663
+	 * @return static
664
+	 */
665
+	public function nth($step, $offset = 0)
666
+	{
667
+		$this->initializeProxy();
668
+
669
+		return parent::nth($step, $offset);
670
+	}
671
+
672
+	/**
673
+	 * Get the items with the specified keys.
674
+	 *
675
+	 * @param mixed $keys
676
+	 *
677
+	 * @return static
678
+	 */
679
+	public function only($keys)
680
+	{
681
+		// TODO : we could rely on the QB if
682
+		// the collection hasn't been initialized yet
683
+		$this->initializeProxy();
684
+
685
+		return parent::only($keys);
686
+	}
687
+
688
+	/**
689
+	 * "Paginate" the collection by slicing it into a smaller collection.
690
+	 *
691
+	 * @param int $page
692
+	 * @param int $perPage
693
+	 *
694
+	 * @return static
695
+	 */
696
+	public function forPage($page, $perPage)
697
+	{
698
+		// TODO : check possibility of partial loading
699
+		// if not initialized
700
+		$this->initializeProxy();
701
+
702
+		return parent::forPage($page, $perPage);
703
+	}
704
+
705
+	/**
706
+	 * Partition the collection into two arrays using the given callback or key.
707
+	 *
708
+	 * @param callable|string $callback
709
+	 *
710
+	 * @return static
711
+	 */
712
+	public function partition($callback)
713
+	{
714
+		$this->initializeProxy();
715
+
716
+		return parent::partition($callback);
717
+	}
718
+
719
+	/**
720
+	 * Pass the collection to the given callback and return the result.
721
+	 *
722
+	 * @param callable $callback
723
+	 *
724
+	 * @return mixed
725
+	 */
726
+	public function pipe(callable $callback)
727
+	{
728
+		$this->initializeProxy();
729
+
730
+		return parent::pipe($callback);
731
+	}
732
+
733
+	/**
734
+	 * Get and remove the last item from the collection.
735
+	 *
736
+	 * @return mixed
737
+	 */
738
+	public function pop()
739
+	{
740
+		$this->initializeProxy();
741
+
742
+		return parent::pop();
743
+	}
744
+
745
+	/**
746
+	 * Push an item onto the beginning of the collection.
747
+	 *
748
+	 * @param mixed $value
749
+	 * @param mixed $key
750
+	 *
751
+	 * @return $this
752
+	 */
753
+	public function prepend($value, $key = null)
754
+	{
755
+		// TODO : partial adding of values.
756
+		// we could have a $prepended , and $pushed arrays
757
+		// which we would combine at full initialization
758
+
759
+		$this->initializeProxy();
760
+
761
+		return parent::prepend($value, $key);
762
+	}
763
+
764
+	/**
765
+	 * Push an item onto the end of the collection.
766
+	 *
767
+	 * @param mixed $value
768
+	 *
769
+	 * @return $this
770
+	 */
771
+	public function push($value)
772
+	{
773
+		// TODO : partial adding of values.
774
+		// we could have a $prepended , and $pushed arrays
775
+		// which we would combine at full initialization
776
+
777
+		$this->initializeProxy();
778
+
779
+		return parent::push($value);
780
+	}
781
+
782
+	/**
783
+	 * Get and remove an item from the collection.
784
+	 *
785
+	 * @param mixed $key
786
+	 * @param mixed $default
787
+	 *
788
+	 * @return mixed
789
+	 */
790
+	public function pull($key, $default = null)
791
+	{
792
+		// TODO : QB query if the collection
793
+		// hasn't been initialized yet
794
+
795
+		$this->initializeProxy();
796
+
797
+		return parent::pull($key, $default);
798
+	}
799
+
800
+	/**
801
+	 * Put an item in the collection by key.
802
+	 *
803
+	 * @param mixed $key
804
+	 * @param mixed $value
805
+	 *
806
+	 * @return $this
807
+	 */
808
+	public function put($key, $value)
809
+	{
810
+		// TODO : Partial loading ?
811
+
812
+		$this->initializeProxy();
813
+
814
+		return parent::put($key, $value);
815
+	}
816
+
817
+	/**
818
+	 * Get one or more items randomly from the collection.
819
+	 *
820
+	 * @param int $amount
821
+	 *
822
+	 * @throws \InvalidArgumentException
823
+	 *
824
+	 * @return mixed
825
+	 */
826
+	public function random($amount = 1)
827
+	{
828
+		// TODO : we could optimize this by only
829
+		// fetching the keys from the database
830
+		// and performing partial loading
831
+
832
+		$this->initializeProxy();
833
+
834
+		return parent::random($amount);
835
+	}
836
+
837
+	/**
838
+	 * Reduce the collection to a single value.
839
+	 *
840
+	 * @param callable $callback
841
+	 * @param mixed    $initial
842
+	 *
843
+	 * @return mixed
844
+	 */
845
+	public function reduce(callable $callback, $initial = null)
846
+	{
847
+		$this->initializeProxy();
848
+
849
+		return parent::reduce($callback, $initial);
850
+	}
851
+
852
+	/**
853
+	 * Create a collection of all elements that do not pass a given truth test.
854
+	 *
855
+	 * @param callable|mixed $callback
856
+	 *
857
+	 * @return static
858
+	 */
859
+	public function reject($callback)
860
+	{
861
+		$this->initializeProxy();
862
+
863
+		return parent::reject($callback);
864
+	}
865
+
866
+	/**
867
+	 * Reverse items order.
868
+	 *
869
+	 * @return static
870
+	 */
871
+	public function reverse()
872
+	{
873
+		$this->initializeProxy();
874
+
875
+		return parent::reverse();
876
+	}
877
+
878
+	/**
879
+	 * Search the collection for a given value and return the corresponding key if successful.
880
+	 *
881
+	 * @param mixed $value
882
+	 * @param bool  $strict
883
+	 *
884
+	 * @return mixed
885
+	 */
886
+	public function search($value, $strict = false)
887
+	{
888
+		$this->initializeProxy();
889
+
890
+		return parent::search($value, $strict);
891
+	}
892
+
893
+	/**
894
+	 * Get and remove the first item from the collection.
895
+	 *
896
+	 * @return mixed
897
+	 */
898
+	public function shift()
899
+	{
900
+		// Todo : Partial Removing
901
+		// we could have a pending removal array
902
+		$this->initializeProxy();
903
+
904
+		return parent::shift();
905
+	}
906
+
907
+	/**
908
+	 * Shuffle the items in the collection.
909
+	 *
910
+	 * @param int $seed
911
+	 *
912
+	 * @return static
913
+	 */
914
+	public function shuffle($seed = null)
915
+	{
916
+		$this->initializeProxy();
917
+
918
+		return parent::shuffle($seed);
919
+	}
920
+
921
+	/**
922
+	 * Slice the underlying collection array.
923
+	 *
924
+	 * @param int $offset
925
+	 * @param int $length
926
+	 *
927
+	 * @return static
928
+	 */
929
+	public function slice($offset, $length = null)
930
+	{
931
+		$this->initializeProxy();
932
+
933
+		return parent::slice($offset, $length);
934
+	}
935
+
936
+	/**
937
+	 * Split a collection into a certain number of groups.
938
+	 *
939
+	 * @param int $numberOfGroups
940
+	 *
941
+	 * @return static
942
+	 */
943
+	public function split($numberOfGroups)
944
+	{
945
+		$this->initializeProxy();
946
+
947
+		return parent::split($numberOfGroups);
948
+	}
949
+
950
+	/**
951
+	 * Chunk the underlying collection array.
952
+	 *
953
+	 * @param int $size
954
+	 *
955
+	 * @return static
956
+	 */
957
+	public function chunk($size)
958
+	{
959
+		// TODO : partial loading ?
960
+		$this->initializeProxy();
961
+
962
+		return parent::chunk($size);
963
+	}
964
+
965
+	/**
966
+	 * Sort through each item with a callback.
967
+	 *
968
+	 * @param callable|null $callback
969
+	 *
970
+	 * @return static
971
+	 */
972
+	public function sort(callable $callback = null)
973
+	{
974
+		$this->initializeProxy();
975
+
976
+		return parent::sort($callback);
977
+	}
978
+
979
+	/**
980
+	 * Sort the collection using the given callback.
981
+	 *
982
+	 * @param callable|string $callback
983
+	 * @param int             $options
984
+	 * @param bool            $descending
985
+	 *
986
+	 * @return static
987
+	 */
988
+	public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
989
+	{
990
+		$this->initializeProxy();
991
+
992
+		return parent::sort($callback, $options, $descending);
993
+	}
994
+
995
+	/**
996
+	 * Splice a portion of the underlying collection array.
997
+	 *
998
+	 * @param int      $offset
999
+	 * @param int|null $length
1000
+	 * @param mixed    $replacement
1001
+	 *
1002
+	 * @return static
1003
+	 */
1004
+	public function splice($offset, $length = null, $replacement = [])
1005
+	{
1006
+		$this->initializeProxy();
1007
+
1008
+		return parent::splice($offset, $length, $replacement);
1009
+	}
1010
+
1011
+	/**
1012
+	 * Get the sum of the given values.
1013
+	 *
1014
+	 * @param callable|string|null $callback
1015
+	 *
1016
+	 * @return mixed
1017
+	 */
1018
+	public function sum($callback = null)
1019
+	{
1020
+		$this->initializeProxy();
1021
+
1022
+		return parent::sum($callback);
1023
+	}
1024
+
1025
+	/**
1026
+	 * Take the first or last {$limit} items.
1027
+	 *
1028
+	 * @param int $limit
1029
+	 *
1030
+	 * @return static
1031
+	 */
1032
+	public function take($limit)
1033
+	{
1034
+		// TODO: partial loading
1035
+		$this->initializeProxy();
1036
+
1037
+		return parent::take($limit);
1038
+	}
1039
+
1040
+	/**
1041
+	 * Pass the collection to the given callback and then return it.
1042
+	 *
1043
+	 * @param callable $callback
1044
+	 *
1045
+	 * @return $this
1046
+	 */
1047
+	public function tap(callable $callback)
1048
+	{
1049
+		$this->initializeProxy();
1050
+
1051
+		return parent::tap($this);
1052
+	}
1053
+
1054
+	/**
1055
+	 * Transform each item in the collection using a callback.
1056
+	 *
1057
+	 * @param callable $callback
1058
+	 *
1059
+	 * @return $this
1060
+	 */
1061
+	public function transform(callable $callback)
1062
+	{
1063
+		$this->initializeProxy();
1064
+
1065
+		return parent::transform($callback);
1066
+	}
1067
+
1068
+	/**
1069
+	 * Return only unique items from the collection array.
1070
+	 *
1071
+	 * @param string|callable|null $key
1072
+	 * @param bool                 $strict
1073
+	 *
1074
+	 * @return static
1075
+	 */
1076
+	public function unique($key = null, $strict = false)
1077
+	{
1078
+		$this->initializeProxy();
1079
+
1080
+		return parent::unique($key, $strict);
1081
+	}
1082
+
1083
+	/**
1084
+	 * Reset the keys on the underlying array.
1085
+	 *
1086
+	 * @return static
1087
+	 */
1088
+	public function values()
1089
+	{
1090
+		$this->initializeProxy();
1091
+
1092
+		return parent::values();
1093
+	}
1094
+
1095
+	/**
1096
+	 * Apply the callback if the value is truthy.
1097
+	 *
1098
+	 * @param  bool  $value
1099
+	 * @param  callable  $callback
1100
+	 * @return mixed
1101
+	 */
1102
+	public function when($value, callable $callback)
1103
+	{
1104
+		$this->initializeProxy();
1105
+
1106
+		return parent::when($value, $callback);
1107
+	}
1108
+
1109
+	/**
1110
+	 * Zip the collection together with one or more arrays.
1111
+	 *
1112
+	 * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1113
+	 *      => [[1, 4], [2, 5], [3, 6]]
1114
+	 *
1115
+	 * @param mixed ...$items
1116
+	 *
1117
+	 * @return static
1118
+	 */
1119
+	public function zip($items)
1120
+	{
1121
+		$this->initializeProxy();
1122
+
1123
+		return parent::zip($items);
1124
+	}
1125
+
1126
+	/**
1127
+	 * Get the collection of items as a plain array.
1128
+	 *
1129
+	 * @return array
1130
+	 */
1131
+	public function toArray()
1132
+	{
1133
+		// If this is called on all subsequent proxy,
1134
+		// this would eventually trigger all lazy loading,
1135
+		// which is NOT what we would expect...
1136
+		// TODO : must think of this.
1137
+		$this->initializeProxy();
1138
+
1139
+		return parent::toArray();
1140
+	}
1141
+
1142
+	/**
1143
+	 * Convert the object into something JSON serializable.
1144
+	 *
1145
+	 * @return array
1146
+	 */
1147
+	public function jsonSerialize()
1148
+	{
1149
+		// If this is called on all subsequent proxy,
1150
+		// this would eventually trigger all lazy loading,
1151
+		// which is NOT what we would expect...
1152
+		// TODO : must think of this.
1153
+		$this->initializeProxy();
1154
+
1155
+		return parent::jsonSerialize();
1156
+	}
1157
+
1158
+	/**
1159
+	 * Get the collection of items as JSON.
1160
+	 *
1161
+	 * @param int $options
1162
+	 *
1163
+	 * @return string
1164
+	 */
1165
+	public function toJson($options = 0)
1166
+	{
1167
+		// If this is called on all subsequent proxy,
1168
+		// this would eventually trigger all lazy loading,
1169
+		// which is NOT what we would expect...
1170
+		// TODO : must think of this.
1171
+		$this->initializeProxy();
1172
+
1173
+		return parent::toJson($options);
1174
+	}
1175
+
1176
+	/**
1177
+	 * Get an iterator for the items.
1178
+	 *
1179
+	 * @return \ArrayIterator
1180
+	 */
1181
+	public function getIterator()
1182
+	{
1183
+		$this->initializeProxy();
1184
+
1185
+		return parent::getIterator();
1186
+	}
1187
+
1188
+	/**
1189
+	 * Get a CachingIterator instance.
1190
+	 *
1191
+	 * @param int $flags
1192
+	 *
1193
+	 * @return \CachingIterator
1194
+	 */
1195
+	public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1196
+	{
1197
+		$this->initializeProxy();
1198
+
1199
+		return parent::getCachingIterator($flags);
1200
+	}
1201
+
1202
+	/**
1203
+	 * Count the number of items in the collection.
1204
+	 *
1205
+	 * @return int
1206
+	 */
1207
+	public function count()
1208
+	{
1209
+		// TODO rely on QB if not initialized
1210
+		$this->initializeProxy();
1211
+
1212
+		return parent::count();
1213
+	}
1214
+
1215
+	/**
1216
+	 * Get a base Support collection instance from this collection.
1217
+	 *
1218
+	 * @return \Illuminate\Support\Collection
1219
+	 */
1220
+	public function toBase()
1221
+	{
1222
+		$this->initializeProxy();
1223
+
1224
+		return parent::toBase();
1225
+	}
1226
+
1227
+	/**
1228
+	 * Determine if an item exists at an offset.
1229
+	 *
1230
+	 * @param mixed $key
1231
+	 *
1232
+	 * @return bool
1233
+	 */
1234
+	public function offsetExists($key)
1235
+	{
1236
+		// TODO rely on QB if no collection
1237
+		// initialized
1238
+		$this->initializeProxy();
1239
+
1240
+		return parent::offsetExists($key);
1241
+	}
1242
+
1243
+	/**
1244
+	 * Get an item at a given offset.
1245
+	 *
1246
+	 * @param mixed $key
1247
+	 *
1248
+	 * @return mixed
1249
+	 */
1250
+	public function offsetGet($key)
1251
+	{
1252
+		// TODO rely on partial init if no collection
1253
+		// initialized
1254
+		$this->initializeProxy();
1255
+
1256
+		return parent::offsetGet($key);
1257
+	}
1258
+
1259
+	/**
1260
+	 * Set the item at a given offset.
1261
+	 *
1262
+	 * @param mixed $key
1263
+	 * @param mixed $value
1264
+	 *
1265
+	 * @return void
1266
+	 */
1267
+	public function offsetSet($key, $value)
1268
+	{
1269
+		// TODO : think of the use of it into a ProxyCollection
1270
+		// context
1271
+		$this->initializeProxy();
1272
+
1273
+		return parent::offsetSet($key, $value);
1274
+	}
1275
+
1276
+	/**
1277
+	 * Unset the item at a given offset.
1278
+	 *
1279
+	 * @param string $key
1280
+	 *
1281
+	 * @return void
1282
+	 */
1283
+	public function offsetUnset($key)
1284
+	{
1285
+		// TODO : think of the use of it into a ProxyCollection
1286
+		// context
1287
+		$this->initializeProxy();
1288
+
1289
+		return parent::offsetUnset($key);
1290
+	}
1291
+
1292
+	/**
1293
+	 * Dynamically access collection proxies.
1294
+	 *
1295
+	 * @param string $key
1296
+	 *
1297
+	 * @throws \Exception
1298
+	 *
1299
+	 * @return mixed
1300
+	 */
1301
+	public function __get($key)
1302
+	{
1303
+		parent::__get($key);
1304
+	}
1305
+
1306
+	/**
1307
+	 * Dynamically handle calls to the class.
1308
+	 *
1309
+	 * @param string $method
1310
+	 * @param array  $parameters
1311
+	 *
1312
+	 * @throws \BadMethodCallException
1313
+	 *
1314
+	 * @return mixed
1315
+	 */
1316
+	public function __call($method, $parameters)
1317
+	{
1318
+		$this->initializeProxy();
1319
+
1320
+		return parent::__call($method, $parameters);
1321
+	}
1322 1322
 }
Please login to merge, or discard this patch.
src/System/Proxies/ProxyFactory.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -14,47 +14,47 @@
 block discarded – undo
14 14
  */
15 15
 class ProxyFactory
16 16
 {
17
-    public function make($entity, $relation, $class)
18
-    {
19
-        $entityMap = Manager::getMapper($entity)->getEntityMap();
20
-
21
-        $singleRelations = $entityMap->getSingleRelationships();
22
-        $manyRelations = $entityMap->getManyRelationships();
23
-
24
-        if (in_array($relation, $singleRelations)) {
25
-            return $this->makeEntityProxy($entity, $relation, $class);
26
-        }
27
-
28
-        if (in_array($relation, $manyRelations)) {
29
-            return new CollectionProxy($entity, $relation);
30
-        }
31
-
32
-        throw new MappingException("Could not identify relation '$relation'");
33
-    }
34
-
35
-    /**
36
-     * Create an instance of a proxy object, extending the actual
37
-     * related class.
38
-     *
39
-     * @param mixed  $entity   parent object
40
-     * @param string $relation the name of the relationship method
41
-     * @param string $class    the class name of the related object
42
-     *
43
-     * @return mixed
44
-     */
45
-    protected function makeEntityProxy($entity, $relation, $class)
46
-    {
47
-        $factory = new LazyLoadingValueHolderFactory();
48
-
49
-        $initializer = function (&$wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, &$initializer) use ($entity, $relation) {
50
-            $entityMap = Manager::getMapper($entity)->getEntityMap();
51
-
52
-            $wrappedObject = $entityMap->$relation($entity)->getResults($relation);
53
-
54
-            $initializer = null; // disable initialization
55
-            return true; // confirm that initialization occurred correctly
56
-        };
57
-
58
-        return $factory->createProxy($class, $initializer);
59
-    }
17
+	public function make($entity, $relation, $class)
18
+	{
19
+		$entityMap = Manager::getMapper($entity)->getEntityMap();
20
+
21
+		$singleRelations = $entityMap->getSingleRelationships();
22
+		$manyRelations = $entityMap->getManyRelationships();
23
+
24
+		if (in_array($relation, $singleRelations)) {
25
+			return $this->makeEntityProxy($entity, $relation, $class);
26
+		}
27
+
28
+		if (in_array($relation, $manyRelations)) {
29
+			return new CollectionProxy($entity, $relation);
30
+		}
31
+
32
+		throw new MappingException("Could not identify relation '$relation'");
33
+	}
34
+
35
+	/**
36
+	 * Create an instance of a proxy object, extending the actual
37
+	 * related class.
38
+	 *
39
+	 * @param mixed  $entity   parent object
40
+	 * @param string $relation the name of the relationship method
41
+	 * @param string $class    the class name of the related object
42
+	 *
43
+	 * @return mixed
44
+	 */
45
+	protected function makeEntityProxy($entity, $relation, $class)
46
+	{
47
+		$factory = new LazyLoadingValueHolderFactory();
48
+
49
+		$initializer = function (&$wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, &$initializer) use ($entity, $relation) {
50
+			$entityMap = Manager::getMapper($entity)->getEntityMap();
51
+
52
+			$wrappedObject = $entityMap->$relation($entity)->getResults($relation);
53
+
54
+			$initializer = null; // disable initialization
55
+			return true; // confirm that initialization occurred correctly
56
+		};
57
+
58
+		return $factory->createProxy($class, $initializer);
59
+	}
60 60
 }
Please login to merge, or discard this patch.