Completed
Branch master (a17b64)
by Rémi
15:50
created
src/System/Wrappers/PlainObjectWrapper.php 3 patches
Indentation   +233 added lines, -233 removed lines patch added patch discarded remove patch
@@ -6,239 +6,239 @@
 block discarded – undo
6 6
 
7 7
 class PlainObjectWrapper extends Wrapper
8 8
 {
9
-    /**
10
-     * The list of attributes for the managed entity
11
-     *
12
-     * @var array
13
-     */
14
-    protected $attributeList;
15
-
16
-    /**
17
-     * The reflection class for the managed entity
18
-     *
19
-     * @var ReflectionClass
20
-     */
21
-    protected $reflection;
22
-
23
-    /**
24
-     * Attributes which have no existence on the actual entity
25
-     * but which exists in DB (eg : foreign key)
26
-     * 
27
-     * @var array
28
-     */
29
-    protected $virtualAttributes = [];
30
-
31
-    /**
32
-     * PlainObjectWrapper constructor.
33
-     * 
34
-     * @param $popoEntity
35
-     * @param $entityMap
36
-     */
37
-    public function __construct($popoEntity, $entityMap)
38
-    {
39
-        $this->reflection = new ReflectionClass($popoEntity);
40
-
41
-        parent::__construct($popoEntity, $entityMap);
42
-
43
-        $this->attributeList = $this->getAttributeList();
44
-    }
45
-
46
-    /**
47
-     * Get Compiled Attributes (key, attributes, embed, relations)
48
-     *
49
-     * @return array
50
-     */
51
-    protected function getAttributeList()
52
-    {
53
-        return  $this->entityMap->getCompiledAttributes();
54
-    }
55
-
56
-    /**
57
-     * Extract Attributes from a Plain Php Object
58
-     *
59
-     * @return array $attributes
60
-     */
61
-    protected function extract()
62
-    {
63
-        $properties = $this->getMappedProperties();
64
-
65
-        $attributes = [];
66
-
67
-        foreach ($properties as $property) {
68
-            $name = $property->getName();
69
-
70
-            if ($property->isPublic()) {
71
-                $attributes[$name] = $this->entity->$name;
72
-            } else {
73
-                $property->setAccessible(true);
9
+	/**
10
+	 * The list of attributes for the managed entity
11
+	 *
12
+	 * @var array
13
+	 */
14
+	protected $attributeList;
15
+
16
+	/**
17
+	 * The reflection class for the managed entity
18
+	 *
19
+	 * @var ReflectionClass
20
+	 */
21
+	protected $reflection;
22
+
23
+	/**
24
+	 * Attributes which have no existence on the actual entity
25
+	 * but which exists in DB (eg : foreign key)
26
+	 * 
27
+	 * @var array
28
+	 */
29
+	protected $virtualAttributes = [];
30
+
31
+	/**
32
+	 * PlainObjectWrapper constructor.
33
+	 * 
34
+	 * @param $popoEntity
35
+	 * @param $entityMap
36
+	 */
37
+	public function __construct($popoEntity, $entityMap)
38
+	{
39
+		$this->reflection = new ReflectionClass($popoEntity);
40
+
41
+		parent::__construct($popoEntity, $entityMap);
42
+
43
+		$this->attributeList = $this->getAttributeList();
44
+	}
45
+
46
+	/**
47
+	 * Get Compiled Attributes (key, attributes, embed, relations)
48
+	 *
49
+	 * @return array
50
+	 */
51
+	protected function getAttributeList()
52
+	{
53
+		return  $this->entityMap->getCompiledAttributes();
54
+	}
55
+
56
+	/**
57
+	 * Extract Attributes from a Plain Php Object
58
+	 *
59
+	 * @return array $attributes
60
+	 */
61
+	protected function extract()
62
+	{
63
+		$properties = $this->getMappedProperties();
64
+
65
+		$attributes = [];
66
+
67
+		foreach ($properties as $property) {
68
+			$name = $property->getName();
69
+
70
+			if ($property->isPublic()) {
71
+				$attributes[$name] = $this->entity->$name;
72
+			} else {
73
+				$property->setAccessible(true);
74 74
     
75
-                $attributes[$name] = $property->getValue($this->entity);
76
-            }
77
-        }
78
-
79
-        return $attributes;
80
-    }
81
-
82
-    /**
83
-     * @return \ReflectionProperty[]
84
-     */
85
-    protected function getMappedProperties()
86
-    {
87
-        $objectProperties = $this->reflection->getProperties();
88
-
89
-        $attributeList = $this->getAttributeList();
90
-
91
-        // We need to filter out properties that could belong to the object
92
-        // and which are not intended to be handled by the ORM
93
-        return array_filter($objectProperties, function (\ReflectionProperty $item) use ($attributeList) {
94
-            if (in_array($item->getName(), $attributeList)) {
95
-                return true;
96
-            }
97
-        });
98
-    }
99
-
100
-    /**
101
-     * Get the property's value from reflection
102
-     * 
103
-     * @param  string $name
104
-     * @return \ReflectionProperty | null
105
-     */
106
-    protected function getMappedProperty($name)
107
-    {
108
-        return $this->reflection->getProperty($name);
109
-    }
110
-
111
-    /**
112
-     * Hydrate Plain PHP Object with wrapped attributes
113
-     *
114
-     * @param  $attributes
115
-     * @return void
116
-     */
117
-    protected function hydrate($attributes)
118
-    {
119
-        $properties = $this->getMappedProperties();
120
-
121
-        foreach ($properties as $property) {
122
-            $name = $property->getName();
123
-
124
-            if ($property->isPublic()) {
125
-                $this->entity->$name = $attributes[$name];
126
-            } else {
127
-                $property->setAccessible(true);
128
-
129
-                $property->setValue($this->entity, $attributes[$name]);
130
-            }
131
-        }
132
-    }
133
-
134
-    /**
135
-     * Method used by the mapper to set the object
136
-     * attribute raw values (hydration)
137
-     *
138
-     * @param array $attributes
139
-     *
140
-     * @return void
141
-     */
142
-    public function setEntityAttributes(array $attributes)
143
-    {
144
-        $this->hydrate($attributes);
145
-    }
146
-
147
-    /**
148
-     * Method used by the mapper to get the
149
-     * raw object's values.
150
-     *
151
-     * @return array
152
-     */
153
-    public function getEntityAttributes()
154
-    {
155
-        $properties = $this->extract();
156
-
157
-        return array_merge($properties, $this->virtualAttributes);
158
-    }
159
-
160
-    /**
161
-     * Method used by the mapper to set raw
162
-     * key-value pair
163
-     *
164
-     * @param string $key
165
-     * @param string $value
166
-     *
167
-     * @return void
168
-     */
169
-    public function setEntityAttribute($key, $value)
170
-    {
171
-        if(! $this->reflection->hasProperty($key)) {
172
-            $this->virtualAttributes[$key] = $value;
173
-            return;
174
-        }
175
-
176
-        $property = $this->getMappedProperty($key);
177
-
178
-        if ($property->isPublic()) {
179
-            $this->entity->$key = $value;
180
-        } else {
181
-            $property->setAccessible(true);
75
+				$attributes[$name] = $property->getValue($this->entity);
76
+			}
77
+		}
78
+
79
+		return $attributes;
80
+	}
81
+
82
+	/**
83
+	 * @return \ReflectionProperty[]
84
+	 */
85
+	protected function getMappedProperties()
86
+	{
87
+		$objectProperties = $this->reflection->getProperties();
88
+
89
+		$attributeList = $this->getAttributeList();
90
+
91
+		// We need to filter out properties that could belong to the object
92
+		// and which are not intended to be handled by the ORM
93
+		return array_filter($objectProperties, function (\ReflectionProperty $item) use ($attributeList) {
94
+			if (in_array($item->getName(), $attributeList)) {
95
+				return true;
96
+			}
97
+		});
98
+	}
99
+
100
+	/**
101
+	 * Get the property's value from reflection
102
+	 * 
103
+	 * @param  string $name
104
+	 * @return \ReflectionProperty | null
105
+	 */
106
+	protected function getMappedProperty($name)
107
+	{
108
+		return $this->reflection->getProperty($name);
109
+	}
110
+
111
+	/**
112
+	 * Hydrate Plain PHP Object with wrapped attributes
113
+	 *
114
+	 * @param  $attributes
115
+	 * @return void
116
+	 */
117
+	protected function hydrate($attributes)
118
+	{
119
+		$properties = $this->getMappedProperties();
120
+
121
+		foreach ($properties as $property) {
122
+			$name = $property->getName();
123
+
124
+			if ($property->isPublic()) {
125
+				$this->entity->$name = $attributes[$name];
126
+			} else {
127
+				$property->setAccessible(true);
128
+
129
+				$property->setValue($this->entity, $attributes[$name]);
130
+			}
131
+		}
132
+	}
133
+
134
+	/**
135
+	 * Method used by the mapper to set the object
136
+	 * attribute raw values (hydration)
137
+	 *
138
+	 * @param array $attributes
139
+	 *
140
+	 * @return void
141
+	 */
142
+	public function setEntityAttributes(array $attributes)
143
+	{
144
+		$this->hydrate($attributes);
145
+	}
146
+
147
+	/**
148
+	 * Method used by the mapper to get the
149
+	 * raw object's values.
150
+	 *
151
+	 * @return array
152
+	 */
153
+	public function getEntityAttributes()
154
+	{
155
+		$properties = $this->extract();
156
+
157
+		return array_merge($properties, $this->virtualAttributes);
158
+	}
159
+
160
+	/**
161
+	 * Method used by the mapper to set raw
162
+	 * key-value pair
163
+	 *
164
+	 * @param string $key
165
+	 * @param string $value
166
+	 *
167
+	 * @return void
168
+	 */
169
+	public function setEntityAttribute($key, $value)
170
+	{
171
+		if(! $this->reflection->hasProperty($key)) {
172
+			$this->virtualAttributes[$key] = $value;
173
+			return;
174
+		}
175
+
176
+		$property = $this->getMappedProperty($key);
177
+
178
+		if ($property->isPublic()) {
179
+			$this->entity->$key = $value;
180
+		} else {
181
+			$property->setAccessible(true);
182 182
     
183
-            $property->setValue($this->entity, $value);
184
-        }
185
-
186
-        $this->attributes[$key] = $value;
187
-    }
188
-
189
-    /**
190
-     * Method used by the mapper to get single
191
-     * key-value pair
192
-     *
193
-     * @param  string $key
194
-     * @return mixed|null
195
-     */
196
-    public function getEntityAttribute($key)
197
-    {
198
-        if(! $this->reflection->hasProperty($key)) {
199
-            return $this->getVirtualAttribute($key);
200
-        }
201
-
202
-        $property = $this->getMappedProperty($key);
203
-
204
-        if ($property->isPublic()) {
205
-            $value = $this->entity->$key;
206
-        } else {
207
-            $property->setAccessible(true);
208
-            $value = $property->getValue($this->entity);
209
-        }
210
-
211
-        return $value;
212
-    }
213
-
214
-    /**
215
-     * Return a virtual attributes
216
-     * 
217
-     * @param  string $key
218
-     * @return mixed
219
-     */
220
-    protected function getVirtualAttribute($key)
221
-    {
222
-        if(array_key_exists($key, $this->virtualAttributes)) {
223
-            return $this->virtualAttributes[$key];
224
-        }
225
-        else {
226
-            return null;
227
-        }
228
-    }
229
-
230
-    /**
231
-     * Test if a given attribute exists
232
-     *
233
-     * @param  string  $key
234
-     * @return boolean
235
-     */
236
-    public function hasAttribute($key)
237
-    {
238
-        if (in_array($key, $this->attributeList)) {
239
-            return true;
240
-        } else {
241
-            return false;
242
-        }
243
-    }
183
+			$property->setValue($this->entity, $value);
184
+		}
185
+
186
+		$this->attributes[$key] = $value;
187
+	}
188
+
189
+	/**
190
+	 * Method used by the mapper to get single
191
+	 * key-value pair
192
+	 *
193
+	 * @param  string $key
194
+	 * @return mixed|null
195
+	 */
196
+	public function getEntityAttribute($key)
197
+	{
198
+		if(! $this->reflection->hasProperty($key)) {
199
+			return $this->getVirtualAttribute($key);
200
+		}
201
+
202
+		$property = $this->getMappedProperty($key);
203
+
204
+		if ($property->isPublic()) {
205
+			$value = $this->entity->$key;
206
+		} else {
207
+			$property->setAccessible(true);
208
+			$value = $property->getValue($this->entity);
209
+		}
210
+
211
+		return $value;
212
+	}
213
+
214
+	/**
215
+	 * Return a virtual attributes
216
+	 * 
217
+	 * @param  string $key
218
+	 * @return mixed
219
+	 */
220
+	protected function getVirtualAttribute($key)
221
+	{
222
+		if(array_key_exists($key, $this->virtualAttributes)) {
223
+			return $this->virtualAttributes[$key];
224
+		}
225
+		else {
226
+			return null;
227
+		}
228
+	}
229
+
230
+	/**
231
+	 * Test if a given attribute exists
232
+	 *
233
+	 * @param  string  $key
234
+	 * @return boolean
235
+	 */
236
+	public function hasAttribute($key)
237
+	{
238
+		if (in_array($key, $this->attributeList)) {
239
+			return true;
240
+		} else {
241
+			return false;
242
+		}
243
+	}
244 244
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 
91 91
         // We need to filter out properties that could belong to the object
92 92
         // and which are not intended to be handled by the ORM
93
-        return array_filter($objectProperties, function (\ReflectionProperty $item) use ($attributeList) {
93
+        return array_filter($objectProperties, function(\ReflectionProperty $item) use ($attributeList) {
94 94
             if (in_array($item->getName(), $attributeList)) {
95 95
                 return true;
96 96
             }
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
      */
169 169
     public function setEntityAttribute($key, $value)
170 170
     {
171
-        if(! $this->reflection->hasProperty($key)) {
171
+        if (!$this->reflection->hasProperty($key)) {
172 172
             $this->virtualAttributes[$key] = $value;
173 173
             return;
174 174
         }
@@ -195,7 +195,7 @@  discard block
 block discarded – undo
195 195
      */
196 196
     public function getEntityAttribute($key)
197 197
     {
198
-        if(! $this->reflection->hasProperty($key)) {
198
+        if (!$this->reflection->hasProperty($key)) {
199 199
             return $this->getVirtualAttribute($key);
200 200
         }
201 201
 
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
      */
220 220
     protected function getVirtualAttribute($key)
221 221
     {
222
-        if(array_key_exists($key, $this->virtualAttributes)) {
222
+        if (array_key_exists($key, $this->virtualAttributes)) {
223 223
             return $this->virtualAttributes[$key];
224 224
         }
225 225
         else {
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -221,8 +221,7 @@
 block discarded – undo
221 221
     {
222 222
         if(array_key_exists($key, $this->virtualAttributes)) {
223 223
             return $this->virtualAttributes[$key];
224
-        }
225
-        else {
224
+        } else {
226 225
             return null;
227 226
         }
228 227
     }
Please login to merge, or discard this patch.
src/System/ResultBuilder.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -122,7 +122,7 @@
 block discarded – undo
122 122
 
123 123
         $columnMap = $this->entityMap->getDiscriminatorColumnMap();
124 124
 
125
-        $class = isset($columnMap[$type]) ? $columnMap[$type]: $type;
125
+        $class = isset($columnMap[$type]) ? $columnMap[$type] : $type;
126 126
 
127 127
         if (!isset($this->builders[$type])) {
128 128
             $this->builders[$type] = new EntityBuilder($this->manager->mapper($class), array_keys($this->eagerLoads));
Please login to merge, or discard this patch.
Indentation   +124 added lines, -124 removed lines patch added patch discarded remove patch
@@ -6,128 +6,128 @@
 block discarded – undo
6 6
 
7 7
 class ResultBuilder
8 8
 {
9
-    /**
10
-     * An instance of the entity manager class.
11
-     * @var \Analogue\ORM\System\Manager
12
-     */
13
-    protected $manager;
14
-
15
-    /**
16
-     * The default mapper used to build entities with.
17
-     * @var \Analogue\ORM\System\Mapper
18
-     */
19
-    protected $defaultMapper;
20
-
21
-    /**
22
-     * Relations that will be eager loaded on this query
23
-     *
24
-     * @var array
25
-     */
26
-    protected $eagerLoads;
27
-
28
-    /**
29
-     * The Entity Map for the entity to build.
30
-     *
31
-     * @var \Analogue\ORM\EntityMap
32
-     */
33
-    protected $entityMap;
34
-
35
-    /**
36
-     * An array of builders used by this class to build necessary
37
-     * entities for each result type.
38
-     *
39
-     * @var array
40
-     */
41
-    protected $builders = [];
42
-
43
-    /**
44
-     * @param Manager $manager
45
-     * @param Mapper  $defaultMapper
46
-     * @param array   $eagerLoads
47
-     */
48
-    public function __construct(Manager $manager, Mapper $defaultMapper, array $eagerLoads)
49
-    {
50
-        $this->manager = $manager;
51
-
52
-        $this->defaultMapper = $defaultMapper;
53
-
54
-        $this->eagerLoads = $eagerLoads;
55
-
56
-        $this->entityMap = $defaultMapper->getEntityMap();
57
-    }
58
-
59
-    /**
60
-     * Convert a result set into an array of entities
61
-     *
62
-     * @param  array $results
63
-     * @return \Illuminate\Support\Collection
64
-     */
65
-    public function build($results)
66
-    {
67
-        switch ($this->entityMap->getInheritanceType()) {
68
-            case 'single_table':
69
-                return $this->buildUsingSingleTableInheritance($results);
70
-                break;
71
-
72
-            default:
73
-                return $this->buildWithDefaultMapper($results);
74
-                break;
75
-        }
76
-    }
77
-
78
-    /**
79
-     * Build an entity from results, using the default mapper on this builder.
80
-     * This is the default build plan when no table inheritance is being used.
81
-     *
82
-     * @param  array $results
83
-     * @return Collection
84
-     */
85
-    protected function buildWithDefaultMapper($results)
86
-    {
87
-        $builder = new EntityBuilder($this->defaultMapper, array_keys($this->eagerLoads));
88
-
89
-        return collect($results)->map(function($item, $key) use ($builder) {
90
-            return $builder->build((array) $item);
91
-        })->all();
92
-    }
93
-
94
-    /**
95
-     * Build an entity from results, using single table inheritance.
96
-     *
97
-     * @param  array $results
98
-     * @return Collection
99
-     */
100
-    protected function buildUsingSingleTableInheritance($results)
101
-    {
102
-        return collect($results)->map(function($item, $key) {
103
-            $builder = $this->builderForResult((array) $item);
104
-
105
-            return $builder->build((array) $item);
106
-        })->all();
107
-    }
108
-
109
-    /**
110
-     * Given a result array, return the entity builder needed to correctly
111
-     * build the result into an entity. If no getDiscriminatorColumnMap property
112
-     * has been defined on the EntityMap, we'll assume that the value stored in
113
-     * the $type column is the fully qualified class name of the entity and
114
-     * we'll use it instead.
115
-     *
116
-     * @param  array  $result
117
-     * @return EntityBuilder
118
-     */
119
-    protected function builderForResult(array $result)
120
-    {
121
-        $type = $result[$this->entityMap->getDiscriminatorColumn()];
122
-
123
-        $columnMap = $this->entityMap->getDiscriminatorColumnMap();
124
-
125
-        $class = isset($columnMap[$type]) ? $columnMap[$type]: $type;
126
-
127
-        if (!isset($this->builders[$type])) {
128
-            $this->builders[$type] = new EntityBuilder($this->manager->mapper($class), array_keys($this->eagerLoads));
129
-        }
130
-
131
-        return $this->builders[$type];
132
-    }
9
+	/**
10
+	 * An instance of the entity manager class.
11
+	 * @var \Analogue\ORM\System\Manager
12
+	 */
13
+	protected $manager;
14
+
15
+	/**
16
+	 * The default mapper used to build entities with.
17
+	 * @var \Analogue\ORM\System\Mapper
18
+	 */
19
+	protected $defaultMapper;
20
+
21
+	/**
22
+	 * Relations that will be eager loaded on this query
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $eagerLoads;
27
+
28
+	/**
29
+	 * The Entity Map for the entity to build.
30
+	 *
31
+	 * @var \Analogue\ORM\EntityMap
32
+	 */
33
+	protected $entityMap;
34
+
35
+	/**
36
+	 * An array of builders used by this class to build necessary
37
+	 * entities for each result type.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	protected $builders = [];
42
+
43
+	/**
44
+	 * @param Manager $manager
45
+	 * @param Mapper  $defaultMapper
46
+	 * @param array   $eagerLoads
47
+	 */
48
+	public function __construct(Manager $manager, Mapper $defaultMapper, array $eagerLoads)
49
+	{
50
+		$this->manager = $manager;
51
+
52
+		$this->defaultMapper = $defaultMapper;
53
+
54
+		$this->eagerLoads = $eagerLoads;
55
+
56
+		$this->entityMap = $defaultMapper->getEntityMap();
57
+	}
58
+
59
+	/**
60
+	 * Convert a result set into an array of entities
61
+	 *
62
+	 * @param  array $results
63
+	 * @return \Illuminate\Support\Collection
64
+	 */
65
+	public function build($results)
66
+	{
67
+		switch ($this->entityMap->getInheritanceType()) {
68
+			case 'single_table':
69
+				return $this->buildUsingSingleTableInheritance($results);
70
+				break;
71
+
72
+			default:
73
+				return $this->buildWithDefaultMapper($results);
74
+				break;
75
+		}
76
+	}
77
+
78
+	/**
79
+	 * Build an entity from results, using the default mapper on this builder.
80
+	 * This is the default build plan when no table inheritance is being used.
81
+	 *
82
+	 * @param  array $results
83
+	 * @return Collection
84
+	 */
85
+	protected function buildWithDefaultMapper($results)
86
+	{
87
+		$builder = new EntityBuilder($this->defaultMapper, array_keys($this->eagerLoads));
88
+
89
+		return collect($results)->map(function($item, $key) use ($builder) {
90
+			return $builder->build((array) $item);
91
+		})->all();
92
+	}
93
+
94
+	/**
95
+	 * Build an entity from results, using single table inheritance.
96
+	 *
97
+	 * @param  array $results
98
+	 * @return Collection
99
+	 */
100
+	protected function buildUsingSingleTableInheritance($results)
101
+	{
102
+		return collect($results)->map(function($item, $key) {
103
+			$builder = $this->builderForResult((array) $item);
104
+
105
+			return $builder->build((array) $item);
106
+		})->all();
107
+	}
108
+
109
+	/**
110
+	 * Given a result array, return the entity builder needed to correctly
111
+	 * build the result into an entity. If no getDiscriminatorColumnMap property
112
+	 * has been defined on the EntityMap, we'll assume that the value stored in
113
+	 * the $type column is the fully qualified class name of the entity and
114
+	 * we'll use it instead.
115
+	 *
116
+	 * @param  array  $result
117
+	 * @return EntityBuilder
118
+	 */
119
+	protected function builderForResult(array $result)
120
+	{
121
+		$type = $result[$this->entityMap->getDiscriminatorColumn()];
122
+
123
+		$columnMap = $this->entityMap->getDiscriminatorColumnMap();
124
+
125
+		$class = isset($columnMap[$type]) ? $columnMap[$type]: $type;
126
+
127
+		if (!isset($this->builders[$type])) {
128
+			$this->builders[$type] = new EntityBuilder($this->manager->mapper($class), array_keys($this->eagerLoads));
129
+		}
130
+
131
+		return $this->builders[$type];
132
+	}
133 133
 }
134 134
\ No newline at end of file
Please login to merge, or discard this patch.
src/System/Aggregate.php 3 patches
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -129,8 +129,7 @@
 block discarded – undo
129 129
             if ($this->hasSetMutator($key)) {
130 130
                 $method = 'set' . $this->getMutatorMethod($key);
131 131
                 $this->attributes[$key] = $this->$method($attribute);
132
-            }
133
-            else {
132
+            } else {
134 133
                 $this->attributes[$key] = $attribute;
135 134
             }
136 135
         }
Please login to merge, or discard this patch.
Indentation   +1042 added lines, -1042 removed lines patch added patch discarded remove patch
@@ -16,1068 +16,1068 @@
 block discarded – undo
16 16
  */
17 17
 class Aggregate implements InternallyMappable
18 18
 {
19
-    /**
20
-     * The Root Entity
21
-     *
22
-     * @var \Analogue\ORM\System\Wrappers\Wrapper
23
-     */
24
-    protected $wrappedEntity;
25
-
26
-    /** 
27
-     * Class of the entity being aggregated
28
-     * 
29
-     * @var string
30
-     */
31
-    protected $class;
32
-
33
-    /**
34
-     * Parent Root Aggregate
35
-     *
36
-     * @var \Analogue\ORM\System\Aggregate
37
-     */
38
-    protected $parent;
39
-
40
-    /**
41
-     * Parent's relationship method
42
-     *
43
-     * @var string
44
-     */
45
-    protected $parentRelationship;
46
-
47
-    /**
48
-     * Root Entity
49
-     *
50
-     * @var \Analogue\ORM\System\Aggregate
51
-     */
52
-    protected $root;
53
-
54
-    /**
55
-     * An associative array containing entity's
56
-     * relationships converted to Aggregates
57
-     *
58
-     * @var array
59
-     */
60
-    protected $relationships = [];
61
-
62
-    /**
63
-     * Relationship that need post-command synchronization
64
-     *
65
-     * @var array
66
-     */
67
-    protected $needSync = [];
68
-
69
-    /**
70
-     * Mapper
71
-     *
72
-     * @var \Analogue\ORM\System\Mapper;
73
-     */
74
-    protected $mapper;
75
-
76
-    /**
77
-     * Entity Map
78
-     *
79
-     * @var \Analogue\ORM\EntityMap;
80
-     */
81
-    protected $entityMap;
82
-
83
-    /**
84
-     * Create a new Aggregated Entity instance
85
-     *
86
-     * @param mixed          $entity
87
-     * @param Aggregate|null $parent
88
-     * @param string         $parentRelationship
89
-     * @param Aggregate|null $root
90
-     * @throws MappingException
91
-     */
92
-    public function __construct($entity, Aggregate $parent = null, $parentRelationship = null, Aggregate $root = null)
93
-    {
94
-        $factory = new Factory;
19
+	/**
20
+	 * The Root Entity
21
+	 *
22
+	 * @var \Analogue\ORM\System\Wrappers\Wrapper
23
+	 */
24
+	protected $wrappedEntity;
25
+
26
+	/** 
27
+	 * Class of the entity being aggregated
28
+	 * 
29
+	 * @var string
30
+	 */
31
+	protected $class;
32
+
33
+	/**
34
+	 * Parent Root Aggregate
35
+	 *
36
+	 * @var \Analogue\ORM\System\Aggregate
37
+	 */
38
+	protected $parent;
39
+
40
+	/**
41
+	 * Parent's relationship method
42
+	 *
43
+	 * @var string
44
+	 */
45
+	protected $parentRelationship;
46
+
47
+	/**
48
+	 * Root Entity
49
+	 *
50
+	 * @var \Analogue\ORM\System\Aggregate
51
+	 */
52
+	protected $root;
53
+
54
+	/**
55
+	 * An associative array containing entity's
56
+	 * relationships converted to Aggregates
57
+	 *
58
+	 * @var array
59
+	 */
60
+	protected $relationships = [];
61
+
62
+	/**
63
+	 * Relationship that need post-command synchronization
64
+	 *
65
+	 * @var array
66
+	 */
67
+	protected $needSync = [];
68
+
69
+	/**
70
+	 * Mapper
71
+	 *
72
+	 * @var \Analogue\ORM\System\Mapper;
73
+	 */
74
+	protected $mapper;
75
+
76
+	/**
77
+	 * Entity Map
78
+	 *
79
+	 * @var \Analogue\ORM\EntityMap;
80
+	 */
81
+	protected $entityMap;
82
+
83
+	/**
84
+	 * Create a new Aggregated Entity instance
85
+	 *
86
+	 * @param mixed          $entity
87
+	 * @param Aggregate|null $parent
88
+	 * @param string         $parentRelationship
89
+	 * @param Aggregate|null $root
90
+	 * @throws MappingException
91
+	 */
92
+	public function __construct($entity, Aggregate $parent = null, $parentRelationship = null, Aggregate $root = null)
93
+	{
94
+		$factory = new Factory;
95 95
         
96
-        $this->class = get_class($entity);
96
+		$this->class = get_class($entity);
97 97
 
98
-        $this->wrappedEntity = $factory->make($entity);
98
+		$this->wrappedEntity = $factory->make($entity);
99 99
 
100
-        $this->parent = $parent;
100
+		$this->parent = $parent;
101 101
 
102
-        $this->parentRelationship = $parentRelationship;
102
+		$this->parentRelationship = $parentRelationship;
103 103
 
104
-        $this->root = $root;
104
+		$this->root = $root;
105 105
 
106
-        $mapper = $this->getMapper($entity);
106
+		$mapper = $this->getMapper($entity);
107 107
 
108
-        $this->entityMap = $mapper->getEntityMap();
108
+		$this->entityMap = $mapper->getEntityMap();
109 109
              
110
-        $this->parseRelationships();
111
-    }
112
-
113
-    /**
114
-     * Parse Every relationships defined on the entity
115
-     *
116
-     * @throws MappingException
117
-     * @return void
118
-     */
119
-    protected function parseRelationships()
120
-    {
121
-        foreach ($this->entityMap->getSingleRelationships() as $relation) {
122
-            $this->parseSingleRelationship($relation);
123
-        }
124
-
125
-        foreach ($this->entityMap->getManyRelationships() as $relation) {
126
-            $this->parseManyRelationship($relation);
127
-        }
128
-    }
129
-
130
-    /**
131
-     * Parse for values common to single & many relations
132
-     *
133
-     * @param  string $relation
134
-     * @throws MappingException
135
-     * @return mixed|boolean
136
-     */
137
-    protected function parseForCommonValues($relation)
138
-    {
139
-        if (!$this->hasAttribute($relation)) {
140
-            // If no attribute exists for this relationships
141
-            // we'll make it a simple empty array. This will
142
-            // save us from constantly checking for the attributes
143
-            // actual existence.
144
-            $this->relationships[$relation] = [];
145
-            return false;
146
-        }
147
-
148
-        $value = $this->getRelationshipValue($relation);
149
-
150
-        if (is_null($value)) {
151
-            $this->relationships[$relation] = [];
152
-
153
-            // If the relationship's content is the null value
154
-            // and the Entity's exist in DB, we'll interpret this
155
-            // as the need to detach all related Entities,
156
-            // therefore a sync operation is needed.
157
-            $this->needSync[] = $relation;
158
-            return false;
159
-        }
160
-
161
-        return $value;
162
-    }
163
-
164
-    /**
165
-     * Parse a 'single' relationship
166
-     *
167
-     * @param  string $relation
168
-     * @throws MappingException
169
-     * @return boolean
170
-     */
171
-    protected function parseSingleRelationship($relation)
172
-    {
173
-        if (!$value = $this->parseForCommonValues($relation)) {
174
-            return true;
175
-        }
110
+		$this->parseRelationships();
111
+	}
112
+
113
+	/**
114
+	 * Parse Every relationships defined on the entity
115
+	 *
116
+	 * @throws MappingException
117
+	 * @return void
118
+	 */
119
+	protected function parseRelationships()
120
+	{
121
+		foreach ($this->entityMap->getSingleRelationships() as $relation) {
122
+			$this->parseSingleRelationship($relation);
123
+		}
124
+
125
+		foreach ($this->entityMap->getManyRelationships() as $relation) {
126
+			$this->parseManyRelationship($relation);
127
+		}
128
+	}
129
+
130
+	/**
131
+	 * Parse for values common to single & many relations
132
+	 *
133
+	 * @param  string $relation
134
+	 * @throws MappingException
135
+	 * @return mixed|boolean
136
+	 */
137
+	protected function parseForCommonValues($relation)
138
+	{
139
+		if (!$this->hasAttribute($relation)) {
140
+			// If no attribute exists for this relationships
141
+			// we'll make it a simple empty array. This will
142
+			// save us from constantly checking for the attributes
143
+			// actual existence.
144
+			$this->relationships[$relation] = [];
145
+			return false;
146
+		}
147
+
148
+		$value = $this->getRelationshipValue($relation);
149
+
150
+		if (is_null($value)) {
151
+			$this->relationships[$relation] = [];
152
+
153
+			// If the relationship's content is the null value
154
+			// and the Entity's exist in DB, we'll interpret this
155
+			// as the need to detach all related Entities,
156
+			// therefore a sync operation is needed.
157
+			$this->needSync[] = $relation;
158
+			return false;
159
+		}
160
+
161
+		return $value;
162
+	}
163
+
164
+	/**
165
+	 * Parse a 'single' relationship
166
+	 *
167
+	 * @param  string $relation
168
+	 * @throws MappingException
169
+	 * @return boolean
170
+	 */
171
+	protected function parseSingleRelationship($relation)
172
+	{
173
+		if (!$value = $this->parseForCommonValues($relation)) {
174
+			return true;
175
+		}
176 176
         
177
-        if ($value instanceof Collection || is_array($value) || $value instanceof CollectionProxy) {
178
-            throw new MappingException("Entity's attribute $relation should not be array, or collection");
179
-        }
180
-
181
-        if ($value instanceof LazyLoadingInterface && !$value->isProxyInitialized()) {
182
-            $this->relationships[$relation] = [];
183
-            return true;
184
-        }
185
-
186
-        // If the attribute is a loaded proxy, swap it for its
187
-        // loaded entity.
188
-        if ($value instanceof LazyLoadingInterface && $value->isProxyInitialized()) {
189
-            $value = $value->getWrappedValueHolderValue();
190
-        }
191
-
192
-        if ($this->isParentOrRoot($value)) {
193
-            $this->relationships[$relation] = [];
194
-            return true;
195
-        }
196
-
197
-        // At this point, we can assume the attribute is an Entity instance
198
-        // so we'll treat it as such.
199
-        $subAggregate = $this->createSubAggregate($value, $relation);
177
+		if ($value instanceof Collection || is_array($value) || $value instanceof CollectionProxy) {
178
+			throw new MappingException("Entity's attribute $relation should not be array, or collection");
179
+		}
180
+
181
+		if ($value instanceof LazyLoadingInterface && !$value->isProxyInitialized()) {
182
+			$this->relationships[$relation] = [];
183
+			return true;
184
+		}
185
+
186
+		// If the attribute is a loaded proxy, swap it for its
187
+		// loaded entity.
188
+		if ($value instanceof LazyLoadingInterface && $value->isProxyInitialized()) {
189
+			$value = $value->getWrappedValueHolderValue();
190
+		}
191
+
192
+		if ($this->isParentOrRoot($value)) {
193
+			$this->relationships[$relation] = [];
194
+			return true;
195
+		}
196
+
197
+		// At this point, we can assume the attribute is an Entity instance
198
+		// so we'll treat it as such.
199
+		$subAggregate = $this->createSubAggregate($value, $relation);
200 200
          
201
-        // Even if it's a single entity, we'll store it as an array
202
-        // just for consistency with other relationships
203
-        $this->relationships[$relation] = [$subAggregate];
204
-
205
-        // We always need to check a loaded relation is in sync
206
-        // with its local key
207
-        $this->needSync[] = $relation;
208
-
209
-        return true;
210
-    }
211
-
212
-    /**
213
-     * Check if value isn't parent or root in the aggregate
214
-     *
215
-     * @param  mixed
216
-     * @return boolean|null
217
-     */
218
-    protected function isParentOrRoot($value)
219
-    {
220
-        if (!is_null($this->root)) {
221
-            $rootClass = get_class($this->root->getEntityObject());
222
-            if ($rootClass == get_class($value)) {
223
-                return true;
224
-            }
225
-        }
226
-
227
-        if (!is_null($this->parent)) {
228
-            $parentClass = get_class($this->parent->getEntityObject());
229
-            if ($parentClass == get_class($value)) {
230
-                return true;
231
-            }
232
-        }
233
-    }
234
-
235
-    /**
236
-     * Parse a 'many' relationship
237
-     *
238
-     * @param  string $relation
239
-     * @throws MappingException
240
-     * @return boolean
241
-     */
242
-    protected function parseManyRelationship($relation)
243
-    {
244
-        if (!$value = $this->parseForCommonValues($relation)) {
245
-            return true;
246
-        }
201
+		// Even if it's a single entity, we'll store it as an array
202
+		// just for consistency with other relationships
203
+		$this->relationships[$relation] = [$subAggregate];
204
+
205
+		// We always need to check a loaded relation is in sync
206
+		// with its local key
207
+		$this->needSync[] = $relation;
208
+
209
+		return true;
210
+	}
211
+
212
+	/**
213
+	 * Check if value isn't parent or root in the aggregate
214
+	 *
215
+	 * @param  mixed
216
+	 * @return boolean|null
217
+	 */
218
+	protected function isParentOrRoot($value)
219
+	{
220
+		if (!is_null($this->root)) {
221
+			$rootClass = get_class($this->root->getEntityObject());
222
+			if ($rootClass == get_class($value)) {
223
+				return true;
224
+			}
225
+		}
226
+
227
+		if (!is_null($this->parent)) {
228
+			$parentClass = get_class($this->parent->getEntityObject());
229
+			if ($parentClass == get_class($value)) {
230
+				return true;
231
+			}
232
+		}
233
+	}
234
+
235
+	/**
236
+	 * Parse a 'many' relationship
237
+	 *
238
+	 * @param  string $relation
239
+	 * @throws MappingException
240
+	 * @return boolean
241
+	 */
242
+	protected function parseManyRelationship($relation)
243
+	{
244
+		if (!$value = $this->parseForCommonValues($relation)) {
245
+			return true;
246
+		}
247 247
         
248
-        if (is_array($value) || $value instanceof Collection) {
249
-            $this->needSync[] = $relation;
250
-        }
251
-
252
-        // If the relation is a proxy, we test is the relation
253
-        // has been lazy loaded, otherwise we'll just treat
254
-        // the subset of newly added items.
255
-        if ($value instanceof CollectionProxy && $value->isProxyInitialized()) {
256
-            $this->needSync[] = $relation;
257
-            //$value = $value->getUnderlyingCollection();
258
-        }
259
-
260
-        if ($value instanceof CollectionProxy && !$value->isProxyInitialized()) {
261
-            $value = $value->getAddedItems();
262
-        }
263
-
264
-        // At this point $value should be either an array or an instance
265
-        // of a collection class.
266
-        if (!is_array($value) && !$value instanceof Collection) {
267
-            throw new MappingException("'$relation' attribute should be array() or Collection");
268
-        }
269
-
270
-        $this->relationships[$relation] = $this->createSubAggregates($value, $relation);
248
+		if (is_array($value) || $value instanceof Collection) {
249
+			$this->needSync[] = $relation;
250
+		}
251
+
252
+		// If the relation is a proxy, we test is the relation
253
+		// has been lazy loaded, otherwise we'll just treat
254
+		// the subset of newly added items.
255
+		if ($value instanceof CollectionProxy && $value->isProxyInitialized()) {
256
+			$this->needSync[] = $relation;
257
+			//$value = $value->getUnderlyingCollection();
258
+		}
259
+
260
+		if ($value instanceof CollectionProxy && !$value->isProxyInitialized()) {
261
+			$value = $value->getAddedItems();
262
+		}
263
+
264
+		// At this point $value should be either an array or an instance
265
+		// of a collection class.
266
+		if (!is_array($value) && !$value instanceof Collection) {
267
+			throw new MappingException("'$relation' attribute should be array() or Collection");
268
+		}
269
+
270
+		$this->relationships[$relation] = $this->createSubAggregates($value, $relation);
271 271
         
272
-        return true;
273
-    }
274
-
275
-    /**
276
-     * Return Entity's relationship attribute
277
-     *
278
-     * @param  string $relation
279
-     * @throws MappingException
280
-     * @return mixed
281
-     */
282
-    protected function getRelationshipValue($relation)
283
-    {
284
-        $value = $this->getEntityAttribute($relation);
285
-        //if($relation == "role") tdd($this->wrappedEntity->getEntityAttributes());
286
-        if (is_bool($value) || is_float($value) || is_int($value) || is_string($value)) {
287
-            throw new MappingException("Entity's attribute $relation should be array, object, collection or null");
288
-        }
289
-
290
-        return $value;
291
-    }
292
-
293
-    /**
294
-     * Create a child, aggregated entity
295
-     *
296
-     * @param  mixed $entities
297
-     * @param string $relation
298
-     * @return array
299
-     */
300
-    protected function createSubAggregates($entities, $relation)
301
-    {
302
-        $aggregates = [];
303
-
304
-        foreach ($entities as $entity) {
305
-            $aggregates[] = $this->createSubAggregate($entity, $relation);
306
-        }
307
-
308
-        return $aggregates;
309
-    }
310
-
311
-    /**
312
-     * Create a related subAggregate
313
-     *
314
-     * @param  mixed $entity
315
-     * @param  string $relation
316
-     * @throws MappingException
317
-     * @return self
318
-     */
319
-    protected function createSubAggregate($entity, $relation)
320
-    {
321
-        // If root isn't defined, then this is the Aggregate Root
322
-        if (is_null($this->root)) {
323
-            $root = $this;
324
-        } else {
325
-            $root = $this->root;
326
-        }
327
-
328
-        return new self($entity, $this, $relation, $root);
329
-    }
330
-
331
-    /**
332
-     * Get the Entity's primary key attribute
333
-     *
334
-     * @return string|integer
335
-     */
336
-    public function getEntityId()
337
-    {
338
-        return $this->wrappedEntity->getEntityAttribute($this->entityMap->getKeyName());
339
-    }
340
-
341
-    /**
342
-     * Get the name of the primary key
343
-     *
344
-     * @return string
345
-     */
346
-    public function getEntityKey()
347
-    {
348
-        return $this->entityMap->getKeyName();
349
-    }
350
-
351
-    /**
352
-     * Return the entity map for the current entity
353
-     *
354
-     * @return \Analogue\ORM\EntityMap
355
-     */
356
-    public function getEntityMap()
357
-    {
358
-        return $this->entityMap;
359
-    }
360
-
361
-    /**
362
-     * Return the Entity's hash $class.$id
363
-     *
364
-     * @return string
365
-     */
366
-    public function getEntityHash()
367
-    {
368
-        return $this->getEntityClass() . '.' . $this->getEntityId();
369
-    }
370
-
371
-    /**
372
-     * Get wrapped entity class
373
-     *
374
-     * @return string
375
-     */
376
-    public function getEntityClass()
377
-    {
378
-        return $this->entityMap->getClass();
379
-    }
380
-
381
-    /**
382
-     * Return the Mapper's entity cache
383
-     *
384
-     * @return \Analogue\ORM\System\EntityCache
385
-     */
386
-    protected function getEntityCache()
387
-    {
388
-        return $this->getMapper()->getEntityCache();
389
-    }
390
-
391
-    /**
392
-     * Get a relationship as an aggregated entities' array
393
-     *
394
-     * @param  string $name
395
-     * @return array
396
-     */
397
-    public function getRelationship($name)
398
-    {
399
-        if (array_key_exists($name, $this->relationships)) {
400
-            return $this->relationships[$name];
401
-        } else {
402
-            return [];
403
-        }
404
-    }
405
-
406
-    /**
407
-     * [TO IMPLEMENT]
408
-     *
409
-     * @return array
410
-     */
411
-    public function getPivotAttributes()
412
-    {
413
-        return [];
414
-    }
415
-
416
-    /**
417
-     * Get Non existing related entities from several relationships
418
-     *
419
-     * @param  array $relationships
420
-     * @return array
421
-     */
422
-    public function getNonExistingRelated(array $relationships)
423
-    {
424
-        $nonExisting = [];
425
-
426
-        foreach ($relationships as $relation) {
427
-
428
-            if ($this->hasAttribute($relation) && array_key_exists($relation, $this->relationships)) {
429
-                $nonExisting = array_merge($nonExisting, $this->getNonExistingFromRelation($relation));
430
-            }
431
-        }
432
-
433
-        return $nonExisting;
434
-    }
435
-
436
-    /**
437
-     * Get non-existing related entities from a single relation
438
-     *
439
-     * @param  string $relation
440
-     * @return array
441
-     */
442
-    protected function getNonExistingFromRelation($relation)
443
-    {
444
-        $nonExisting = [];
445
-
446
-        foreach ($this->relationships[$relation] as $aggregate) {
447
-            if (!$aggregate->exists()) {
448
-                $nonExisting[] = $aggregate;
449
-            }
450
-        }
451
-
452
-        return $nonExisting;
453
-    }
454
-
455
-    /**
456
-     * Synchronize relationships if needed
457
-     *
458
-     * @param array
459
-     * @return void
460
-     */
461
-    public function syncRelationships(array $relationships)
462
-    {
463
-        foreach ($relationships as $relation) {
464
-            if (in_array($relation, $this->needSync)) {
465
-                $this->synchronize($relation);
466
-            }
467
-        }
468
-    }
469
-
470
-    /**
471
-     * Synchronize a relationship attribute
472
-     *
473
-     * @param $relation
474
-     * @return void
475
-     */
476
-    protected function synchronize($relation)
477
-    {
478
-        $actualContent = $this->relationships[$relation];
479
-
480
-        $relationshipObject = $this->entityMap->$relation($this->getEntityObject());
481
-        $relationshipObject->setParent($this->wrappedEntity);
482
-        $relationshipObject->sync($actualContent);
483
-    }
484
-
485
-    /**
486
-     * Returns an array of Missing related Entities for the
487
-     * given $relation
488
-     *
489
-     * @param  string $relation
490
-     * @return array
491
-     */
492
-    public function getMissingEntities($relation)
493
-    {
494
-        $cachedRelations = $this->getCachedAttribute($relation);
495
-
496
-        if (!is_null($cachedRelations)) {
497
-            $missing = [];
498
-
499
-            foreach ($cachedRelations as $hash) {
500
-                if (!$this->getRelatedAggregateFromHash($hash, $relation)) {
501
-                    $missing[] = $hash;
502
-                }
503
-            }
504
-
505
-            return $missing;
506
-        } else {
507
-            return [];
508
-        }
509
-    }
272
+		return true;
273
+	}
274
+
275
+	/**
276
+	 * Return Entity's relationship attribute
277
+	 *
278
+	 * @param  string $relation
279
+	 * @throws MappingException
280
+	 * @return mixed
281
+	 */
282
+	protected function getRelationshipValue($relation)
283
+	{
284
+		$value = $this->getEntityAttribute($relation);
285
+		//if($relation == "role") tdd($this->wrappedEntity->getEntityAttributes());
286
+		if (is_bool($value) || is_float($value) || is_int($value) || is_string($value)) {
287
+			throw new MappingException("Entity's attribute $relation should be array, object, collection or null");
288
+		}
289
+
290
+		return $value;
291
+	}
292
+
293
+	/**
294
+	 * Create a child, aggregated entity
295
+	 *
296
+	 * @param  mixed $entities
297
+	 * @param string $relation
298
+	 * @return array
299
+	 */
300
+	protected function createSubAggregates($entities, $relation)
301
+	{
302
+		$aggregates = [];
303
+
304
+		foreach ($entities as $entity) {
305
+			$aggregates[] = $this->createSubAggregate($entity, $relation);
306
+		}
307
+
308
+		return $aggregates;
309
+	}
310
+
311
+	/**
312
+	 * Create a related subAggregate
313
+	 *
314
+	 * @param  mixed $entity
315
+	 * @param  string $relation
316
+	 * @throws MappingException
317
+	 * @return self
318
+	 */
319
+	protected function createSubAggregate($entity, $relation)
320
+	{
321
+		// If root isn't defined, then this is the Aggregate Root
322
+		if (is_null($this->root)) {
323
+			$root = $this;
324
+		} else {
325
+			$root = $this->root;
326
+		}
327
+
328
+		return new self($entity, $this, $relation, $root);
329
+	}
330
+
331
+	/**
332
+	 * Get the Entity's primary key attribute
333
+	 *
334
+	 * @return string|integer
335
+	 */
336
+	public function getEntityId()
337
+	{
338
+		return $this->wrappedEntity->getEntityAttribute($this->entityMap->getKeyName());
339
+	}
340
+
341
+	/**
342
+	 * Get the name of the primary key
343
+	 *
344
+	 * @return string
345
+	 */
346
+	public function getEntityKey()
347
+	{
348
+		return $this->entityMap->getKeyName();
349
+	}
350
+
351
+	/**
352
+	 * Return the entity map for the current entity
353
+	 *
354
+	 * @return \Analogue\ORM\EntityMap
355
+	 */
356
+	public function getEntityMap()
357
+	{
358
+		return $this->entityMap;
359
+	}
360
+
361
+	/**
362
+	 * Return the Entity's hash $class.$id
363
+	 *
364
+	 * @return string
365
+	 */
366
+	public function getEntityHash()
367
+	{
368
+		return $this->getEntityClass() . '.' . $this->getEntityId();
369
+	}
370
+
371
+	/**
372
+	 * Get wrapped entity class
373
+	 *
374
+	 * @return string
375
+	 */
376
+	public function getEntityClass()
377
+	{
378
+		return $this->entityMap->getClass();
379
+	}
380
+
381
+	/**
382
+	 * Return the Mapper's entity cache
383
+	 *
384
+	 * @return \Analogue\ORM\System\EntityCache
385
+	 */
386
+	protected function getEntityCache()
387
+	{
388
+		return $this->getMapper()->getEntityCache();
389
+	}
390
+
391
+	/**
392
+	 * Get a relationship as an aggregated entities' array
393
+	 *
394
+	 * @param  string $name
395
+	 * @return array
396
+	 */
397
+	public function getRelationship($name)
398
+	{
399
+		if (array_key_exists($name, $this->relationships)) {
400
+			return $this->relationships[$name];
401
+		} else {
402
+			return [];
403
+		}
404
+	}
405
+
406
+	/**
407
+	 * [TO IMPLEMENT]
408
+	 *
409
+	 * @return array
410
+	 */
411
+	public function getPivotAttributes()
412
+	{
413
+		return [];
414
+	}
415
+
416
+	/**
417
+	 * Get Non existing related entities from several relationships
418
+	 *
419
+	 * @param  array $relationships
420
+	 * @return array
421
+	 */
422
+	public function getNonExistingRelated(array $relationships)
423
+	{
424
+		$nonExisting = [];
425
+
426
+		foreach ($relationships as $relation) {
427
+
428
+			if ($this->hasAttribute($relation) && array_key_exists($relation, $this->relationships)) {
429
+				$nonExisting = array_merge($nonExisting, $this->getNonExistingFromRelation($relation));
430
+			}
431
+		}
432
+
433
+		return $nonExisting;
434
+	}
435
+
436
+	/**
437
+	 * Get non-existing related entities from a single relation
438
+	 *
439
+	 * @param  string $relation
440
+	 * @return array
441
+	 */
442
+	protected function getNonExistingFromRelation($relation)
443
+	{
444
+		$nonExisting = [];
445
+
446
+		foreach ($this->relationships[$relation] as $aggregate) {
447
+			if (!$aggregate->exists()) {
448
+				$nonExisting[] = $aggregate;
449
+			}
450
+		}
451
+
452
+		return $nonExisting;
453
+	}
454
+
455
+	/**
456
+	 * Synchronize relationships if needed
457
+	 *
458
+	 * @param array
459
+	 * @return void
460
+	 */
461
+	public function syncRelationships(array $relationships)
462
+	{
463
+		foreach ($relationships as $relation) {
464
+			if (in_array($relation, $this->needSync)) {
465
+				$this->synchronize($relation);
466
+			}
467
+		}
468
+	}
469
+
470
+	/**
471
+	 * Synchronize a relationship attribute
472
+	 *
473
+	 * @param $relation
474
+	 * @return void
475
+	 */
476
+	protected function synchronize($relation)
477
+	{
478
+		$actualContent = $this->relationships[$relation];
479
+
480
+		$relationshipObject = $this->entityMap->$relation($this->getEntityObject());
481
+		$relationshipObject->setParent($this->wrappedEntity);
482
+		$relationshipObject->sync($actualContent);
483
+	}
484
+
485
+	/**
486
+	 * Returns an array of Missing related Entities for the
487
+	 * given $relation
488
+	 *
489
+	 * @param  string $relation
490
+	 * @return array
491
+	 */
492
+	public function getMissingEntities($relation)
493
+	{
494
+		$cachedRelations = $this->getCachedAttribute($relation);
495
+
496
+		if (!is_null($cachedRelations)) {
497
+			$missing = [];
498
+
499
+			foreach ($cachedRelations as $hash) {
500
+				if (!$this->getRelatedAggregateFromHash($hash, $relation)) {
501
+					$missing[] = $hash;
502
+				}
503
+			}
504
+
505
+			return $missing;
506
+		} else {
507
+			return [];
508
+		}
509
+	}
510 510
        
511
-    /**
512
-     * Get Relationships who have dirty attributes / dirty relationships
513
-     *
514
-     * @return array
515
-     */
516
-    public function getDirtyRelationships()
517
-    {
518
-        $dirtyAggregates = [];
519
-
520
-        foreach ($this->relationships as $relation) {
521
-            foreach ($relation as $aggregate) {
522
-
523
-                if (!$aggregate->exists() || $aggregate->isDirty() || count($aggregate->getDirtyRelationships()) > 0) {
524
-                    $dirtyAggregates[] = $aggregate;
525
-                }
526
-            }
527
-        }
528
-
529
-        return $dirtyAggregates;
530
-    }
511
+	/**
512
+	 * Get Relationships who have dirty attributes / dirty relationships
513
+	 *
514
+	 * @return array
515
+	 */
516
+	public function getDirtyRelationships()
517
+	{
518
+		$dirtyAggregates = [];
519
+
520
+		foreach ($this->relationships as $relation) {
521
+			foreach ($relation as $aggregate) {
522
+
523
+				if (!$aggregate->exists() || $aggregate->isDirty() || count($aggregate->getDirtyRelationships()) > 0) {
524
+					$dirtyAggregates[] = $aggregate;
525
+				}
526
+			}
527
+		}
528
+
529
+		return $dirtyAggregates;
530
+	}
531 531
     
532
-    /**
533
-     * Compare the object's raw attributes with the record in cache
534
-     *
535
-     * @return boolean
536
-     */
537
-    public function isDirty()
538
-    {
539
-        if (count($this->getDirtyRawAttributes()) > 0) {
540
-            return true;
541
-        } else {
542
-            return false;
543
-        }
544
-    }
545
-
546
-    /**
547
-     * Get Raw Entity's attributes, as they are represented
548
-     * in the database, including value objects, foreign keys,
549
-     * and discriminator column
550
-     *
551
-     * @return array
552
-     */
553
-    public function getRawAttributes()
554
-    {
555
-        $attributes = $this->wrappedEntity->getEntityAttributes();
556
-
557
-        foreach ($this->entityMap->getRelationships() as $relation) {
558
-            unset($attributes[$relation]);
559
-        }
560
-
561
-        if($this->entityMap->getInheritanceType() == 'single_table') {
562
-            $attributes = $this->addDiscriminatorColumn($attributes);
563
-        }
564
-
565
-        $attributes = $this->flattenEmbeddables($attributes);
566
-
567
-        $foreignKeys = $this->getForeignKeyAttributes();
568
-
569
-        return $attributes + $foreignKeys;
570
-    }
571
-
572
-    /**
573
-     * Add Discriminator Column if it doesn't exist on the actual entity
574
-     * 
575
-     * @param array $attributes
576
-     * @return array
577
-     */
578
-    protected function addDiscriminatorColumn($attributes)
579
-    {
580
-        $discriminatorColumn = $this->entityMap->getDiscriminatorColumn();
581
-        $entityClass = $this->entityMap->getClass();
582
-
583
-        if(! array_key_exists($discriminatorColumn, $attributes)) {
532
+	/**
533
+	 * Compare the object's raw attributes with the record in cache
534
+	 *
535
+	 * @return boolean
536
+	 */
537
+	public function isDirty()
538
+	{
539
+		if (count($this->getDirtyRawAttributes()) > 0) {
540
+			return true;
541
+		} else {
542
+			return false;
543
+		}
544
+	}
545
+
546
+	/**
547
+	 * Get Raw Entity's attributes, as they are represented
548
+	 * in the database, including value objects, foreign keys,
549
+	 * and discriminator column
550
+	 *
551
+	 * @return array
552
+	 */
553
+	public function getRawAttributes()
554
+	{
555
+		$attributes = $this->wrappedEntity->getEntityAttributes();
556
+
557
+		foreach ($this->entityMap->getRelationships() as $relation) {
558
+			unset($attributes[$relation]);
559
+		}
560
+
561
+		if($this->entityMap->getInheritanceType() == 'single_table') {
562
+			$attributes = $this->addDiscriminatorColumn($attributes);
563
+		}
564
+
565
+		$attributes = $this->flattenEmbeddables($attributes);
566
+
567
+		$foreignKeys = $this->getForeignKeyAttributes();
568
+
569
+		return $attributes + $foreignKeys;
570
+	}
571
+
572
+	/**
573
+	 * Add Discriminator Column if it doesn't exist on the actual entity
574
+	 * 
575
+	 * @param array $attributes
576
+	 * @return array
577
+	 */
578
+	protected function addDiscriminatorColumn($attributes)
579
+	{
580
+		$discriminatorColumn = $this->entityMap->getDiscriminatorColumn();
581
+		$entityClass = $this->entityMap->getClass();
582
+
583
+		if(! array_key_exists($discriminatorColumn, $attributes)) {
584 584
             
585
-            // Use key if present in discriminatorMap
586
-            $map = $this->entityMap->getDiscriminatorColumnMap();
587
-
588
-            $type = array_search($entityClass, $map);
589
-
590
-            if($type === false) {
591
-                // Use entity FQDN if no corresponding key is set
592
-                $attributes[$discriminatorColumn] = $entityClass;
593
-            }
594
-            else {
595
-                $attributes[$discriminatorColumn] = $type;
596
-            }
597
-        }
598
-
599
-        return $attributes;
600
-    }
601
-
602
-    /**
603
-     * Convert Value Objects to raw db attributes
604
-     *
605
-     * @param  array $attributes
606
-     * @return array
607
-     */
608
-    protected function flattenEmbeddables($attributes)
609
-    {
610
-        $embeddables = $this->entityMap->getEmbeddables();
585
+			// Use key if present in discriminatorMap
586
+			$map = $this->entityMap->getDiscriminatorColumnMap();
587
+
588
+			$type = array_search($entityClass, $map);
589
+
590
+			if($type === false) {
591
+				// Use entity FQDN if no corresponding key is set
592
+				$attributes[$discriminatorColumn] = $entityClass;
593
+			}
594
+			else {
595
+				$attributes[$discriminatorColumn] = $type;
596
+			}
597
+		}
598
+
599
+		return $attributes;
600
+	}
601
+
602
+	/**
603
+	 * Convert Value Objects to raw db attributes
604
+	 *
605
+	 * @param  array $attributes
606
+	 * @return array
607
+	 */
608
+	protected function flattenEmbeddables($attributes)
609
+	{
610
+		$embeddables = $this->entityMap->getEmbeddables();
611 611
         
612
-        foreach ($embeddables as $localKey => $embed) {
613
-            // Retrieve the value object from the entity's attributes
614
-            $valueObject = $attributes[$localKey];
612
+		foreach ($embeddables as $localKey => $embed) {
613
+			// Retrieve the value object from the entity's attributes
614
+			$valueObject = $attributes[$localKey];
615 615
 
616
-            // Unset the corresponding key
617
-            unset($attributes[$localKey]);
616
+			// Unset the corresponding key
617
+			unset($attributes[$localKey]);
618 618
 
619
-            // TODO Make wrapper object compatible with value objects
620
-            $valueObjectAttributes = $valueObject->getEntityAttributes();
619
+			// TODO Make wrapper object compatible with value objects
620
+			$valueObjectAttributes = $valueObject->getEntityAttributes();
621 621
 
622
-            // Now (if setup in the entity map) we prefix the value object's
623
-            // attributes with the snake_case name of the embedded class.
624
-            $prefix = snake_case(class_basename($embed));
622
+			// Now (if setup in the entity map) we prefix the value object's
623
+			// attributes with the snake_case name of the embedded class.
624
+			$prefix = snake_case(class_basename($embed));
625 625
 
626
-            foreach ($valueObjectAttributes as $key=>$value) {
627
-                $valueObjectAttributes[$prefix . '_' . $key] = $value;
628
-                unset($valueObjectAttributes[$key]);
629
-            }
626
+			foreach ($valueObjectAttributes as $key=>$value) {
627
+				$valueObjectAttributes[$prefix . '_' . $key] = $value;
628
+				unset($valueObjectAttributes[$key]);
629
+			}
630 630
 
631
-            $attributes = array_merge($attributes, $valueObjectAttributes);
632
-        }
631
+			$attributes = array_merge($attributes, $valueObjectAttributes);
632
+		}
633 633
         
634
-        return $attributes;
635
-    }
636
-
637
-    /**
638
-     * Return's entity raw attributes in the state they were at last
639
-     * query.
640
-     *
641
-     * @param  array|null $columns
642
-     * @return array
643
-     */
644
-    protected function getCachedRawAttributes(array $columns = null)
645
-    {
646
-        $cachedAttributes = $this->getCache()->get($this->getEntityId());
647
-
648
-        if (is_null($columns)) {
649
-            return $cachedAttributes;
650
-        } else {
651
-            return array_only($cachedAttributes, $columns);
652
-        }
653
-    }
654
-
655
-    /**
656
-     * Return a single attribute from the cache
657
-     * @param  string $key
658
-     * @return mixed
659
-     */
660
-    protected function getCachedAttribute($key)
661
-    {
662
-        $cachedAttributes = $this->getCache()->get($this->getEntityId());
663
-
664
-        if (!array_key_exists($key, $cachedAttributes)) {
665
-            return null;
666
-        } else {
667
-            return $cachedAttributes[$key];
668
-        }
669
-    }
670
-
671
-    /**
672
-     * Convert related Entity's attributes to foreign keys
673
-     *
674
-     * @return array
675
-     */
676
-    protected function getForeignKeyAttributes()
677
-    {
678
-        $foreignKeys = [];
679
-
680
-        foreach ($this->entityMap->getLocalRelationships() as $relation) {
681
-            // check if relationship has been parsed, meaning it has an actual object
682
-            // in the entity's attributes
683
-            if ($this->isActualRelationships($relation)) {
684
-                $foreignKeys = $foreignKeys + $this->getForeignKeyAttributesFromRelation($relation);
685
-            }
686
-        }
687
-
688
-        if ( ! is_null($this->parent)) {
689
-            $foreignKeys = $foreignKeys + $this->getForeignKeyAttributesFromParent();
690
-        }
691
-
692
-        return $foreignKeys;
693
-    }
694
-
695
-    /**
696
-     * Return an associative array containing the key-value pair(s) from
697
-     * the related entity.
698
-     *
699
-     * @param  string $relation
700
-     * @return array
701
-     */
702
-    protected function getForeignKeyAttributesFromRelation($relation)
703
-    {
704
-        $localRelations = $this->entityMap->getLocalRelationships();
705
-
706
-        if (in_array($relation, $localRelations)) {
707
-            // Call Relationship's method
708
-            $relationship = $this->entityMap->$relation($this->getEntityObject());
709
-
710
-            $relatedAggregate = $this->relationships[$relation][0];
711
-
712
-            return $relationship->getForeignKeyValuePair($relatedAggregate->getEntityObject());
713
-        } else {
714
-            return [];
715
-        }
716
-    }
717
-
718
-    /**
719
-     * Get foreign key attribute(s) from a parent entity in this
720
-     * aggregate context
721
-     *
722
-     * @return array
723
-     */
724
-    protected function getForeignKeyAttributesFromParent()
725
-    {
726
-        $parentMap = $this->parent->getEntityMap();
727
-
728
-        $parentForeignRelations = $parentMap->getForeignRelationships();
729
-        $parentPivotRelations = $parentMap->getPivotRelationships();
730
-
731
-        // The parentRelation is the name of the relationship
732
-        // methods on the parent entity map
733
-        $parentRelation = $this->parentRelationship;
734
-
735
-        if (in_array($parentRelation, $parentForeignRelations)
736
-            && !in_array($parentRelation, $parentPivotRelations)
737
-        ) {
738
-            $parentObject = $this->parent->getEntityObject();
739
-
740
-            // Call Relationship's method on parent map
741
-            $relationship = $parentMap->$parentRelation($parentObject);
742
-
743
-            return $relationship->getForeignKeyValuePair();
744
-        } else {
745
-            return [];
746
-        }
747
-    }
748
-
749
-    /**
750
-     * Update Pivot records on loaded relationships, by comparing the
751
-     * values from the Entity Cache to the actual relationship inside
752
-     * the aggregated entity.
753
-     *
754
-     * @return void
755
-     */
756
-    public function updatePivotRecords()
757
-    {
758
-        $pivots = $this->entityMap->getPivotRelationships();
759
-
760
-        foreach ($pivots as $pivot) {
761
-            if (array_key_exists($pivot, $this->relationships)) {
762
-                $this->updatePivotRelation($pivot);
763
-            }
764
-        }
765
-    }
766
-
767
-    /**
768
-     * Update Single pivot relationship
769
-     *
770
-     * @param  string $relation
771
-     * @return void
772
-     */
773
-    protected function updatePivotRelation($relation)
774
-    {
775
-        $hashes = $this->getEntityHashesFromRelation($relation);
776
-
777
-        $cachedAttributes = $this->getCachedRawAttributes();
778
-
779
-        if (array_key_exists($relation, $cachedAttributes)) {
780
-            // Compare the two array of hashes to find out existing
781
-            // pivot records, and the ones to be created.
782
-            $new = array_diff($hashes, array_keys($cachedAttributes[$relation]));
783
-            $existing = array_intersect($hashes, array_keys($cachedAttributes[$relation]));
784
-        } else {
785
-            $existing = [];
786
-            $new = $hashes;
787
-        }
788
-
789
-        if (count($new) > 0) {
790
-            $pivots = $this->getRelatedAggregatesFromHashes($new, $relation);
791
-
792
-            $this->entityMap->$relation($this->getEntityObject())->createPivots($pivots);
793
-        }
794
-
795
-        if (count($existing) > 0) {
796
-            foreach ($existing as $pivotHash) {
797
-                $this->updatePivotIfDirty($pivotHash, $relation);
798
-            }
799
-        }
800
-    }
801
-
802
-    /**
803
-     * Compare existing pivot record in cache and update it
804
-     * if the pivot attributes are dirty
805
-     *
806
-     * @param  string $pivotHash
807
-     * @param  string $relation
808
-     * @return void
809
-     */
810
-    protected function updatePivotIfDirty($pivotHash, $relation)
811
-    {
812
-        $aggregate = $this->getRelatedAggregateFromHash($pivotHash, $relation);
813
-
814
-        if ($aggregate->hasAttribute('pivot')) {
815
-            $pivot = $aggregate->getEntityAttribute('pivot')->getEntityAttributes();
816
-
817
-            $cachedPivotAttributes = $this->getPivotAttributesFromCache($pivotHash, $relation);
818
-
819
-            $actualPivotAttributes = array_only($pivot, array_keys($cachedPivotAttributes));
820
-
821
-            $dirty = $this->getDirtyAttributes($actualPivotAttributes, $cachedPivotAttributes);
822
-
823
-            if (count($dirty) > 0) {
824
-                $id = $aggregate->getEntityId();
825
-
826
-                $this->entityMap->$relation($this->getEntityObject())->updateExistingPivot($id, $dirty);
827
-            }
828
-        }
829
-    }
830
-
831
-    /**
832
-     * Compare two attributes array and return dirty attributes
833
-     *
834
-     * @param  array $actual
835
-     * @param  array $cached
836
-     * @return array
837
-     */
838
-    protected function getDirtyAttributes(array $actual, array $cached)
839
-    {
840
-        $dirty = [];
841
-
842
-        foreach ($actual as $key => $value) {
843
-            if (!$this->originalIsNumericallyEquivalent($value, $cached[$key])) {
844
-                $dirty[$key] = $actual[$key];
845
-            }
846
-        }
847
-
848
-        return $dirty;
849
-    }
850
-
851
-    /**
852
-     *
853
-     * @param  string $pivotHash
854
-     * @param  string $relation
855
-     * @return array
856
-     */
857
-    protected function getPivotAttributesFromCache($pivotHash, $relation)
858
-    {
859
-        $cachedAttributes = $this->getCachedRawAttributes();
860
-
861
-        $cachedRelations = $cachedAttributes[$relation];
862
-
863
-        foreach ($cachedRelations as $cachedRelation) {
864
-            if ($cachedRelation == $pivotHash) {
865
-                return $cachedRelation->getPivotAttributes();
866
-            }
867
-        }
868
-    }
869
-
870
-    /**
871
-     * Returns an array of related Aggregates from its entity hashes
872
-     *
873
-     * @param  array  $hashes
874
-     * @param  string $relation
875
-     * @return array
876
-     */
877
-    protected function getRelatedAggregatesFromHashes(array $hashes, $relation)
878
-    {
879
-        $related = [];
880
-
881
-        foreach ($hashes as $hash) {
882
-            $aggregate = $this->getRelatedAggregateFromHash($hash, $relation);
883
-
884
-            if (!is_null($aggregate)) {
885
-                $related[] = $aggregate;
886
-            }
887
-        }
888
-
889
-        return $related;
890
-    }
891
-
892
-    /**
893
-     * Get related aggregate from its hash
894
-     *
895
-     * @param  string $hash
896
-     * @param  string $relation
897
-     * @return \Analogue\ORM\System\Aggregate|null
898
-     */
899
-    protected function getRelatedAggregateFromHash($hash, $relation)
900
-    {
901
-        foreach ($this->relationships[$relation] as $aggregate) {
902
-            if ($aggregate->getEntityHash() == $hash) {
903
-                return $aggregate;
904
-            }
905
-        }
906
-        return null;
907
-    }
908
-
909
-    /**
910
-     * Return an array of Entity Hashes from a specific relation
911
-     *
912
-     * @param  string $relation
913
-     * @return array
914
-     */
915
-    protected function getEntityHashesFromRelation($relation)
916
-    {
917
-        return array_map(function ($aggregate) {
918
-            return $aggregate->getEntityHash();
919
-        }, $this->relationships[$relation]);
920
-    }
921
-
922
-    /**
923
-     * Check the existence of an actual relationship
924
-     *
925
-     * @param  string $relation
926
-     * @return boolean
927
-     */
928
-    protected function isActualRelationships($relation)
929
-    {
930
-        return array_key_exists($relation, $this->relationships)
931
-            && count($this->relationships[$relation]) > 0;
932
-    }
933
-
934
-    /**
935
-     * Return cache instance for the current entity type
936
-     *
937
-     * @return \Analogue\ORM\System\EntityCache
938
-     */
939
-    protected function getCache()
940
-    {
941
-        return $this->getMapper()->getEntityCache();
942
-    }
943
-
944
-    /**
945
-     * Get Only Raw Entiy's attributes which have been modified
946
-     * since last query
947
-     *
948
-     * @return array
949
-     */
950
-    public function getDirtyRawAttributes()
951
-    {
952
-        $attributes = $this->getRawAttributes();
953
-        $cachedAttributes = $this->getCachedRawAttributes(array_keys($attributes));
954
-
955
-        $dirty = [];
956
-
957
-        foreach ($attributes as $key => $value) {
958
-            if ($this->isRelation($key) || $key == 'pivot') {
959
-                continue;
960
-            }
961
-
962
-            if (!array_key_exists($key, $cachedAttributes) && !$value instanceof Pivot) {
963
-                $dirty[$key] = $value;
964
-            } elseif ($value !== $cachedAttributes[$key] &&
965
-                !$this->originalIsNumericallyEquivalent($value, $cachedAttributes[$key])) {
966
-                $dirty[$key] = $value;
967
-            }
968
-        }
969
-
970
-        return $dirty;
971
-    }
972
-
973
-    /**
974
-     * @param $key
975
-     * @return bool
976
-     */
977
-    protected function isRelation($key)
978
-    {
979
-        return in_array($key, $this->entityMap->getRelationships());
980
-    }
981
-
982
-    /**
983
-     * Determine if the new and old values for a given key are numerically equivalent.
984
-     *
985
-     * @param $current
986
-     * @param $original
987
-     * @return boolean
988
-     */
989
-    protected function originalIsNumericallyEquivalent($current, $original)
990
-    {
991
-        return is_numeric($current) && is_numeric($original) && strcmp((string) $current, (string) $original) === 0;
992
-    }
993
-
994
-    /**
995
-     * Get the underlying entity object
996
-     *
997
-     * @return mixed
998
-     */
999
-    public function getEntityObject()
1000
-    {
1001
-        return $this->wrappedEntity->getObject();
1002
-    }
1003
-
1004
-    /**
1005
-     * Return the Mapper instance for the current Entity Type
1006
-     *
1007
-     * @return \Analogue\ORM\System\Mapper
1008
-     */
1009
-    public function getMapper()
1010
-    {
1011
-        return Manager::getMapper($this->class);
1012
-    }
1013
-
1014
-    /**
1015
-     * Check that the entity already exists in the database, by checking
1016
-     * if it has an EntityCache record
1017
-     *
1018
-     * @return boolean
1019
-     */
1020
-    public function exists()
1021
-    {
1022
-        return $this->getCache()->has($this->getEntityId());
1023
-    }
1024
-
1025
-    /**
1026
-     * Set the object attribute raw values (hydration)
1027
-     *
1028
-     * @param array $attributes
1029
-     */
1030
-    public function setEntityAttributes(array $attributes)
1031
-    {
1032
-        $this->wrappedEntity->setEntityAttributes($attributes);
1033
-    }
1034
-
1035
-    /**
1036
-     * Get the raw object's values.
1037
-     *
1038
-     * @return array
1039
-     */
1040
-    public function getEntityAttributes()
1041
-    {
1042
-        return $this->wrappedEntity->getEntityAttributes();
1043
-    }
1044
-
1045
-    /**
1046
-     * Set the raw entity attributes
1047
-     * @param string $key
1048
-     * @param string $value
1049
-     */
1050
-    public function setEntityAttribute($key, $value)
1051
-    {
1052
-        $this->wrappedEntity->setEntityAttribute($key, $value);
1053
-    }
1054
-
1055
-    /**
1056
-     * Return the entity's attribute
1057
-     * @param  string $key
1058
-     * @return mixed
1059
-     */
1060
-    public function getEntityAttribute($key)
1061
-    {
1062
-        return $this->wrappedEntity->getEntityAttribute($key);
1063
-    }
1064
-
1065
-    /**
1066
-     * Does the attribute exists on the entity
1067
-     *
1068
-     * @param  string  $key
1069
-     * @return boolean
1070
-     */
1071
-    public function hasAttribute($key)
1072
-    {
1073
-        return $this->wrappedEntity->hasAttribute($key);
1074
-    }
1075
-
1076
-    /**
1077
-     * Set the lazyloading proxies on the wrapped entity
1078
-     */
1079
-    public function setProxies()
1080
-    {
1081
-        $this->wrappedEntity->setProxies();
1082
-    }
634
+		return $attributes;
635
+	}
636
+
637
+	/**
638
+	 * Return's entity raw attributes in the state they were at last
639
+	 * query.
640
+	 *
641
+	 * @param  array|null $columns
642
+	 * @return array
643
+	 */
644
+	protected function getCachedRawAttributes(array $columns = null)
645
+	{
646
+		$cachedAttributes = $this->getCache()->get($this->getEntityId());
647
+
648
+		if (is_null($columns)) {
649
+			return $cachedAttributes;
650
+		} else {
651
+			return array_only($cachedAttributes, $columns);
652
+		}
653
+	}
654
+
655
+	/**
656
+	 * Return a single attribute from the cache
657
+	 * @param  string $key
658
+	 * @return mixed
659
+	 */
660
+	protected function getCachedAttribute($key)
661
+	{
662
+		$cachedAttributes = $this->getCache()->get($this->getEntityId());
663
+
664
+		if (!array_key_exists($key, $cachedAttributes)) {
665
+			return null;
666
+		} else {
667
+			return $cachedAttributes[$key];
668
+		}
669
+	}
670
+
671
+	/**
672
+	 * Convert related Entity's attributes to foreign keys
673
+	 *
674
+	 * @return array
675
+	 */
676
+	protected function getForeignKeyAttributes()
677
+	{
678
+		$foreignKeys = [];
679
+
680
+		foreach ($this->entityMap->getLocalRelationships() as $relation) {
681
+			// check if relationship has been parsed, meaning it has an actual object
682
+			// in the entity's attributes
683
+			if ($this->isActualRelationships($relation)) {
684
+				$foreignKeys = $foreignKeys + $this->getForeignKeyAttributesFromRelation($relation);
685
+			}
686
+		}
687
+
688
+		if ( ! is_null($this->parent)) {
689
+			$foreignKeys = $foreignKeys + $this->getForeignKeyAttributesFromParent();
690
+		}
691
+
692
+		return $foreignKeys;
693
+	}
694
+
695
+	/**
696
+	 * Return an associative array containing the key-value pair(s) from
697
+	 * the related entity.
698
+	 *
699
+	 * @param  string $relation
700
+	 * @return array
701
+	 */
702
+	protected function getForeignKeyAttributesFromRelation($relation)
703
+	{
704
+		$localRelations = $this->entityMap->getLocalRelationships();
705
+
706
+		if (in_array($relation, $localRelations)) {
707
+			// Call Relationship's method
708
+			$relationship = $this->entityMap->$relation($this->getEntityObject());
709
+
710
+			$relatedAggregate = $this->relationships[$relation][0];
711
+
712
+			return $relationship->getForeignKeyValuePair($relatedAggregate->getEntityObject());
713
+		} else {
714
+			return [];
715
+		}
716
+	}
717
+
718
+	/**
719
+	 * Get foreign key attribute(s) from a parent entity in this
720
+	 * aggregate context
721
+	 *
722
+	 * @return array
723
+	 */
724
+	protected function getForeignKeyAttributesFromParent()
725
+	{
726
+		$parentMap = $this->parent->getEntityMap();
727
+
728
+		$parentForeignRelations = $parentMap->getForeignRelationships();
729
+		$parentPivotRelations = $parentMap->getPivotRelationships();
730
+
731
+		// The parentRelation is the name of the relationship
732
+		// methods on the parent entity map
733
+		$parentRelation = $this->parentRelationship;
734
+
735
+		if (in_array($parentRelation, $parentForeignRelations)
736
+			&& !in_array($parentRelation, $parentPivotRelations)
737
+		) {
738
+			$parentObject = $this->parent->getEntityObject();
739
+
740
+			// Call Relationship's method on parent map
741
+			$relationship = $parentMap->$parentRelation($parentObject);
742
+
743
+			return $relationship->getForeignKeyValuePair();
744
+		} else {
745
+			return [];
746
+		}
747
+	}
748
+
749
+	/**
750
+	 * Update Pivot records on loaded relationships, by comparing the
751
+	 * values from the Entity Cache to the actual relationship inside
752
+	 * the aggregated entity.
753
+	 *
754
+	 * @return void
755
+	 */
756
+	public function updatePivotRecords()
757
+	{
758
+		$pivots = $this->entityMap->getPivotRelationships();
759
+
760
+		foreach ($pivots as $pivot) {
761
+			if (array_key_exists($pivot, $this->relationships)) {
762
+				$this->updatePivotRelation($pivot);
763
+			}
764
+		}
765
+	}
766
+
767
+	/**
768
+	 * Update Single pivot relationship
769
+	 *
770
+	 * @param  string $relation
771
+	 * @return void
772
+	 */
773
+	protected function updatePivotRelation($relation)
774
+	{
775
+		$hashes = $this->getEntityHashesFromRelation($relation);
776
+
777
+		$cachedAttributes = $this->getCachedRawAttributes();
778
+
779
+		if (array_key_exists($relation, $cachedAttributes)) {
780
+			// Compare the two array of hashes to find out existing
781
+			// pivot records, and the ones to be created.
782
+			$new = array_diff($hashes, array_keys($cachedAttributes[$relation]));
783
+			$existing = array_intersect($hashes, array_keys($cachedAttributes[$relation]));
784
+		} else {
785
+			$existing = [];
786
+			$new = $hashes;
787
+		}
788
+
789
+		if (count($new) > 0) {
790
+			$pivots = $this->getRelatedAggregatesFromHashes($new, $relation);
791
+
792
+			$this->entityMap->$relation($this->getEntityObject())->createPivots($pivots);
793
+		}
794
+
795
+		if (count($existing) > 0) {
796
+			foreach ($existing as $pivotHash) {
797
+				$this->updatePivotIfDirty($pivotHash, $relation);
798
+			}
799
+		}
800
+	}
801
+
802
+	/**
803
+	 * Compare existing pivot record in cache and update it
804
+	 * if the pivot attributes are dirty
805
+	 *
806
+	 * @param  string $pivotHash
807
+	 * @param  string $relation
808
+	 * @return void
809
+	 */
810
+	protected function updatePivotIfDirty($pivotHash, $relation)
811
+	{
812
+		$aggregate = $this->getRelatedAggregateFromHash($pivotHash, $relation);
813
+
814
+		if ($aggregate->hasAttribute('pivot')) {
815
+			$pivot = $aggregate->getEntityAttribute('pivot')->getEntityAttributes();
816
+
817
+			$cachedPivotAttributes = $this->getPivotAttributesFromCache($pivotHash, $relation);
818
+
819
+			$actualPivotAttributes = array_only($pivot, array_keys($cachedPivotAttributes));
820
+
821
+			$dirty = $this->getDirtyAttributes($actualPivotAttributes, $cachedPivotAttributes);
822
+
823
+			if (count($dirty) > 0) {
824
+				$id = $aggregate->getEntityId();
825
+
826
+				$this->entityMap->$relation($this->getEntityObject())->updateExistingPivot($id, $dirty);
827
+			}
828
+		}
829
+	}
830
+
831
+	/**
832
+	 * Compare two attributes array and return dirty attributes
833
+	 *
834
+	 * @param  array $actual
835
+	 * @param  array $cached
836
+	 * @return array
837
+	 */
838
+	protected function getDirtyAttributes(array $actual, array $cached)
839
+	{
840
+		$dirty = [];
841
+
842
+		foreach ($actual as $key => $value) {
843
+			if (!$this->originalIsNumericallyEquivalent($value, $cached[$key])) {
844
+				$dirty[$key] = $actual[$key];
845
+			}
846
+		}
847
+
848
+		return $dirty;
849
+	}
850
+
851
+	/**
852
+	 *
853
+	 * @param  string $pivotHash
854
+	 * @param  string $relation
855
+	 * @return array
856
+	 */
857
+	protected function getPivotAttributesFromCache($pivotHash, $relation)
858
+	{
859
+		$cachedAttributes = $this->getCachedRawAttributes();
860
+
861
+		$cachedRelations = $cachedAttributes[$relation];
862
+
863
+		foreach ($cachedRelations as $cachedRelation) {
864
+			if ($cachedRelation == $pivotHash) {
865
+				return $cachedRelation->getPivotAttributes();
866
+			}
867
+		}
868
+	}
869
+
870
+	/**
871
+	 * Returns an array of related Aggregates from its entity hashes
872
+	 *
873
+	 * @param  array  $hashes
874
+	 * @param  string $relation
875
+	 * @return array
876
+	 */
877
+	protected function getRelatedAggregatesFromHashes(array $hashes, $relation)
878
+	{
879
+		$related = [];
880
+
881
+		foreach ($hashes as $hash) {
882
+			$aggregate = $this->getRelatedAggregateFromHash($hash, $relation);
883
+
884
+			if (!is_null($aggregate)) {
885
+				$related[] = $aggregate;
886
+			}
887
+		}
888
+
889
+		return $related;
890
+	}
891
+
892
+	/**
893
+	 * Get related aggregate from its hash
894
+	 *
895
+	 * @param  string $hash
896
+	 * @param  string $relation
897
+	 * @return \Analogue\ORM\System\Aggregate|null
898
+	 */
899
+	protected function getRelatedAggregateFromHash($hash, $relation)
900
+	{
901
+		foreach ($this->relationships[$relation] as $aggregate) {
902
+			if ($aggregate->getEntityHash() == $hash) {
903
+				return $aggregate;
904
+			}
905
+		}
906
+		return null;
907
+	}
908
+
909
+	/**
910
+	 * Return an array of Entity Hashes from a specific relation
911
+	 *
912
+	 * @param  string $relation
913
+	 * @return array
914
+	 */
915
+	protected function getEntityHashesFromRelation($relation)
916
+	{
917
+		return array_map(function ($aggregate) {
918
+			return $aggregate->getEntityHash();
919
+		}, $this->relationships[$relation]);
920
+	}
921
+
922
+	/**
923
+	 * Check the existence of an actual relationship
924
+	 *
925
+	 * @param  string $relation
926
+	 * @return boolean
927
+	 */
928
+	protected function isActualRelationships($relation)
929
+	{
930
+		return array_key_exists($relation, $this->relationships)
931
+			&& count($this->relationships[$relation]) > 0;
932
+	}
933
+
934
+	/**
935
+	 * Return cache instance for the current entity type
936
+	 *
937
+	 * @return \Analogue\ORM\System\EntityCache
938
+	 */
939
+	protected function getCache()
940
+	{
941
+		return $this->getMapper()->getEntityCache();
942
+	}
943
+
944
+	/**
945
+	 * Get Only Raw Entiy's attributes which have been modified
946
+	 * since last query
947
+	 *
948
+	 * @return array
949
+	 */
950
+	public function getDirtyRawAttributes()
951
+	{
952
+		$attributes = $this->getRawAttributes();
953
+		$cachedAttributes = $this->getCachedRawAttributes(array_keys($attributes));
954
+
955
+		$dirty = [];
956
+
957
+		foreach ($attributes as $key => $value) {
958
+			if ($this->isRelation($key) || $key == 'pivot') {
959
+				continue;
960
+			}
961
+
962
+			if (!array_key_exists($key, $cachedAttributes) && !$value instanceof Pivot) {
963
+				$dirty[$key] = $value;
964
+			} elseif ($value !== $cachedAttributes[$key] &&
965
+				!$this->originalIsNumericallyEquivalent($value, $cachedAttributes[$key])) {
966
+				$dirty[$key] = $value;
967
+			}
968
+		}
969
+
970
+		return $dirty;
971
+	}
972
+
973
+	/**
974
+	 * @param $key
975
+	 * @return bool
976
+	 */
977
+	protected function isRelation($key)
978
+	{
979
+		return in_array($key, $this->entityMap->getRelationships());
980
+	}
981
+
982
+	/**
983
+	 * Determine if the new and old values for a given key are numerically equivalent.
984
+	 *
985
+	 * @param $current
986
+	 * @param $original
987
+	 * @return boolean
988
+	 */
989
+	protected function originalIsNumericallyEquivalent($current, $original)
990
+	{
991
+		return is_numeric($current) && is_numeric($original) && strcmp((string) $current, (string) $original) === 0;
992
+	}
993
+
994
+	/**
995
+	 * Get the underlying entity object
996
+	 *
997
+	 * @return mixed
998
+	 */
999
+	public function getEntityObject()
1000
+	{
1001
+		return $this->wrappedEntity->getObject();
1002
+	}
1003
+
1004
+	/**
1005
+	 * Return the Mapper instance for the current Entity Type
1006
+	 *
1007
+	 * @return \Analogue\ORM\System\Mapper
1008
+	 */
1009
+	public function getMapper()
1010
+	{
1011
+		return Manager::getMapper($this->class);
1012
+	}
1013
+
1014
+	/**
1015
+	 * Check that the entity already exists in the database, by checking
1016
+	 * if it has an EntityCache record
1017
+	 *
1018
+	 * @return boolean
1019
+	 */
1020
+	public function exists()
1021
+	{
1022
+		return $this->getCache()->has($this->getEntityId());
1023
+	}
1024
+
1025
+	/**
1026
+	 * Set the object attribute raw values (hydration)
1027
+	 *
1028
+	 * @param array $attributes
1029
+	 */
1030
+	public function setEntityAttributes(array $attributes)
1031
+	{
1032
+		$this->wrappedEntity->setEntityAttributes($attributes);
1033
+	}
1034
+
1035
+	/**
1036
+	 * Get the raw object's values.
1037
+	 *
1038
+	 * @return array
1039
+	 */
1040
+	public function getEntityAttributes()
1041
+	{
1042
+		return $this->wrappedEntity->getEntityAttributes();
1043
+	}
1044
+
1045
+	/**
1046
+	 * Set the raw entity attributes
1047
+	 * @param string $key
1048
+	 * @param string $value
1049
+	 */
1050
+	public function setEntityAttribute($key, $value)
1051
+	{
1052
+		$this->wrappedEntity->setEntityAttribute($key, $value);
1053
+	}
1054
+
1055
+	/**
1056
+	 * Return the entity's attribute
1057
+	 * @param  string $key
1058
+	 * @return mixed
1059
+	 */
1060
+	public function getEntityAttribute($key)
1061
+	{
1062
+		return $this->wrappedEntity->getEntityAttribute($key);
1063
+	}
1064
+
1065
+	/**
1066
+	 * Does the attribute exists on the entity
1067
+	 *
1068
+	 * @param  string  $key
1069
+	 * @return boolean
1070
+	 */
1071
+	public function hasAttribute($key)
1072
+	{
1073
+		return $this->wrappedEntity->hasAttribute($key);
1074
+	}
1075
+
1076
+	/**
1077
+	 * Set the lazyloading proxies on the wrapped entity
1078
+	 */
1079
+	public function setProxies()
1080
+	{
1081
+		$this->wrappedEntity->setProxies();
1082
+	}
1083 1083
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -365,7 +365,7 @@  discard block
 block discarded – undo
365 365
      */
366 366
     public function getEntityHash()
367 367
     {
368
-        return $this->getEntityClass() . '.' . $this->getEntityId();
368
+        return $this->getEntityClass().'.'.$this->getEntityId();
369 369
     }
370 370
 
371 371
     /**
@@ -558,7 +558,7 @@  discard block
 block discarded – undo
558 558
             unset($attributes[$relation]);
559 559
         }
560 560
 
561
-        if($this->entityMap->getInheritanceType() == 'single_table') {
561
+        if ($this->entityMap->getInheritanceType() == 'single_table') {
562 562
             $attributes = $this->addDiscriminatorColumn($attributes);
563 563
         }
564 564
 
@@ -580,14 +580,14 @@  discard block
 block discarded – undo
580 580
         $discriminatorColumn = $this->entityMap->getDiscriminatorColumn();
581 581
         $entityClass = $this->entityMap->getClass();
582 582
 
583
-        if(! array_key_exists($discriminatorColumn, $attributes)) {
583
+        if (!array_key_exists($discriminatorColumn, $attributes)) {
584 584
             
585 585
             // Use key if present in discriminatorMap
586 586
             $map = $this->entityMap->getDiscriminatorColumnMap();
587 587
 
588 588
             $type = array_search($entityClass, $map);
589 589
 
590
-            if($type === false) {
590
+            if ($type === false) {
591 591
                 // Use entity FQDN if no corresponding key is set
592 592
                 $attributes[$discriminatorColumn] = $entityClass;
593 593
             }
@@ -624,7 +624,7 @@  discard block
 block discarded – undo
624 624
             $prefix = snake_case(class_basename($embed));
625 625
 
626 626
             foreach ($valueObjectAttributes as $key=>$value) {
627
-                $valueObjectAttributes[$prefix . '_' . $key] = $value;
627
+                $valueObjectAttributes[$prefix.'_'.$key] = $value;
628 628
                 unset($valueObjectAttributes[$key]);
629 629
             }
630 630
 
@@ -685,7 +685,7 @@  discard block
 block discarded – undo
685 685
             }
686 686
         }
687 687
 
688
-        if ( ! is_null($this->parent)) {
688
+        if (!is_null($this->parent)) {
689 689
             $foreignKeys = $foreignKeys + $this->getForeignKeyAttributesFromParent();
690 690
         }
691 691
 
@@ -914,7 +914,7 @@  discard block
 block discarded – undo
914 914
      */
915 915
     protected function getEntityHashesFromRelation($relation)
916 916
     {
917
-        return array_map(function ($aggregate) {
917
+        return array_map(function($aggregate) {
918 918
             return $aggregate->getEntityHash();
919 919
         }, $this->relationships[$relation]);
920 920
     }
Please login to merge, or discard this patch.
src/Relationships/BelongsTo.php 2 patches
Indentation   +294 added lines, -294 removed lines patch added patch discarded remove patch
@@ -10,299 +10,299 @@
 block discarded – undo
10 10
 
11 11
 class BelongsTo extends Relationship
12 12
 {
13
-    /**
14
-     * The foreign key of the parent model.
15
-     *
16
-     * @var string
17
-     */
18
-    protected $foreignKey;
19
-
20
-    /**
21
-     * The associated key on the parent model.
22
-     *
23
-     * @var string
24
-     */
25
-    protected $otherKey;
26
-
27
-    /**
28
-     * The name of the relationship.
29
-     *
30
-     * @var string
31
-     */
32
-    protected $relation;
33
-
34
-    /**
35
-     * Indicate if the parent entity hold the key for the relation.
36
-     *
37
-     * @var boolean
38
-     */
39
-    protected static $ownForeignKey = true;
40
-
41
-    /**
42
-     * Create a new belongs to relationship instance.
43
-     *
44
-     * @param Mapper   $mapper
45
-     * @param Mappable $parent
46
-     * @param string   $foreignKey
47
-     * @param string   $otherKey
48
-     * @param string   $relation
49
-     */
50
-    public function __construct(Mapper $mapper, $parent, $foreignKey, $otherKey, $relation)
51
-    {
52
-        $this->otherKey = $otherKey;
53
-        $this->relation = $relation;
54
-        $this->foreignKey = $foreignKey;
55
-
56
-        parent::__construct($mapper, $parent);
57
-    }
58
-
59
-    /**
60
-     * Get the results of the relationship.
61
-     *
62
-     * @param  $relation
63
-     *
64
-     * @return \Analogue\ORM\Entity
65
-     */
66
-    public function getResults($relation)
67
-    {
68
-        $result = $this->query->first();
69
-
70
-        $this->cacheRelation($result, $relation);
71
-
72
-        return $result;
73
-    }
74
-
75
-    /**
76
-     * Set the base constraints on the relation query.
77
-     *
78
-     * @return void
79
-     */
80
-    public function addConstraints()
81
-    {
82
-        if (static::$constraints) {
83
-            // For belongs to relationships, which are essentially the inverse of has one
84
-            // or has many relationships, we need to actually query on the primary key
85
-            // of the related models matching on the foreign key that's on a parent.
86
-            $this->query->where($this->otherKey, '=', $this->parent->getEntityAttribute($this->foreignKey));
87
-        }
88
-    }
89
-
90
-    /**
91
-     * Add the constraints for a relationship count query.
92
-     *
93
-     * @param  Query $query
94
-     * @param  Query $parent
95
-     * @return Query
96
-     */
97
-    public function getRelationCountQuery(Query $query, Query $parent)
98
-    {
99
-        $query->select(new Expression('count(*)'));
100
-
101
-        $otherKey = $this->wrap($query->getTable() . '.' . $this->otherKey);
102
-
103
-        return $query->where($this->getQualifiedForeignKey(), '=', new Expression($otherKey));
104
-    }
105
-
106
-    /**
107
-     * Set the constraints for an eager load of the relation.
108
-     *
109
-     * @param  array $entities
110
-     * @return void
111
-     */
112
-    public function addEagerConstraints(array $entities)
113
-    {
114
-        // We'll grab the primary key name of the related models since it could be set to
115
-        // a non-standard name and not "id". We will then construct the constraint for
116
-        // our eagerly loading query so it returns the proper models from execution.
117
-        $key = $this->otherKey;
118
-
119
-        $this->query->whereIn($key, $this->getEagerModelKeys($entities));
120
-    }
121
-
122
-    /**
123
-     * Gather the keys from an array of related models.
124
-     *
125
-     * @param  array $entities
126
-     * @return array
127
-     */
128
-    protected function getEagerModelKeys(array $entities)
129
-    {
130
-        $keys = [];
131
-
132
-        // First we need to gather all of the keys from the parent models so we know what
133
-        // to query for via the eager loading query. We will add them to an array then
134
-        // execute a "where in" statement to gather up all of those related records.
135
-        foreach ($entities as $entity) {
136
-            $entity = $this->factory->make($entity);
137
-
138
-            if (!is_null($value = $entity->getEntityAttribute($this->foreignKey))) {
139
-                $keys[] = $value;
140
-            }
141
-        }
142
-
143
-        // If there are no keys that were not null we will just return an array with 0 in
144
-        // it so the query doesn't fail, but will not return any results, which should
145
-        // be what this developer is expecting in a case where this happens to them.
146
-        if (count($keys) == 0) {
147
-            return [0];
148
-        }
149
-
150
-        return array_values(array_unique($keys));
151
-    }
152
-
153
-    /**
154
-     * Initialize the relation on a set of models.
155
-     *
156
-     * @param  array  $entities
157
-     * @param  string $relation
158
-     * @return array
159
-     */
160
-    public function initRelation(array $entities, $relation)
161
-    {
162
-        foreach ($entities as $entity) {
163
-            $entity = $this->factory->make($entity);
164
-            $entity->setEntityAttribute($relation, null);
165
-        }
166
-
167
-        return $entities;
168
-    }
169
-
170
-    /**
171
-     * Match the eagerly loaded results to their parents.
172
-     *
173
-     * @param  array            $entities
174
-     * @param  EntityCollection $results
175
-     * @param  string           $relation
176
-     * @return array
177
-     */
178
-    public function match(array $entities, EntityCollection $results, $relation)
179
-    {
180
-        $foreign = $this->foreignKey;
181
-
182
-        $other = $this->otherKey;
183
-
184
-        // First we will get to build a dictionary of the child models by their primary
185
-        // key of the relationship, then we can easily match the children back onto
186
-        // the parents using that dictionary and the primary key of the children.
187
-        $dictionary = [];
188
-
189
-        foreach ($results as $result) {
190
-            $result = $this->factory->make($result);
191
-            $dictionary[$result->getEntityAttribute($other)] = $result->getObject();
192
-        }
193
-
194
-        // Once we have the dictionary constructed, we can loop through all the parents
195
-        // and match back onto their children using these keys of the dictionary and
196
-        // the primary key of the children to map them onto the correct instances.
197
-        foreach ($entities as $entity) {
198
-            $entity = $this->factory->make($entity);
199
-
200
-            if (isset($dictionary[$entity->getEntityAttribute($foreign)])) {
201
-                $entity->setEntityAttribute($relation, $dictionary[$entity->getEntityAttribute($foreign)]);
202
-            }
203
-        }
204
-
205
-        return $entities;
206
-    }
207
-
208
-    public function sync(array $entities)
209
-    {
210
-        if (count($entities) > 1) {
211
-            throw new MappingException("Single Relationship shouldn't be synced with more than one entity");
212
-        }
13
+	/**
14
+	 * The foreign key of the parent model.
15
+	 *
16
+	 * @var string
17
+	 */
18
+	protected $foreignKey;
19
+
20
+	/**
21
+	 * The associated key on the parent model.
22
+	 *
23
+	 * @var string
24
+	 */
25
+	protected $otherKey;
26
+
27
+	/**
28
+	 * The name of the relationship.
29
+	 *
30
+	 * @var string
31
+	 */
32
+	protected $relation;
33
+
34
+	/**
35
+	 * Indicate if the parent entity hold the key for the relation.
36
+	 *
37
+	 * @var boolean
38
+	 */
39
+	protected static $ownForeignKey = true;
40
+
41
+	/**
42
+	 * Create a new belongs to relationship instance.
43
+	 *
44
+	 * @param Mapper   $mapper
45
+	 * @param Mappable $parent
46
+	 * @param string   $foreignKey
47
+	 * @param string   $otherKey
48
+	 * @param string   $relation
49
+	 */
50
+	public function __construct(Mapper $mapper, $parent, $foreignKey, $otherKey, $relation)
51
+	{
52
+		$this->otherKey = $otherKey;
53
+		$this->relation = $relation;
54
+		$this->foreignKey = $foreignKey;
55
+
56
+		parent::__construct($mapper, $parent);
57
+	}
58
+
59
+	/**
60
+	 * Get the results of the relationship.
61
+	 *
62
+	 * @param  $relation
63
+	 *
64
+	 * @return \Analogue\ORM\Entity
65
+	 */
66
+	public function getResults($relation)
67
+	{
68
+		$result = $this->query->first();
69
+
70
+		$this->cacheRelation($result, $relation);
71
+
72
+		return $result;
73
+	}
74
+
75
+	/**
76
+	 * Set the base constraints on the relation query.
77
+	 *
78
+	 * @return void
79
+	 */
80
+	public function addConstraints()
81
+	{
82
+		if (static::$constraints) {
83
+			// For belongs to relationships, which are essentially the inverse of has one
84
+			// or has many relationships, we need to actually query on the primary key
85
+			// of the related models matching on the foreign key that's on a parent.
86
+			$this->query->where($this->otherKey, '=', $this->parent->getEntityAttribute($this->foreignKey));
87
+		}
88
+	}
89
+
90
+	/**
91
+	 * Add the constraints for a relationship count query.
92
+	 *
93
+	 * @param  Query $query
94
+	 * @param  Query $parent
95
+	 * @return Query
96
+	 */
97
+	public function getRelationCountQuery(Query $query, Query $parent)
98
+	{
99
+		$query->select(new Expression('count(*)'));
100
+
101
+		$otherKey = $this->wrap($query->getTable() . '.' . $this->otherKey);
102
+
103
+		return $query->where($this->getQualifiedForeignKey(), '=', new Expression($otherKey));
104
+	}
105
+
106
+	/**
107
+	 * Set the constraints for an eager load of the relation.
108
+	 *
109
+	 * @param  array $entities
110
+	 * @return void
111
+	 */
112
+	public function addEagerConstraints(array $entities)
113
+	{
114
+		// We'll grab the primary key name of the related models since it could be set to
115
+		// a non-standard name and not "id". We will then construct the constraint for
116
+		// our eagerly loading query so it returns the proper models from execution.
117
+		$key = $this->otherKey;
118
+
119
+		$this->query->whereIn($key, $this->getEagerModelKeys($entities));
120
+	}
121
+
122
+	/**
123
+	 * Gather the keys from an array of related models.
124
+	 *
125
+	 * @param  array $entities
126
+	 * @return array
127
+	 */
128
+	protected function getEagerModelKeys(array $entities)
129
+	{
130
+		$keys = [];
131
+
132
+		// First we need to gather all of the keys from the parent models so we know what
133
+		// to query for via the eager loading query. We will add them to an array then
134
+		// execute a "where in" statement to gather up all of those related records.
135
+		foreach ($entities as $entity) {
136
+			$entity = $this->factory->make($entity);
137
+
138
+			if (!is_null($value = $entity->getEntityAttribute($this->foreignKey))) {
139
+				$keys[] = $value;
140
+			}
141
+		}
142
+
143
+		// If there are no keys that were not null we will just return an array with 0 in
144
+		// it so the query doesn't fail, but will not return any results, which should
145
+		// be what this developer is expecting in a case where this happens to them.
146
+		if (count($keys) == 0) {
147
+			return [0];
148
+		}
149
+
150
+		return array_values(array_unique($keys));
151
+	}
152
+
153
+	/**
154
+	 * Initialize the relation on a set of models.
155
+	 *
156
+	 * @param  array  $entities
157
+	 * @param  string $relation
158
+	 * @return array
159
+	 */
160
+	public function initRelation(array $entities, $relation)
161
+	{
162
+		foreach ($entities as $entity) {
163
+			$entity = $this->factory->make($entity);
164
+			$entity->setEntityAttribute($relation, null);
165
+		}
166
+
167
+		return $entities;
168
+	}
169
+
170
+	/**
171
+	 * Match the eagerly loaded results to their parents.
172
+	 *
173
+	 * @param  array            $entities
174
+	 * @param  EntityCollection $results
175
+	 * @param  string           $relation
176
+	 * @return array
177
+	 */
178
+	public function match(array $entities, EntityCollection $results, $relation)
179
+	{
180
+		$foreign = $this->foreignKey;
181
+
182
+		$other = $this->otherKey;
183
+
184
+		// First we will get to build a dictionary of the child models by their primary
185
+		// key of the relationship, then we can easily match the children back onto
186
+		// the parents using that dictionary and the primary key of the children.
187
+		$dictionary = [];
188
+
189
+		foreach ($results as $result) {
190
+			$result = $this->factory->make($result);
191
+			$dictionary[$result->getEntityAttribute($other)] = $result->getObject();
192
+		}
193
+
194
+		// Once we have the dictionary constructed, we can loop through all the parents
195
+		// and match back onto their children using these keys of the dictionary and
196
+		// the primary key of the children to map them onto the correct instances.
197
+		foreach ($entities as $entity) {
198
+			$entity = $this->factory->make($entity);
199
+
200
+			if (isset($dictionary[$entity->getEntityAttribute($foreign)])) {
201
+				$entity->setEntityAttribute($relation, $dictionary[$entity->getEntityAttribute($foreign)]);
202
+			}
203
+		}
204
+
205
+		return $entities;
206
+	}
207
+
208
+	public function sync(array $entities)
209
+	{
210
+		if (count($entities) > 1) {
211
+			throw new MappingException("Single Relationship shouldn't be synced with more than one entity");
212
+		}
213 213
         
214
-        if (count($entities) == 1) {
215
-            return $this->associate($entities[0]);
216
-        }
217
-
218
-        return false;
219
-    }
220
-
221
-    /**
222
-     * Associate the model instance to the given parent.
223
-     *
224
-     * @param  mixed $entity
225
-     * @return void
226
-     */
227
-    public function associate($entity)
228
-    {
229
-        $this->parent->setEntityAttribute($this->foreignKey, $entity->getEntityAttribute($this->otherKey));
230
-    }
231
-
232
-    /**
233
-     * Dissociate previously associated model from the given parent.
234
-     *
235
-     * @return Mappable
236
-     */
237
-    public function dissociate()
238
-    {
239
-        // The Mapper will retrieve this association within the object model, we won't be using
240
-        // the foreign key attribute inside the parent Entity.
241
-        //
242
-        //$this->parent->setEntityAttribute($this->foreignKey, null);
243
-
244
-        $this->parent->setEntityAttribute($this->relation, null);
245
-    }
246
-
247
-    /**
248
-     * Get the foreign key of the relationship.
249
-     *
250
-     * @return string
251
-     */
252
-    public function getForeignKey()
253
-    {
254
-        return $this->foreignKey;
255
-    }
256
-
257
-    /**
258
-     * Get the foreign key value pair for a related object
259
-     *
260
-     * @param  mixed $related
261
-     *
262
-     * @return array
263
-     */
264
-    public function getForeignKeyValuePair($related)
265
-    {
266
-        $foreignKey = $this->getForeignKey();
267
-
268
-        if ($related) {
269
-            $wrapper = $this->factory->make($related);
270
-
271
-            $relatedKey = $this->relatedMap->getKeyName();
272
-
273
-            return [$foreignKey => $wrapper->getEntityAttribute($relatedKey)];
274
-        } else {
275
-            return [$foreignKey => null];
276
-        }
277
-    }
278
-
279
-    /**
280
-     * Get the fully qualified foreign key of the relationship.
281
-     *
282
-     * @return string
283
-     */
284
-    public function getQualifiedForeignKey()
285
-    {
286
-        return $this->parentMap->getTable() . '.' . $this->foreignKey;
287
-    }
288
-
289
-    /**
290
-     * Get the associated key of the relationship.
291
-     *
292
-     * @return string
293
-     */
294
-    public function getOtherKey()
295
-    {
296
-        return $this->otherKey;
297
-    }
298
-
299
-    /**
300
-     * Get the fully qualified associated key of the relationship.
301
-     *
302
-     * @return string
303
-     */
304
-    public function getQualifiedOtherKeyName()
305
-    {
306
-        return $this->relatedMap->getTable() . '.' . $this->otherKey;
307
-    }
214
+		if (count($entities) == 1) {
215
+			return $this->associate($entities[0]);
216
+		}
217
+
218
+		return false;
219
+	}
220
+
221
+	/**
222
+	 * Associate the model instance to the given parent.
223
+	 *
224
+	 * @param  mixed $entity
225
+	 * @return void
226
+	 */
227
+	public function associate($entity)
228
+	{
229
+		$this->parent->setEntityAttribute($this->foreignKey, $entity->getEntityAttribute($this->otherKey));
230
+	}
231
+
232
+	/**
233
+	 * Dissociate previously associated model from the given parent.
234
+	 *
235
+	 * @return Mappable
236
+	 */
237
+	public function dissociate()
238
+	{
239
+		// The Mapper will retrieve this association within the object model, we won't be using
240
+		// the foreign key attribute inside the parent Entity.
241
+		//
242
+		//$this->parent->setEntityAttribute($this->foreignKey, null);
243
+
244
+		$this->parent->setEntityAttribute($this->relation, null);
245
+	}
246
+
247
+	/**
248
+	 * Get the foreign key of the relationship.
249
+	 *
250
+	 * @return string
251
+	 */
252
+	public function getForeignKey()
253
+	{
254
+		return $this->foreignKey;
255
+	}
256
+
257
+	/**
258
+	 * Get the foreign key value pair for a related object
259
+	 *
260
+	 * @param  mixed $related
261
+	 *
262
+	 * @return array
263
+	 */
264
+	public function getForeignKeyValuePair($related)
265
+	{
266
+		$foreignKey = $this->getForeignKey();
267
+
268
+		if ($related) {
269
+			$wrapper = $this->factory->make($related);
270
+
271
+			$relatedKey = $this->relatedMap->getKeyName();
272
+
273
+			return [$foreignKey => $wrapper->getEntityAttribute($relatedKey)];
274
+		} else {
275
+			return [$foreignKey => null];
276
+		}
277
+	}
278
+
279
+	/**
280
+	 * Get the fully qualified foreign key of the relationship.
281
+	 *
282
+	 * @return string
283
+	 */
284
+	public function getQualifiedForeignKey()
285
+	{
286
+		return $this->parentMap->getTable() . '.' . $this->foreignKey;
287
+	}
288
+
289
+	/**
290
+	 * Get the associated key of the relationship.
291
+	 *
292
+	 * @return string
293
+	 */
294
+	public function getOtherKey()
295
+	{
296
+		return $this->otherKey;
297
+	}
298
+
299
+	/**
300
+	 * Get the fully qualified associated key of the relationship.
301
+	 *
302
+	 * @return string
303
+	 */
304
+	public function getQualifiedOtherKeyName()
305
+	{
306
+		return $this->relatedMap->getTable() . '.' . $this->otherKey;
307
+	}
308 308
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
     {
99 99
         $query->select(new Expression('count(*)'));
100 100
 
101
-        $otherKey = $this->wrap($query->getTable() . '.' . $this->otherKey);
101
+        $otherKey = $this->wrap($query->getTable().'.'.$this->otherKey);
102 102
 
103 103
         return $query->where($this->getQualifiedForeignKey(), '=', new Expression($otherKey));
104 104
     }
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
      */
284 284
     public function getQualifiedForeignKey()
285 285
     {
286
-        return $this->parentMap->getTable() . '.' . $this->foreignKey;
286
+        return $this->parentMap->getTable().'.'.$this->foreignKey;
287 287
     }
288 288
 
289 289
     /**
@@ -303,6 +303,6 @@  discard block
 block discarded – undo
303 303
      */
304 304
     public function getQualifiedOtherKeyName()
305 305
     {
306
-        return $this->relatedMap->getTable() . '.' . $this->otherKey;
306
+        return $this->relatedMap->getTable().'.'.$this->otherKey;
307 307
     }
308 308
 }
Please login to merge, or discard this patch.
src/System/SingleTableInheritanceScope.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -32,7 +32,7 @@
 block discarded – undo
32 32
     /**
33 33
      * Remove the scope from the given Analogue query builder.
34 34
      *
35
-     * @param  mixed $query
35
+     * @param  Query $query
36 36
      * @return void
37 37
      */
38 38
     public function remove(Query $query)
Please login to merge, or discard this patch.
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -69,47 +69,47 @@
 block discarded – undo
69 69
 		return $type[0];
70 70
 	}
71 71
 
72
-    /**
73
-     * Apply the scope to a given Analogue query builder.
74
-     *
75
-     * @param  \Analogue\ORM\System\Query $query
76
-     * @return void
77
-     */
78
-    public function apply(Query $query)
79
-    {
80
-        $query->whereIn($this->column, $this->types);
81
-    }
82
-
83
-    /**
84
-     * Remove the scope from the given Analogue query builder.
85
-     *
86
-     * @param  mixed $query
87
-     * @return void
88
-     */
89
-    public function remove(Query $query)
90
-    {
91
-        $query = $query->getQuery();
92
-
93
-        foreach ((array) $query->wheres as $key => $where) {
72
+	/**
73
+	 * Apply the scope to a given Analogue query builder.
74
+	 *
75
+	 * @param  \Analogue\ORM\System\Query $query
76
+	 * @return void
77
+	 */
78
+	public function apply(Query $query)
79
+	{
80
+		$query->whereIn($this->column, $this->types);
81
+	}
82
+
83
+	/**
84
+	 * Remove the scope from the given Analogue query builder.
85
+	 *
86
+	 * @param  mixed $query
87
+	 * @return void
88
+	 */
89
+	public function remove(Query $query)
90
+	{
91
+		$query = $query->getQuery();
92
+
93
+		foreach ((array) $query->wheres as $key => $where) {
94 94
             
95
-            if ($this->isSingleTableConstraint($where, $this->column)) {
96
-                unset($query->wheres[$key]);
97
-
98
-                $query->wheres = array_values($query->wheres);
99
-            }
100
-        }
101
-    }
102
-
103
-    /**
104
-     * Determine if the given where clause is a single table inheritance constraint.
105
-     *
106
-     * @param  array  $where
107
-     * @param  string $column
108
-     * @return bool
109
-     */
110
-    protected function isSingleTableConstraint(array $where, $column)
111
-    {
112
-        return $where['column'] == $column;
113
-    }
95
+			if ($this->isSingleTableConstraint($where, $this->column)) {
96
+				unset($query->wheres[$key]);
97
+
98
+				$query->wheres = array_values($query->wheres);
99
+			}
100
+		}
101
+	}
102
+
103
+	/**
104
+	 * Determine if the given where clause is a single table inheritance constraint.
105
+	 *
106
+	 * @param  array  $where
107
+	 * @param  string $column
108
+	 * @return bool
109
+	 */
110
+	protected function isSingleTableConstraint(array $where, $column)
111
+	{
112
+		return $where['column'] == $column;
113
+	}
114 114
 
115 115
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -37,9 +37,9 @@  discard block
 block discarded – undo
37 37
 		// child class.
38 38
 		$classes = Manager::getInstance()->getRegisteredEntities();
39 39
 
40
-		foreach($classes as $otherClass => $entityMap) {
40
+		foreach ($classes as $otherClass => $entityMap) {
41 41
 
42
-			if(is_subclass_of($otherClass, $class)) {
42
+			if (is_subclass_of($otherClass, $class)) {
43 43
 				$this->types[] = $this->getTypeStringForEntity($otherClass, $entityMap);
44 44
 			}
45 45
 		}
@@ -62,7 +62,7 @@  discard block
 block discarded – undo
62 62
 			$class
63 63
 		);
64 64
 
65
-		if(count($type) == 0) {
65
+		if (count($type) == 0) {
66 66
 			return $class;
67 67
 		}
68 68
 
Please login to merge, or discard this patch.
src/System/MapperFactory.php 2 patches
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -13,76 +13,76 @@
 block discarded – undo
13 13
  */
14 14
 class MapperFactory
15 15
 {
16
-    /**
17
-     * Manager instance
18
-     *
19
-     * @var \Analogue\ORM\System\Manager
20
-     */
21
-    protected $manager;
16
+	/**
17
+	 * Manager instance
18
+	 *
19
+	 * @var \Analogue\ORM\System\Manager
20
+	 */
21
+	protected $manager;
22 22
 
23
-    /**
24
-     * DriverManager instance
25
-     *
26
-     * @var \Analogue\ORM\Drivers\Manager
27
-     */
28
-    protected $drivers;
23
+	/**
24
+	 * DriverManager instance
25
+	 *
26
+	 * @var \Analogue\ORM\Drivers\Manager
27
+	 */
28
+	protected $drivers;
29 29
 
30
-    /**
31
-     * Event dispatcher instance
32
-     *
33
-     * @var \Illuminate\Contracts\Events\Dispatcher
34
-     */
35
-    protected $dispatcher;
30
+	/**
31
+	 * Event dispatcher instance
32
+	 *
33
+	 * @var \Illuminate\Contracts\Events\Dispatcher
34
+	 */
35
+	protected $dispatcher;
36 36
 
37
-    /**
38
-     * MapperFactory constructor.
39
-     * @param DriverManager $drivers
40
-     * @param Dispatcher    $dispatcher
41
-     * @param Manager       $manager
42
-     */
43
-    public function __construct(DriverManager $drivers, Dispatcher $dispatcher, Manager $manager)
44
-    {
45
-        $this->drivers = $drivers;
37
+	/**
38
+	 * MapperFactory constructor.
39
+	 * @param DriverManager $drivers
40
+	 * @param Dispatcher    $dispatcher
41
+	 * @param Manager       $manager
42
+	 */
43
+	public function __construct(DriverManager $drivers, Dispatcher $dispatcher, Manager $manager)
44
+	{
45
+		$this->drivers = $drivers;
46 46
 
47
-        $this->dispatcher = $dispatcher;
47
+		$this->dispatcher = $dispatcher;
48 48
 
49
-        $this->manager = $manager;
50
-    }
49
+		$this->manager = $manager;
50
+	}
51 51
 
52
-    /**
53
-     * Return a new Mapper instance
54
-     *
55
-     * @param  string    $entityClass
56
-     * @param  EntityMap $entityMap
57
-     * @return Mapper
58
-     */
59
-    public function make($entityClass, EntityMap $entityMap)
60
-    {
61
-        $driver = $entityMap->getDriver();
52
+	/**
53
+	 * Return a new Mapper instance
54
+	 *
55
+	 * @param  string    $entityClass
56
+	 * @param  EntityMap $entityMap
57
+	 * @return Mapper
58
+	 */
59
+	public function make($entityClass, EntityMap $entityMap)
60
+	{
61
+		$driver = $entityMap->getDriver();
62 62
         
63
-        $connection = $entityMap->getConnection();
63
+		$connection = $entityMap->getConnection();
64 64
 
65
-        $adapter = $this->drivers->getAdapter($driver, $connection);
65
+		$adapter = $this->drivers->getAdapter($driver, $connection);
66 66
         
67
-        $entityMap->setDateFormat($adapter->getDateFormat());
67
+		$entityMap->setDateFormat($adapter->getDateFormat());
68 68
 
69
-        $mapper = new Mapper($entityMap, $adapter, $this->dispatcher, $this->manager);
69
+		$mapper = new Mapper($entityMap, $adapter, $this->dispatcher, $this->manager);
70 70
 
71
-        // Fire Initializing Event
72
-        $mapper->fireEvent('initializing', $mapper);
71
+		// Fire Initializing Event
72
+		$mapper->fireEvent('initializing', $mapper);
73 73
         
74
-        // Proceed necessary parsing on the EntityMap object
75
-        $entityMap->initialize();
74
+		// Proceed necessary parsing on the EntityMap object
75
+		$entityMap->initialize();
76 76
 
77
-        // Apply Inheritance scope, if necessary
78
-        if($entityMap->getInheritanceType() == 'single_table') {
79
-            $scope = new SingleTableInheritanceScope($entityMap);
80
-            $mapper->addGlobalScope($scope);
81
-        }
77
+		// Apply Inheritance scope, if necessary
78
+		if($entityMap->getInheritanceType() == 'single_table') {
79
+			$scope = new SingleTableInheritanceScope($entityMap);
80
+			$mapper->addGlobalScope($scope);
81
+		}
82 82
 
83
-        // Fire Initialized Event
84
-        $mapper->fireEvent('initialized', $mapper);
83
+		// Fire Initialized Event
84
+		$mapper->fireEvent('initialized', $mapper);
85 85
 
86
-        return $mapper;
87
-    }
86
+		return $mapper;
87
+	}
88 88
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -75,7 +75,7 @@
 block discarded – undo
75 75
         $entityMap->initialize();
76 76
 
77 77
         // Apply Inheritance scope, if necessary
78
-        if($entityMap->getInheritanceType() == 'single_table') {
78
+        if ($entityMap->getInheritanceType() == 'single_table') {
79 79
             $scope = new SingleTableInheritanceScope($entityMap);
80 80
             $mapper->addGlobalScope($scope);
81 81
         }
Please login to merge, or discard this patch.
src/AnalogueServiceProvider.php 2 patches
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -13,59 +13,59 @@
 block discarded – undo
13 13
  */
14 14
 class AnalogueServiceProvider extends ServiceProvider
15 15
 {
16
-    /**
17
-     * Indicates if loading of the provider is deferred.
18
-     *
19
-     * @var bool
20
-     */
21
-    protected $defer = false;
16
+	/**
17
+	 * Indicates if loading of the provider is deferred.
18
+	 *
19
+	 * @var bool
20
+	 */
21
+	protected $defer = false;
22 22
 
23
-    public function boot()
24
-    {
25
-        //   
26
-    }
23
+	public function boot()
24
+	{
25
+		//   
26
+	}
27 27
 
28
-    /**
29
-     * Register the service provider.
30
-     *
31
-     * @return void
32
-     */
33
-    public function register()
34
-    {
35
-        $this->app->singleton('analogue', function ($app) {
28
+	/**
29
+	 * Register the service provider.
30
+	 *
31
+	 * @return void
32
+	 */
33
+	public function register()
34
+	{
35
+		$this->app->singleton('analogue', function ($app) {
36 36
 
37
-            $db = $app['db'];
37
+			$db = $app['db'];
38 38
 
39
-            $connectionProvider = new IlluminateConnectionProvider($db);
39
+			$connectionProvider = new IlluminateConnectionProvider($db);
40 40
 
41
-            $illuminate = new IlluminateDriver($connectionProvider);
41
+			$illuminate = new IlluminateDriver($connectionProvider);
42 42
 
43
-            $driverManager = new DriverManager;
43
+			$driverManager = new DriverManager;
44 44
 
45
-            $driverManager->addDriver($illuminate);
45
+			$driverManager->addDriver($illuminate);
46 46
 
47
-            $event = $app->make('events');
47
+			$event = $app->make('events');
48 48
 
49
-            $manager = new Manager($driverManager, $event);
49
+			$manager = new Manager($driverManager, $event);
50 50
 
51
-            $manager->registerPlugin(\Analogue\ORM\Plugins\Timestamps\TimestampsPlugin::class);
52
-            $manager->registerPlugin(\Analogue\ORM\Plugins\SoftDeletes\SoftDeletesPlugin::class);
51
+			$manager->registerPlugin(\Analogue\ORM\Plugins\Timestamps\TimestampsPlugin::class);
52
+			$manager->registerPlugin(\Analogue\ORM\Plugins\SoftDeletes\SoftDeletesPlugin::class);
53 53
 
54
-            return $manager;
55
-        });
54
+			return $manager;
55
+		});
56 56
 
57
-        $this->app->bind(Manager::class, function ($app) {
58
-            return $app->make('analogue');
59
-        }); 
60
-    }
57
+		$this->app->bind(Manager::class, function ($app) {
58
+			return $app->make('analogue');
59
+		}); 
60
+	}
61 61
     
62
-    /**
63
-     * Get the services provided by the provider.
64
-     *
65
-     * @return array
66
-     */
67
-    public function provides()
68
-    {
69
-        return ['analogue'];
70
-    }
62
+	/**
63
+	 * Get the services provided by the provider.
64
+	 *
65
+	 * @return array
66
+	 */
67
+	public function provides()
68
+	{
69
+		return ['analogue'];
70
+	}
71 71
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -32,7 +32,7 @@  discard block
 block discarded – undo
32 32
      */
33 33
     public function register()
34 34
     {
35
-        $this->app->singleton('analogue', function ($app) {
35
+        $this->app->singleton('analogue', function($app) {
36 36
 
37 37
             $db = $app['db'];
38 38
 
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
             return $manager;
55 55
         });
56 56
 
57
-        $this->app->bind(Manager::class, function ($app) {
57
+        $this->app->bind(Manager::class, function($app) {
58 58
             return $app->make('analogue');
59 59
         }); 
60 60
     }
Please login to merge, or discard this patch.
src/EntityMap.php 3 patches
Doc Comments   +1 added lines, -3 removed lines patch added patch discarded remove patch
@@ -808,7 +808,6 @@  discard block
 block discarded – undo
808 808
      * @param  string      $related
809 809
      * @param  string|null $foreignKey
810 810
      * @param  string|null $otherKey
811
-     * @param  string|null $relation
812 811
      * @throws MappingException
813 812
      * @return \Analogue\ORM\Relationships\BelongsTo
814 813
      */
@@ -1004,11 +1003,10 @@  discard block
 block discarded – undo
1004 1003
      * Define a many-to-many relationship.
1005 1004
      *
1006 1005
      * @param  mixed       $entity
1007
-     * @param  string      $relatedClass
1006
+     * @param  string      $related
1008 1007
      * @param  string|null $table
1009 1008
      * @param  string|null $foreignKey
1010 1009
      * @param  string|null $otherKey
1011
-     * @param  string|null $relation
1012 1010
      * @throws MappingException
1013 1011
      * @return \Analogue\ORM\Relationships\BelongsToMany
1014 1012
      */
Please login to merge, or discard this patch.
Indentation   +1279 added lines, -1279 removed lines patch added patch discarded remove patch
@@ -23,1286 +23,1286 @@
 block discarded – undo
23 23
  */
24 24
 class EntityMap
25 25
 {
26
-    /**
27
-     * The mapping driver to use with this entity
28
-     *
29
-     * @var  string
30
-     */
31
-    protected $driver = 'illuminate';
32
-
33
-    /**
34
-     * The Database Connection name for the model.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $connection;
39
-
40
-    /**
41
-     * The table associated with the entity.
42
-     *
43
-     * @var string|null
44
-     */
45
-    protected $table = null;
46
-
47
-    /**
48
-     * The primary key for the model.
49
-     *
50
-     * @var string
51
-     */
52
-    protected $primaryKey = 'id';
53
-
54
-    /**
55
-     * Name of the entity's array property that should
56
-     * contain the attributes
57
-     * 
58
-     * @var string
59
-     */
60
-    protected $arrayName = 'attributes';
61
-
62
-    /**
63
-     * Array containing the list of database columns to be mapped
64
-     * in the attributes array of the entity. 
65
-     *
66
-     * @var array
67
-     */
68
-    protected $attributes = [];
69
-
70
-    /**
71
-     * Array containing the list of database columns to be mapped
72
-     * to the entity's class properties. 
73
-     *
74
-     * @var array
75
-     */
76
-    protected $properties = [];
77
-
78
-    /**
79
-     * The Custom Domain Class to use with this mapping
80
-     *
81
-     * @var string|null
82
-     */
83
-    protected $class = null;
84
-
85
-    /**
86
-     * Embedded Value Objects
87
-     * 
88
-     * @var array
89
-     */
90
-    protected $embeddables = [];
91
-
92
-    /**
93
-     * Determine the relationships method used on the entity.
94
-     * If not set, mapper will autodetect them
95
-     *
96
-     * @var array
97
-     */
98
-    private $relationships = [];
99
-
100
-    /**
101
-     * Relationships that should be treated as collection.
102
-     *
103
-     * @var array
104
-     */
105
-    private $manyRelations = [];
106
-
107
-    /**
108
-     * Relationships that should be treated as single entity.
109
-     *
110
-     * @var array
111
-     */
112
-    private $singleRelations = [];
113
-
114
-    /**
115
-     * Relationships for which the key is stored in the Entity itself
116
-     *
117
-     * @var array
118
-     */
119
-    private $localRelations = [];
120
-
121
-    /** 
122
-     * List of local keys associated to local relation methods
123
-     * 
124
-     * @var array
125
-     */
126
-    private $localForeignKeys = [];
127
-
128
-    /**
129
-     * Relationships for which the key is stored in the Related Entity
130
-     *
131
-     * @var array
132
-     */
133
-    private $foreignRelations = [];
134
-
135
-    /**
136
-     * Relationships which use a pivot record.
137
-     *
138
-     * @var array
139
-     */
140
-    private $pivotRelations = [];
141
-
142
-    /**
143
-     * Dynamic relationships
144
-     *
145
-     * @var array
146
-     */
147
-    private $dynamicRelationships = [];
148
-
149
-    /**
150
-     * Targetted class for the relationship method. value is set to `null` for
151
-     * polymorphic relations. 
152
-     * 
153
-     * @var array
154
-     */
155
-    private $relatedClasses = [];
156
-
157
-    /** 
158
-     * Some relation methods like embedded objects, or HasOne and MorphOne,
159
-     * will never have a proxy loaded on them. 
160
-     * 
161
-     * @var  array
162
-     */
163
-    private $nonProxyRelationships = [];
164
-
165
-    /**
166
-     * The number of models to return for pagination.
167
-     *
168
-     * @var int
169
-     */
170
-    protected $perPage = 15;
171
-
172
-    /**
173
-     * The relations to eager load on every query.
174
-     *
175
-     * @var array
176
-     */
177
-    protected $with = [];
178
-
179
-    /**
180
-     * The class name to be used in polymorphic relations.
181
-     *
182
-     * @var string
183
-     */
184
-    protected $morphClass;
185
-
186
-    /**
187
-     * Sequence name, to be used with postgreSql
188
-     * defaults to %table_name%_id_seq
189
-     *
190
-     * @var string|null
191
-     */
192
-    protected $sequence = null;
193
-
194
-    /**
195
-     * Indicates if the entity should be timestamped.
196
-     *
197
-     * @var bool
198
-     */
199
-    public $timestamps = false;
200
-
201
-    /**
202
-     * The name of the "created at" column.
203
-     *
204
-     * @var string
205
-     */
206
-    protected $createdAtColumn = 'created_at';
207
-
208
-    /**
209
-     * The name of the "updated at" column.
210
-     *
211
-     * @var string
212
-     */
213
-    protected $updatedAtColumn = 'updated_at';
214
-
215
-    /**
216
-     * Indicates if the entity uses softdeletes
217
-     *
218
-     * @var boolean
219
-     */
220
-    public $softDeletes = false;
221
-
222
-    /**
223
-     * The name of the "deleted at" column.
224
-     *
225
-     * @var string
226
-     */
227
-    protected $deletedAtColumn = 'deleted_at';
228
-
229
-    /**
230
-     * The date format to use with the current database connection
231
-     *
232
-     * @var string
233
-     */
234
-    protected $dateFormat;
235
-
236
-    /**
237
-     * Set this property to true if the entity should be instantiated
238
-     * using the IoC Container
239
-     * 
240
-     * @var boolean
241
-     */
242
-    protected $dependencyInjection = false;
243
-
244
-    /**
245
-     * Set the usage of inheritance, possible values are :
246
-     * "single_table"
247
-     * null
248
-     * 
249
-     * @var string | null
250
-     */
251
-    protected $inheritanceType = null;
252
-
253
-    /**
254
-     * Discriminator column name
255
-     * 
256
-     * @var string
257
-     */
258
-    protected $discriminatorColumn = "type";
259
-
260
-    /**
261
-     * Allow using a string to define which entity type should be instantiated.
262
-     * If not set, analogue will uses entity's FQDN
263
-     * 
264
-     * @var array
265
-     */
266
-    protected $discriminatorColumnMap = [];
267
-
268
-    /**
269
-     * Return Domain class attributes, useful when mapping to a Plain PHP Object
270
-     *
271
-     * @return array
272
-     */
273
-    public function getAttributes()
274
-    {
275
-        return $this->attributes;
276
-    }
277
-
278
-    /**
279
-     * Set the domain class attributes
280
-     *
281
-     * @param array $attributeNames
282
-     */
283
-    public function setAttributes(array $attributeNames)
284
-    {
285
-        $this->attributes = $attributeNames;
286
-    }
287
-
288
-    /**
289
-     * Get all the attribute names for the class, including relationships, embeddables and primary key.
290
-     *
291
-     * @return array
292
-     */
293
-    public function getCompiledAttributes()
294
-    {
295
-        $key = $this->getKeyName();
296
-
297
-        $embeddables = array_keys($this->getEmbeddables());
298
-
299
-        $relationships = $this->getRelationships();
300
-
301
-        $attributes = $this->getAttributes();
302
-
303
-        return array_merge([$key], $embeddables, $relationships, $attributes);
304
-    }
305
-
306
-    /**
307
-     * Set the date format to use with the current database connection
308
-     *
309
-     * @param string $format
310
-     */
311
-    public function setDateFormat($format)
312
-    {
313
-        $this->dateFormat = $format;
314
-    }
315
-
316
-    /**
317
-     * Get the date format to use with the current database connection
318
-     *
319
-     *  @return string
320
-     */
321
-    public function getDateFormat()
322
-    {
323
-        return $this->dateFormat;
324
-    }
325
-
326
-    /**
327
-     * Set the Driver for this mapping
328
-     *
329
-     * @param string $driver
330
-     */
331
-    public function setDriver($driver)
332
-    {
333
-        $this->driver = $driver;
334
-    }
335
-
336
-    /**
337
-     * Get the Driver for this mapping.
338
-     *
339
-     * @return string
340
-     */
341
-    public function getDriver()
342
-    {
343
-        return $this->driver;
344
-    }
345
-
346
-    /**
347
-     * Set the db connection to use on the table
348
-     *
349
-     * @param $connection
350
-     */
351
-    public function setConnection($connection)
352
-    {
353
-        $this->connection = $connection;
354
-    }
355
-
356
-    /**
357
-     * Get the Database connection the Entity is stored on.
358
-     *
359
-     * @return string
360
-     */
361
-    public function getConnection()
362
-    {
363
-        return $this->connection;
364
-    }
365
-
366
-    /**
367
-     * Get the table associated with the entity.
368
-     *
369
-     * @return string
370
-     */
371
-    public function getTable()
372
-    {
373
-        if (!is_null($this->table)) {
374
-            return $this->table;
375
-        }
376
-
377
-        return str_replace('\\', '', snake_case(str_plural(class_basename($this->getClass()))));
378
-    }
379
-
380
-    /**
381
-     * Set the database table name
382
-     *
383
-     * @param  string $table
384
-     */
385
-    public function setTable($table)
386
-    {
387
-        $this->table = $table;
388
-    }
389
-
390
-    /**
391
-     * Get the pgSql sequence name
392
-     *
393
-     * @return string
394
-     */
395
-    public function getSequence()
396
-    {
397
-        if (!is_null($this->sequence)) {
398
-            return $this->sequence;
399
-        } else {
400
-            return $this->getTable() . '_id_seq';
401
-        }
402
-    }
403
-
404
-    /**
405
-     * Get the custom entity class
406
-     *
407
-     * @return string namespaced class name
408
-     */
409
-    public function getClass()
410
-    {
411
-        return isset($this->class) ? $this->class : null;
412
-    }
413
-
414
-    /**
415
-     * Set the custom entity class
416
-     *
417
-     * @param string $class namespaced class name
418
-     */
419
-    public function setClass($class)
420
-    {
421
-        $this->class = $class;
422
-    }
423
-
424
-    /**
425
-     * Get the embedded Value Objects
426
-     *
427
-     * @return array
428
-     */
429
-    public function getEmbeddables()
430
-    {
431
-        return $this->embeddables;
432
-    }
433
-
434
-    /**
435
-     * Set the embedded Value Objects
436
-     *
437
-     * @param array $embeddables
438
-     */
439
-    public function setEmbeddables(array $embeddables)
440
-    {
441
-        $this->embeddables = $embeddables;
442
-    }
443
-
444
-    /**
445
-     * Get the relationships to map on a custom domain
446
-     * class.
447
-     *
448
-     * @return array
449
-     */
450
-    public function getRelationships()
451
-    {
452
-        return $this->relationships;
453
-    }
454
-
455
-    /**  
456
-     * Get the relationships that will not have a proxy
457
-     * set on them
458
-     * 
459
-     * @return array
460
-     */
461
-    public function getRelationshipsWithoutProxy()
462
-    {
463
-        return $this->nonProxyRelationships;
464
-    }
465
-
466
-    /**
467
-     * Relationships of the Entity type
468
-     *
469
-     * @return array
470
-     */
471
-    public function getSingleRelationships()
472
-    {
473
-        return $this->singleRelations;
474
-    }
475
-
476
-    /**
477
-     * Relationships of type Collection
478
-     *
479
-     * @return array
480
-     */
481
-    public function getManyRelationships()
482
-    {
483
-        return $this->manyRelations;
484
-    }
485
-
486
-    /**
487
-     * Relationships with foreign key in the mapped entity record.
488
-     *
489
-     * @return array
490
-     */
491
-    public function getLocalRelationships()
492
-    {
493
-        return $this->localRelations;
494
-    }
495
-
496
-    /**  
497
-     * Return the local keys associated to the relationship
498
-     * 
499
-     * @param  string $relation
500
-     * @return string | array | null
501
-     */
502
-    public function getLocalKeys($relation)
503
-    {
504
-        return isset($this->localForeignKeys[$relation]) ? $this->localForeignKeys[$relation] : null;
505
-    }
506
-
507
-    /**
508
-     * Relationships with foreign key in the related Entity record
509
-     *
510
-     * @return array
511
-     */
512
-    public function getForeignRelationships()
513
-    {
514
-        return $this->foreignRelations;
515
-    }
516
-
517
-    /**
518
-     * Relationships which keys are stored in a pivot record
519
-     *
520
-     * @return array
521
-     */
522
-    public function getPivotRelationships()
523
-    {
524
-        return $this->pivotRelations;
525
-    }
526
-
527
-    /**  
528
-     * Get the targetted type for a relationship. Return null if polymorphic
529
-     * 
530
-     * @param  string  $relation
531
-     * @return string | null
532
-     */
533
-    public function getTargettedClass($relation)
534
-    {
535
-        return $this->relatedClasses[$relation];
536
-    }
537
-
538
-    /**
539
-     * Add a Dynamic Relationship method at runtime. This has to be done
540
-     * by hooking the 'initializing' event, before entityMap is initialized.
541
-     *
542
-     * @param string  $name         Relation name
543
-     * @param \Closure $relationship
544
-     *
545
-     * @return void
546
-     */
547
-    public function addRelationshipMethod($name, \Closure $relationship)
548
-    {
549
-        $this->dynamicRelationships[$name] = $relationship;
550
-    }
551
-
552
-    /**
553
-     * Get the dynamic relationship method names.
554
-     *
555
-     * @return array
556
-     */
557
-    public function getDynamicRelationships()
558
-    {
559
-        return array_keys($this->dynamicRelationships);
560
-    }
561
-
562
-    /**
563
-     * Get the relationships that have to be eager loaded
564
-     * on each request.
565
-     *
566
-     * @return array
567
-     */
568
-    public function getEagerloadedRelationships()
569
-    {
570
-        return $this->with;
571
-    }
572
-
573
-    /**
574
-     * Get the primary key for the entity.
575
-     *
576
-     * @return string
577
-     */
578
-    public function getKeyName()
579
-    {
580
-        return $this->primaryKey;
581
-    }
582
-
583
-    /**
584
-     * Set the primary key for the entity.
585
-     *
586
-     * @param $key
587
-     * @return void
588
-     */
589
-    public function setKeyName($key)
590
-    {
591
-        $this->primaryKey = $key;
592
-    }
593
-
594
-    /**
595
-     * Get the table qualified key name.
596
-     *
597
-     * @return string
598
-     */
599
-    public function getQualifiedKeyName()
600
-    {
601
-        return $this->getTable() . '.' . $this->getKeyName();
602
-    }
603
-
604
-    /**
605
-     * Get the number of models to return per page.
606
-     *
607
-     * @return int
608
-     */
609
-    public function getPerPage()
610
-    {
611
-        return $this->perPage;
612
-    }
613
-
614
-    /**
615
-     * Set the number of models to return per page.
616
-     *
617
-     * @param  int $perPage
618
-     * @return void
619
-     */
620
-    public function setPerPage($perPage)
621
-    {
622
-        $this->perPage = $perPage;
623
-    }
624
-
625
-    /**
626
-     * Determine if the entity uses get.
627
-     *
628
-     * @return bool
629
-     */
630
-    public function usesTimestamps()
631
-    {
632
-        return $this->timestamps;
633
-    }
634
-
635
-    /**
636
-     * Determine if the entity uses soft deletes
637
-     *
638
-     * @return bool
639
-     */
640
-    public function usesSoftDeletes()
641
-    {
642
-        return $this->softDeletes;
643
-    }
644
-
645
-    /**
646
-     * Get the 'created_at' column name
647
-     *
648
-     * @return string
649
-     */
650
-    public function getCreatedAtColumn()
651
-    {
652
-        return $this->createdAtColumn;
653
-    }
654
-
655
-    /**
656
-     * Get the 'updated_at' column name
657
-     *
658
-     * @return string
659
-     */
660
-    public function getUpdatedAtColumn()
661
-    {
662
-        return $this->updatedAtColumn;
663
-    }
664
-
665
-    /**
666
-     * Get the deleted_at column
667
-     *
668
-     * @return string
669
-     */
670
-    public function getQualifiedDeletedAtColumn()
671
-    {
672
-        return $this->deletedAtColumn;
673
-    }
674
-
675
-    /**
676
-     * Get the default foreign key name for the model.
677
-     *
678
-     * @return string
679
-     */
680
-    public function getForeignKey()
681
-    {
682
-        return snake_case(class_basename($this->getClass())) . '_id';
683
-    }
684
-
685
-    /**
686
-     * Return the inheritance type used by the entity.
687
-     *
688
-     * @return string|null
689
-     */
690
-    public function getInheritanceType()
691
-    {
692
-        return $this->inheritanceType;
693
-    }
694
-
695
-    /**
696
-     * Return the discriminator column name on the entity that's
697
-     * used for table inheritance.
698
-     *
699
-     * @return string
700
-     */
701
-    public function getDiscriminatorColumn()
702
-    {
703
-        return $this->discriminatorColumn;
704
-    }
705
-
706
-    /**
707
-     * Return the mapping of discriminator column values to
708
-     * entity class names that are used for table inheritance.
709
-     *
710
-     * @return array
711
-     */
712
-    public function getDiscriminatorColumnMap()
713
-    {
714
-        return $this->discriminatorColumnMap;
715
-    }
716
-
717
-    /**
718
-     * Return true if the entity should be instanciated using
719
-     * the IoC Container
720
-     * 
721
-     * @return boolean
722
-     */
723
-    public function useDependencyInjection()
724
-    {
725
-        return $this->dependencyInjection;
726
-    }
727
-
728
-    /**
729
-     * Define a one-to-one relationship.
730
-     *
731
-     * @param  mixed  $entity
732
-     * @param  string $related entity class
733
-     * @param  string $foreignKey
734
-     * @param  string $localKey
735
-     * @throws MappingException
736
-     * @return \Analogue\ORM\Relationships\HasOne
737
-     */
738
-    public function hasOne($entity, $related, $foreignKey = null, $localKey = null)
739
-    {
740
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
741
-
742
-        $relatedMapper = Manager::getInstance()->mapper($related);
743
-
744
-        $relatedMap = $relatedMapper->getEntityMap();
745
-
746
-        $localKey = $localKey ?: $this->getKeyName();
747
-
748
-        // Add the relation to the definition in map
749
-        list(, $caller) = debug_backtrace(false);
750
-        $relation = $caller['function'];
751
-        $this->relatedClasses[$relation] = $related;
752
-        $this->singleRelations[] = $relation;
753
-        $this->foreignRelations[] = $relation;
754
-        $this->nonProxyRelationships[] = $relation;
755
-
756
-        // This relationship will always be eager loaded, as proxying it would
757
-        // mean having an object that doesn't actually exists.
758
-        if(! in_array($relation, $this->with)) {
759
-            $this->with[] = $relation;
760
-        }
761
-
762
-        return new HasOne($relatedMapper, $entity, $relatedMap->getTable() . '.' . $foreignKey, $localKey);
763
-    }
764
-
765
-    /**
766
-     * Define a polymorphic one-to-one relationship.
767
-     *
768
-     * @param  mixed       $entity
769
-     * @param  string      $related
770
-     * @param  string      $name
771
-     * @param  string|null $type
772
-     * @param  string|null $id
773
-     * @param  string|null $localKey
774
-     * @throws MappingException
775
-     * @return \Analogue\ORM\Relationships\MorphOne
776
-     */
777
-    public function morphOne($entity, $related, $name, $type = null, $id = null, $localKey = null)
778
-    {
779
-        list($type, $id) = $this->getMorphs($name, $type, $id);
780
-
781
-        $localKey = $localKey ?: $this->getKeyName();
782
-
783
-        $relatedMapper = Manager::getInstance()->mapper($related);
784
-
785
-        $table = $relatedMapper->getEntityMap()->getTable();
786
-
787
-        // Add the relation to the definition in map
788
-        list(, $caller) = debug_backtrace(false);
789
-        $relation = $caller['function'];
790
-        $this->relatedClasses[$relation] = $related;
791
-        $this->singleRelations[] = $relation;
792
-        $this->foreignRelations[] = $relation;
793
-        $this->nonProxyRelationships[] = $relation;
794
-
795
-        // This relationship will always be eager loaded, as proxying it would
796
-        // mean having an object that doesn't actually exists.
797
-        if(! in_array($relation, $this->with)) {
798
-            $this->with[] = $relation;
799
-        }
26
+	/**
27
+	 * The mapping driver to use with this entity
28
+	 *
29
+	 * @var  string
30
+	 */
31
+	protected $driver = 'illuminate';
32
+
33
+	/**
34
+	 * The Database Connection name for the model.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $connection;
39
+
40
+	/**
41
+	 * The table associated with the entity.
42
+	 *
43
+	 * @var string|null
44
+	 */
45
+	protected $table = null;
46
+
47
+	/**
48
+	 * The primary key for the model.
49
+	 *
50
+	 * @var string
51
+	 */
52
+	protected $primaryKey = 'id';
53
+
54
+	/**
55
+	 * Name of the entity's array property that should
56
+	 * contain the attributes
57
+	 * 
58
+	 * @var string
59
+	 */
60
+	protected $arrayName = 'attributes';
61
+
62
+	/**
63
+	 * Array containing the list of database columns to be mapped
64
+	 * in the attributes array of the entity. 
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $attributes = [];
69
+
70
+	/**
71
+	 * Array containing the list of database columns to be mapped
72
+	 * to the entity's class properties. 
73
+	 *
74
+	 * @var array
75
+	 */
76
+	protected $properties = [];
77
+
78
+	/**
79
+	 * The Custom Domain Class to use with this mapping
80
+	 *
81
+	 * @var string|null
82
+	 */
83
+	protected $class = null;
84
+
85
+	/**
86
+	 * Embedded Value Objects
87
+	 * 
88
+	 * @var array
89
+	 */
90
+	protected $embeddables = [];
91
+
92
+	/**
93
+	 * Determine the relationships method used on the entity.
94
+	 * If not set, mapper will autodetect them
95
+	 *
96
+	 * @var array
97
+	 */
98
+	private $relationships = [];
99
+
100
+	/**
101
+	 * Relationships that should be treated as collection.
102
+	 *
103
+	 * @var array
104
+	 */
105
+	private $manyRelations = [];
106
+
107
+	/**
108
+	 * Relationships that should be treated as single entity.
109
+	 *
110
+	 * @var array
111
+	 */
112
+	private $singleRelations = [];
113
+
114
+	/**
115
+	 * Relationships for which the key is stored in the Entity itself
116
+	 *
117
+	 * @var array
118
+	 */
119
+	private $localRelations = [];
120
+
121
+	/** 
122
+	 * List of local keys associated to local relation methods
123
+	 * 
124
+	 * @var array
125
+	 */
126
+	private $localForeignKeys = [];
127
+
128
+	/**
129
+	 * Relationships for which the key is stored in the Related Entity
130
+	 *
131
+	 * @var array
132
+	 */
133
+	private $foreignRelations = [];
134
+
135
+	/**
136
+	 * Relationships which use a pivot record.
137
+	 *
138
+	 * @var array
139
+	 */
140
+	private $pivotRelations = [];
141
+
142
+	/**
143
+	 * Dynamic relationships
144
+	 *
145
+	 * @var array
146
+	 */
147
+	private $dynamicRelationships = [];
148
+
149
+	/**
150
+	 * Targetted class for the relationship method. value is set to `null` for
151
+	 * polymorphic relations. 
152
+	 * 
153
+	 * @var array
154
+	 */
155
+	private $relatedClasses = [];
156
+
157
+	/** 
158
+	 * Some relation methods like embedded objects, or HasOne and MorphOne,
159
+	 * will never have a proxy loaded on them. 
160
+	 * 
161
+	 * @var  array
162
+	 */
163
+	private $nonProxyRelationships = [];
164
+
165
+	/**
166
+	 * The number of models to return for pagination.
167
+	 *
168
+	 * @var int
169
+	 */
170
+	protected $perPage = 15;
171
+
172
+	/**
173
+	 * The relations to eager load on every query.
174
+	 *
175
+	 * @var array
176
+	 */
177
+	protected $with = [];
178
+
179
+	/**
180
+	 * The class name to be used in polymorphic relations.
181
+	 *
182
+	 * @var string
183
+	 */
184
+	protected $morphClass;
185
+
186
+	/**
187
+	 * Sequence name, to be used with postgreSql
188
+	 * defaults to %table_name%_id_seq
189
+	 *
190
+	 * @var string|null
191
+	 */
192
+	protected $sequence = null;
193
+
194
+	/**
195
+	 * Indicates if the entity should be timestamped.
196
+	 *
197
+	 * @var bool
198
+	 */
199
+	public $timestamps = false;
200
+
201
+	/**
202
+	 * The name of the "created at" column.
203
+	 *
204
+	 * @var string
205
+	 */
206
+	protected $createdAtColumn = 'created_at';
207
+
208
+	/**
209
+	 * The name of the "updated at" column.
210
+	 *
211
+	 * @var string
212
+	 */
213
+	protected $updatedAtColumn = 'updated_at';
214
+
215
+	/**
216
+	 * Indicates if the entity uses softdeletes
217
+	 *
218
+	 * @var boolean
219
+	 */
220
+	public $softDeletes = false;
221
+
222
+	/**
223
+	 * The name of the "deleted at" column.
224
+	 *
225
+	 * @var string
226
+	 */
227
+	protected $deletedAtColumn = 'deleted_at';
228
+
229
+	/**
230
+	 * The date format to use with the current database connection
231
+	 *
232
+	 * @var string
233
+	 */
234
+	protected $dateFormat;
235
+
236
+	/**
237
+	 * Set this property to true if the entity should be instantiated
238
+	 * using the IoC Container
239
+	 * 
240
+	 * @var boolean
241
+	 */
242
+	protected $dependencyInjection = false;
243
+
244
+	/**
245
+	 * Set the usage of inheritance, possible values are :
246
+	 * "single_table"
247
+	 * null
248
+	 * 
249
+	 * @var string | null
250
+	 */
251
+	protected $inheritanceType = null;
252
+
253
+	/**
254
+	 * Discriminator column name
255
+	 * 
256
+	 * @var string
257
+	 */
258
+	protected $discriminatorColumn = "type";
259
+
260
+	/**
261
+	 * Allow using a string to define which entity type should be instantiated.
262
+	 * If not set, analogue will uses entity's FQDN
263
+	 * 
264
+	 * @var array
265
+	 */
266
+	protected $discriminatorColumnMap = [];
267
+
268
+	/**
269
+	 * Return Domain class attributes, useful when mapping to a Plain PHP Object
270
+	 *
271
+	 * @return array
272
+	 */
273
+	public function getAttributes()
274
+	{
275
+		return $this->attributes;
276
+	}
277
+
278
+	/**
279
+	 * Set the domain class attributes
280
+	 *
281
+	 * @param array $attributeNames
282
+	 */
283
+	public function setAttributes(array $attributeNames)
284
+	{
285
+		$this->attributes = $attributeNames;
286
+	}
287
+
288
+	/**
289
+	 * Get all the attribute names for the class, including relationships, embeddables and primary key.
290
+	 *
291
+	 * @return array
292
+	 */
293
+	public function getCompiledAttributes()
294
+	{
295
+		$key = $this->getKeyName();
296
+
297
+		$embeddables = array_keys($this->getEmbeddables());
298
+
299
+		$relationships = $this->getRelationships();
300
+
301
+		$attributes = $this->getAttributes();
302
+
303
+		return array_merge([$key], $embeddables, $relationships, $attributes);
304
+	}
305
+
306
+	/**
307
+	 * Set the date format to use with the current database connection
308
+	 *
309
+	 * @param string $format
310
+	 */
311
+	public function setDateFormat($format)
312
+	{
313
+		$this->dateFormat = $format;
314
+	}
315
+
316
+	/**
317
+	 * Get the date format to use with the current database connection
318
+	 *
319
+	 *  @return string
320
+	 */
321
+	public function getDateFormat()
322
+	{
323
+		return $this->dateFormat;
324
+	}
325
+
326
+	/**
327
+	 * Set the Driver for this mapping
328
+	 *
329
+	 * @param string $driver
330
+	 */
331
+	public function setDriver($driver)
332
+	{
333
+		$this->driver = $driver;
334
+	}
335
+
336
+	/**
337
+	 * Get the Driver for this mapping.
338
+	 *
339
+	 * @return string
340
+	 */
341
+	public function getDriver()
342
+	{
343
+		return $this->driver;
344
+	}
345
+
346
+	/**
347
+	 * Set the db connection to use on the table
348
+	 *
349
+	 * @param $connection
350
+	 */
351
+	public function setConnection($connection)
352
+	{
353
+		$this->connection = $connection;
354
+	}
355
+
356
+	/**
357
+	 * Get the Database connection the Entity is stored on.
358
+	 *
359
+	 * @return string
360
+	 */
361
+	public function getConnection()
362
+	{
363
+		return $this->connection;
364
+	}
365
+
366
+	/**
367
+	 * Get the table associated with the entity.
368
+	 *
369
+	 * @return string
370
+	 */
371
+	public function getTable()
372
+	{
373
+		if (!is_null($this->table)) {
374
+			return $this->table;
375
+		}
376
+
377
+		return str_replace('\\', '', snake_case(str_plural(class_basename($this->getClass()))));
378
+	}
379
+
380
+	/**
381
+	 * Set the database table name
382
+	 *
383
+	 * @param  string $table
384
+	 */
385
+	public function setTable($table)
386
+	{
387
+		$this->table = $table;
388
+	}
389
+
390
+	/**
391
+	 * Get the pgSql sequence name
392
+	 *
393
+	 * @return string
394
+	 */
395
+	public function getSequence()
396
+	{
397
+		if (!is_null($this->sequence)) {
398
+			return $this->sequence;
399
+		} else {
400
+			return $this->getTable() . '_id_seq';
401
+		}
402
+	}
403
+
404
+	/**
405
+	 * Get the custom entity class
406
+	 *
407
+	 * @return string namespaced class name
408
+	 */
409
+	public function getClass()
410
+	{
411
+		return isset($this->class) ? $this->class : null;
412
+	}
413
+
414
+	/**
415
+	 * Set the custom entity class
416
+	 *
417
+	 * @param string $class namespaced class name
418
+	 */
419
+	public function setClass($class)
420
+	{
421
+		$this->class = $class;
422
+	}
423
+
424
+	/**
425
+	 * Get the embedded Value Objects
426
+	 *
427
+	 * @return array
428
+	 */
429
+	public function getEmbeddables()
430
+	{
431
+		return $this->embeddables;
432
+	}
433
+
434
+	/**
435
+	 * Set the embedded Value Objects
436
+	 *
437
+	 * @param array $embeddables
438
+	 */
439
+	public function setEmbeddables(array $embeddables)
440
+	{
441
+		$this->embeddables = $embeddables;
442
+	}
443
+
444
+	/**
445
+	 * Get the relationships to map on a custom domain
446
+	 * class.
447
+	 *
448
+	 * @return array
449
+	 */
450
+	public function getRelationships()
451
+	{
452
+		return $this->relationships;
453
+	}
454
+
455
+	/**  
456
+	 * Get the relationships that will not have a proxy
457
+	 * set on them
458
+	 * 
459
+	 * @return array
460
+	 */
461
+	public function getRelationshipsWithoutProxy()
462
+	{
463
+		return $this->nonProxyRelationships;
464
+	}
465
+
466
+	/**
467
+	 * Relationships of the Entity type
468
+	 *
469
+	 * @return array
470
+	 */
471
+	public function getSingleRelationships()
472
+	{
473
+		return $this->singleRelations;
474
+	}
475
+
476
+	/**
477
+	 * Relationships of type Collection
478
+	 *
479
+	 * @return array
480
+	 */
481
+	public function getManyRelationships()
482
+	{
483
+		return $this->manyRelations;
484
+	}
485
+
486
+	/**
487
+	 * Relationships with foreign key in the mapped entity record.
488
+	 *
489
+	 * @return array
490
+	 */
491
+	public function getLocalRelationships()
492
+	{
493
+		return $this->localRelations;
494
+	}
495
+
496
+	/**  
497
+	 * Return the local keys associated to the relationship
498
+	 * 
499
+	 * @param  string $relation
500
+	 * @return string | array | null
501
+	 */
502
+	public function getLocalKeys($relation)
503
+	{
504
+		return isset($this->localForeignKeys[$relation]) ? $this->localForeignKeys[$relation] : null;
505
+	}
506
+
507
+	/**
508
+	 * Relationships with foreign key in the related Entity record
509
+	 *
510
+	 * @return array
511
+	 */
512
+	public function getForeignRelationships()
513
+	{
514
+		return $this->foreignRelations;
515
+	}
516
+
517
+	/**
518
+	 * Relationships which keys are stored in a pivot record
519
+	 *
520
+	 * @return array
521
+	 */
522
+	public function getPivotRelationships()
523
+	{
524
+		return $this->pivotRelations;
525
+	}
526
+
527
+	/**  
528
+	 * Get the targetted type for a relationship. Return null if polymorphic
529
+	 * 
530
+	 * @param  string  $relation
531
+	 * @return string | null
532
+	 */
533
+	public function getTargettedClass($relation)
534
+	{
535
+		return $this->relatedClasses[$relation];
536
+	}
537
+
538
+	/**
539
+	 * Add a Dynamic Relationship method at runtime. This has to be done
540
+	 * by hooking the 'initializing' event, before entityMap is initialized.
541
+	 *
542
+	 * @param string  $name         Relation name
543
+	 * @param \Closure $relationship
544
+	 *
545
+	 * @return void
546
+	 */
547
+	public function addRelationshipMethod($name, \Closure $relationship)
548
+	{
549
+		$this->dynamicRelationships[$name] = $relationship;
550
+	}
551
+
552
+	/**
553
+	 * Get the dynamic relationship method names.
554
+	 *
555
+	 * @return array
556
+	 */
557
+	public function getDynamicRelationships()
558
+	{
559
+		return array_keys($this->dynamicRelationships);
560
+	}
561
+
562
+	/**
563
+	 * Get the relationships that have to be eager loaded
564
+	 * on each request.
565
+	 *
566
+	 * @return array
567
+	 */
568
+	public function getEagerloadedRelationships()
569
+	{
570
+		return $this->with;
571
+	}
572
+
573
+	/**
574
+	 * Get the primary key for the entity.
575
+	 *
576
+	 * @return string
577
+	 */
578
+	public function getKeyName()
579
+	{
580
+		return $this->primaryKey;
581
+	}
582
+
583
+	/**
584
+	 * Set the primary key for the entity.
585
+	 *
586
+	 * @param $key
587
+	 * @return void
588
+	 */
589
+	public function setKeyName($key)
590
+	{
591
+		$this->primaryKey = $key;
592
+	}
593
+
594
+	/**
595
+	 * Get the table qualified key name.
596
+	 *
597
+	 * @return string
598
+	 */
599
+	public function getQualifiedKeyName()
600
+	{
601
+		return $this->getTable() . '.' . $this->getKeyName();
602
+	}
603
+
604
+	/**
605
+	 * Get the number of models to return per page.
606
+	 *
607
+	 * @return int
608
+	 */
609
+	public function getPerPage()
610
+	{
611
+		return $this->perPage;
612
+	}
613
+
614
+	/**
615
+	 * Set the number of models to return per page.
616
+	 *
617
+	 * @param  int $perPage
618
+	 * @return void
619
+	 */
620
+	public function setPerPage($perPage)
621
+	{
622
+		$this->perPage = $perPage;
623
+	}
624
+
625
+	/**
626
+	 * Determine if the entity uses get.
627
+	 *
628
+	 * @return bool
629
+	 */
630
+	public function usesTimestamps()
631
+	{
632
+		return $this->timestamps;
633
+	}
634
+
635
+	/**
636
+	 * Determine if the entity uses soft deletes
637
+	 *
638
+	 * @return bool
639
+	 */
640
+	public function usesSoftDeletes()
641
+	{
642
+		return $this->softDeletes;
643
+	}
644
+
645
+	/**
646
+	 * Get the 'created_at' column name
647
+	 *
648
+	 * @return string
649
+	 */
650
+	public function getCreatedAtColumn()
651
+	{
652
+		return $this->createdAtColumn;
653
+	}
654
+
655
+	/**
656
+	 * Get the 'updated_at' column name
657
+	 *
658
+	 * @return string
659
+	 */
660
+	public function getUpdatedAtColumn()
661
+	{
662
+		return $this->updatedAtColumn;
663
+	}
664
+
665
+	/**
666
+	 * Get the deleted_at column
667
+	 *
668
+	 * @return string
669
+	 */
670
+	public function getQualifiedDeletedAtColumn()
671
+	{
672
+		return $this->deletedAtColumn;
673
+	}
674
+
675
+	/**
676
+	 * Get the default foreign key name for the model.
677
+	 *
678
+	 * @return string
679
+	 */
680
+	public function getForeignKey()
681
+	{
682
+		return snake_case(class_basename($this->getClass())) . '_id';
683
+	}
684
+
685
+	/**
686
+	 * Return the inheritance type used by the entity.
687
+	 *
688
+	 * @return string|null
689
+	 */
690
+	public function getInheritanceType()
691
+	{
692
+		return $this->inheritanceType;
693
+	}
694
+
695
+	/**
696
+	 * Return the discriminator column name on the entity that's
697
+	 * used for table inheritance.
698
+	 *
699
+	 * @return string
700
+	 */
701
+	public function getDiscriminatorColumn()
702
+	{
703
+		return $this->discriminatorColumn;
704
+	}
705
+
706
+	/**
707
+	 * Return the mapping of discriminator column values to
708
+	 * entity class names that are used for table inheritance.
709
+	 *
710
+	 * @return array
711
+	 */
712
+	public function getDiscriminatorColumnMap()
713
+	{
714
+		return $this->discriminatorColumnMap;
715
+	}
716
+
717
+	/**
718
+	 * Return true if the entity should be instanciated using
719
+	 * the IoC Container
720
+	 * 
721
+	 * @return boolean
722
+	 */
723
+	public function useDependencyInjection()
724
+	{
725
+		return $this->dependencyInjection;
726
+	}
727
+
728
+	/**
729
+	 * Define a one-to-one relationship.
730
+	 *
731
+	 * @param  mixed  $entity
732
+	 * @param  string $related entity class
733
+	 * @param  string $foreignKey
734
+	 * @param  string $localKey
735
+	 * @throws MappingException
736
+	 * @return \Analogue\ORM\Relationships\HasOne
737
+	 */
738
+	public function hasOne($entity, $related, $foreignKey = null, $localKey = null)
739
+	{
740
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
741
+
742
+		$relatedMapper = Manager::getInstance()->mapper($related);
743
+
744
+		$relatedMap = $relatedMapper->getEntityMap();
745
+
746
+		$localKey = $localKey ?: $this->getKeyName();
747
+
748
+		// Add the relation to the definition in map
749
+		list(, $caller) = debug_backtrace(false);
750
+		$relation = $caller['function'];
751
+		$this->relatedClasses[$relation] = $related;
752
+		$this->singleRelations[] = $relation;
753
+		$this->foreignRelations[] = $relation;
754
+		$this->nonProxyRelationships[] = $relation;
755
+
756
+		// This relationship will always be eager loaded, as proxying it would
757
+		// mean having an object that doesn't actually exists.
758
+		if(! in_array($relation, $this->with)) {
759
+			$this->with[] = $relation;
760
+		}
761
+
762
+		return new HasOne($relatedMapper, $entity, $relatedMap->getTable() . '.' . $foreignKey, $localKey);
763
+	}
764
+
765
+	/**
766
+	 * Define a polymorphic one-to-one relationship.
767
+	 *
768
+	 * @param  mixed       $entity
769
+	 * @param  string      $related
770
+	 * @param  string      $name
771
+	 * @param  string|null $type
772
+	 * @param  string|null $id
773
+	 * @param  string|null $localKey
774
+	 * @throws MappingException
775
+	 * @return \Analogue\ORM\Relationships\MorphOne
776
+	 */
777
+	public function morphOne($entity, $related, $name, $type = null, $id = null, $localKey = null)
778
+	{
779
+		list($type, $id) = $this->getMorphs($name, $type, $id);
780
+
781
+		$localKey = $localKey ?: $this->getKeyName();
782
+
783
+		$relatedMapper = Manager::getInstance()->mapper($related);
784
+
785
+		$table = $relatedMapper->getEntityMap()->getTable();
786
+
787
+		// Add the relation to the definition in map
788
+		list(, $caller) = debug_backtrace(false);
789
+		$relation = $caller['function'];
790
+		$this->relatedClasses[$relation] = $related;
791
+		$this->singleRelations[] = $relation;
792
+		$this->foreignRelations[] = $relation;
793
+		$this->nonProxyRelationships[] = $relation;
794
+
795
+		// This relationship will always be eager loaded, as proxying it would
796
+		// mean having an object that doesn't actually exists.
797
+		if(! in_array($relation, $this->with)) {
798
+			$this->with[] = $relation;
799
+		}
800 800
         
801
-        return new MorphOne($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
802
-    }
803
-
804
-    /**
805
-     * Define an inverse one-to-one or many relationship.
806
-     *
807
-     * @param  mixed       $entity
808
-     * @param  string      $related
809
-     * @param  string|null $foreignKey
810
-     * @param  string|null $otherKey
811
-     * @param  string|null $relation
812
-     * @throws MappingException
813
-     * @return \Analogue\ORM\Relationships\BelongsTo
814
-     */
815
-    public function belongsTo($entity, $related, $foreignKey = null, $otherKey = null)
816
-    {
817
-        // Add the relation to the definition in map
818
-        list(, $caller) = debug_backtrace(false);
819
-        $relation = $caller['function'];
820
-        $this->relatedClasses[$relation] = $related;
821
-        $this->singleRelations[] = $relation;
822
-        $this->localRelations[] = $relation;
823
-
824
-        // If no foreign key was supplied, we can use a backtrace to guess the proper
825
-        // foreign key name by using the name of the relationship function, which
826
-        // when combined with an "_id" should conventionally match the columns.
827
-        if (is_null($foreignKey)) {
828
-            $foreignKey = snake_case($relation) . '_id';
829
-        }
830
-
831
-        $this->localForeignKeys[$relation] = $foreignKey;
832
-
833
-        $relatedMapper = Manager::getInstance()->mapper($related);
834
-
835
-        $otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getKeyName();
836
-
837
-        return new BelongsTo($relatedMapper, $entity, $foreignKey, $otherKey, $relation);
838
-    }
839
-
840
-    /**
841
-     * Define a polymorphic, inverse one-to-one or many relationship.
842
-     *
843
-     * @param  mixed       $entity
844
-     * @param  string|null $name
845
-     * @param  string|null $type
846
-     * @param  string|null $id
847
-     * @throws MappingException
848
-     * @return \Analogue\ORM\Relationships\MorphTo
849
-     */
850
-    public function morphTo($entity, $name = null, $type = null, $id = null)
851
-    {
852
-        // If no name is provided, we will use the backtrace to get the function name
853
-        // since that is most likely the name of the polymorphic interface. We can
854
-        // use that to get both the class and foreign key that will be utilized.
855
-        if (is_null($name)) {
856
-            list(, $caller) = debug_backtrace(false);
857
-
858
-            $name = snake_case($caller['function']);
859
-        }
860
-        $this->singleRelations[] = $name;
861
-        $this->localRelations[] = $relation;
862
-        $this->foreignRelations[] = $relation;
863
-        $this->relatedClass[$relation] = null;
864
-
865
-        list($type, $id) = $this->getMorphs($name, $type, $id);
866
-
867
-        // Store the foreign key in the entity map. 
868
-        // We might want to store the (key, type) as we might need it
869
-        // to build a MorphTo proxy
870
-        $this->localForeignKeys[$name] = [
871
-            "id" => $id,
872
-            "type" => $type
873
-        ];
801
+		return new MorphOne($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
802
+	}
803
+
804
+	/**
805
+	 * Define an inverse one-to-one or many relationship.
806
+	 *
807
+	 * @param  mixed       $entity
808
+	 * @param  string      $related
809
+	 * @param  string|null $foreignKey
810
+	 * @param  string|null $otherKey
811
+	 * @param  string|null $relation
812
+	 * @throws MappingException
813
+	 * @return \Analogue\ORM\Relationships\BelongsTo
814
+	 */
815
+	public function belongsTo($entity, $related, $foreignKey = null, $otherKey = null)
816
+	{
817
+		// Add the relation to the definition in map
818
+		list(, $caller) = debug_backtrace(false);
819
+		$relation = $caller['function'];
820
+		$this->relatedClasses[$relation] = $related;
821
+		$this->singleRelations[] = $relation;
822
+		$this->localRelations[] = $relation;
823
+
824
+		// If no foreign key was supplied, we can use a backtrace to guess the proper
825
+		// foreign key name by using the name of the relationship function, which
826
+		// when combined with an "_id" should conventionally match the columns.
827
+		if (is_null($foreignKey)) {
828
+			$foreignKey = snake_case($relation) . '_id';
829
+		}
830
+
831
+		$this->localForeignKeys[$relation] = $foreignKey;
832
+
833
+		$relatedMapper = Manager::getInstance()->mapper($related);
834
+
835
+		$otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getKeyName();
836
+
837
+		return new BelongsTo($relatedMapper, $entity, $foreignKey, $otherKey, $relation);
838
+	}
839
+
840
+	/**
841
+	 * Define a polymorphic, inverse one-to-one or many relationship.
842
+	 *
843
+	 * @param  mixed       $entity
844
+	 * @param  string|null $name
845
+	 * @param  string|null $type
846
+	 * @param  string|null $id
847
+	 * @throws MappingException
848
+	 * @return \Analogue\ORM\Relationships\MorphTo
849
+	 */
850
+	public function morphTo($entity, $name = null, $type = null, $id = null)
851
+	{
852
+		// If no name is provided, we will use the backtrace to get the function name
853
+		// since that is most likely the name of the polymorphic interface. We can
854
+		// use that to get both the class and foreign key that will be utilized.
855
+		if (is_null($name)) {
856
+			list(, $caller) = debug_backtrace(false);
857
+
858
+			$name = snake_case($caller['function']);
859
+		}
860
+		$this->singleRelations[] = $name;
861
+		$this->localRelations[] = $relation;
862
+		$this->foreignRelations[] = $relation;
863
+		$this->relatedClass[$relation] = null;
864
+
865
+		list($type, $id) = $this->getMorphs($name, $type, $id);
866
+
867
+		// Store the foreign key in the entity map. 
868
+		// We might want to store the (key, type) as we might need it
869
+		// to build a MorphTo proxy
870
+		$this->localForeignKeys[$name] = [
871
+			"id" => $id,
872
+			"type" => $type
873
+		];
874 874
         
875 875
 
876
-        $mapper = Manager::getInstance()->mapper(get_class($entity));
877
-
878
-        // If the type value is null it is probably safe to assume we're eager loading
879
-        // the relationship. When that is the case we will pass in a dummy query as
880
-        // there are multiple types in the morph and we can't use single queries.
881
-        $factory = new Factory;
882
-        $wrapper = $factory->make($entity);
883
-
884
-        if (is_null($class = $wrapper->getEntityAttribute($type))) {
885
-            return new MorphTo(
886
-                $mapper, $entity, $id, null, $type, $name
887
-            );
888
-        }
889
-
890
-        // If we are not eager loading the relationship we will essentially treat this
891
-        // as a belongs-to style relationship since morph-to extends that class and
892
-        // we will pass in the appropriate values so that it behaves as expected.
893
-        else {
894
-            $class = Manager::getInstance()->getInverseMorphMap($class);
895
-            $relatedMapper = Manager::getInstance()->mapper($class);
896
-
897
-            $foreignKey = $relatedMapper->getEntityMap()->getKeyName();
898
-
899
-            return new MorphTo(
900
-                $relatedMapper, $entity, $id, $foreignKey, $type, $name
901
-            );
902
-        }
903
-    }
904
-
905
-    /**
906
-     * Define a one-to-many relationship.
907
-     *
908
-     * @param  mixed       $entity
909
-     * @param  string      $related
910
-     * @param  string|null $foreignKey
911
-     * @param  string|null $localKey
912
-     * @throws MappingException
913
-     * @return \Analogue\ORM\Relationships\HasMany
914
-     */
915
-    public function hasMany($entity, $related, $foreignKey = null, $localKey = null)
916
-    {
917
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
918
-
919
-        $relatedMapper = Manager::getInstance()->mapper($related);
920
-
921
-        $table = $relatedMapper->getEntityMap()->getTable() . '.' . $foreignKey;
922
-
923
-        $localKey = $localKey ?: $this->getKeyName();
924
-
925
-        // Add the relation to the definition in map
926
-        list(, $caller) = debug_backtrace(false);
927
-        $relation = $caller['function'];
928
-        $this->relatedClasses[$relation] = $related;
929
-        $this->manyRelations[] = $relation;
930
-        $this->foreignRelations[] = $relation;
931
-
932
-        return new HasMany($relatedMapper, $entity, $table, $localKey);
933
-    }
934
-
935
-    /**
936
-     * Define a has-many-through relationship.
937
-     *
938
-     * @param  mixed       $entity
939
-     * @param  string      $related
940
-     * @param  string      $through
941
-     * @param  string|null $firstKey
942
-     * @param  string|null $secondKey
943
-     * @throws MappingException
944
-     * @return \Analogue\ORM\Relationships\HasManyThrough
945
-     */
946
-    public function hasManyThrough($entity, $related, $through, $firstKey = null, $secondKey = null)
947
-    {
948
-        $relatedMapper = Manager::getInstance()->mapper($related);
949
-
950
-        $throughMapper = Manager::getInstance()->mapper($through);
951
-
952
-
953
-        $firstKey = $firstKey ?: $this->getForeignKey();
954
-
955
-        $throughMap = $throughMapper->getEntityMap();
956
-
957
-        $secondKey = $secondKey ?: $throughMap->getForeignKey();
958
-
959
-        // Add the relation to the definition in map
960
-        list(, $caller) = debug_backtrace(false);
961
-        $relation = $caller['function'];
962
-        $this->relatedClasses[$relation] = $related;
963
-        $this->manyRelations[] = $relation;
964
-        $this->foreignRelations[] = $relation;
965
-
966
-        return new HasManyThrough($relatedMapper, $entity, $throughMap, $firstKey, $secondKey);
967
-    }
968
-
969
-    /**
970
-     * Define a polymorphic one-to-many relationship.
971
-     *
972
-     * @param  mixed       $entity
973
-     * @param  string      $related
974
-     * @param  string      $name
975
-     * @param  string|null $type
976
-     * @param  string|null $id
977
-     * @param  string|null $localKey
978
-     * @return \Analogue\ORM\Relationships\MorphMany
979
-     */
980
-    public function morphMany($entity, $related, $name, $type = null, $id = null, $localKey = null)
981
-    {
982
-        // Here we will gather up the morph type and ID for the relationship so that we
983
-        // can properly query the intermediate table of a relation. Finally, we will
984
-        // get the table and create the relationship instances for the developers.
985
-        list($type, $id) = $this->getMorphs($name, $type, $id);
986
-
987
-        $relatedMapper = Manager::getInstance()->mapper($related);
988
-
989
-        $table = $relatedMapper->getEntityMap()->getTable();
990
-
991
-        $localKey = $localKey ?: $this->getKeyName();
992
-
993
-        // Add the relation to the definition in map
994
-        list(, $caller) = debug_backtrace(false);
995
-        $relation = $caller['function'];
996
-        $this->relatedClasses[$relation] = $related;
997
-        $this->manyRelations[] = $relation;
998
-        $this->foreignRelations[] = $relation;
999
-
1000
-        return new MorphMany($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
1001
-    }
1002
-
1003
-    /**
1004
-     * Define a many-to-many relationship.
1005
-     *
1006
-     * @param  mixed       $entity
1007
-     * @param  string      $relatedClass
1008
-     * @param  string|null $table
1009
-     * @param  string|null $foreignKey
1010
-     * @param  string|null $otherKey
1011
-     * @param  string|null $relation
1012
-     * @throws MappingException
1013
-     * @return \Analogue\ORM\Relationships\BelongsToMany
1014
-     */
1015
-    public function belongsToMany($entity, $related, $table = null, $foreignKey = null, $otherKey = null)
1016
-    {
1017
-        // Add the relation to the definition in map
1018
-        list(, $caller) = debug_backtrace(false);
1019
-        $relation = $caller['function'];
1020
-        $this->relatedClasses[$relation] = $related;
1021
-        $this->manyRelations[] = $relation;
1022
-        $this->foreignRelations[] = $relation;
1023
-        $this->pivotRelations[] = $relation;
1024
-
1025
-        // First, we'll need to determine the foreign key and "other key" for the
1026
-        // relationship. Once we have determined the keys we'll make the query
1027
-        // instances as well as the relationship instances we need for this.
1028
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
1029
-
1030
-        $relatedMapper = Manager::getInstance()->mapper($related);
1031
-
1032
-        $relatedMap = $relatedMapper->getEntityMap();
1033
-
1034
-        $otherKey = $otherKey ?: $relatedMap->getForeignKey();
1035
-
1036
-        // If no table name was provided, we can guess it by concatenating the two
1037
-        // models using underscores in alphabetical order. The two model names
1038
-        // are transformed to snake case from their default CamelCase also.
1039
-        if (is_null($table)) {
1040
-            $table = $this->joiningTable($relatedMap);
1041
-        }
1042
-
1043
-        return new BelongsToMany($relatedMapper, $entity, $table, $foreignKey, $otherKey, $relation);
1044
-    }
1045
-
1046
-    /**
1047
-     * Define a polymorphic many-to-many relationship.
1048
-     *
1049
-     * @param  mixed       $entity
1050
-     * @param  string      $related
1051
-     * @param  string      $name
1052
-     * @param  string|null $table
1053
-     * @param  string|null $foreignKey
1054
-     * @param  string|null $otherKey
1055
-     * @param  bool        $inverse
1056
-     * @throws MappingException
1057
-     * @return \Analogue\ORM\Relationships\MorphToMany
1058
-     */
1059
-    public function morphToMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
1060
-    {
1061
-        // Add the relation to the definition in map
1062
-        list(, $caller) = debug_backtrace(false);
1063
-        $relation = $caller['function'];
1064
-        $this->relatedClasses[$relation] = $related;
1065
-        $this->manyRelations[] = $relation;
1066
-        $this->foreignRelations[] = $relation;
1067
-        $this->pivotRelations[] = $relation;
1068
-
1069
-        // First, we will need to determine the foreign key and "other key" for the
1070
-        // relationship. Once we have determined the keys we will make the query
1071
-        // instances, as well as the relationship instances we need for these.
1072
-        $foreignKey = $foreignKey ?: $name . '_id';
1073
-
1074
-        $relatedMapper = Manager::getInstance()->mapper($related);
1075
-
1076
-        $otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getForeignKey();
1077
-
1078
-        $table = $table ?: str_plural($name);
1079
-
1080
-        return new MorphToMany($relatedMapper, $entity, $name, $table, $foreignKey, $otherKey, $caller, $inverse);
1081
-    }
1082
-
1083
-    /**
1084
-     * Define a polymorphic, inverse many-to-many relationship.
1085
-     *
1086
-     * @param  mixed       $entity
1087
-     * @param  string      $related
1088
-     * @param  string      $name
1089
-     * @param  string|null $table
1090
-     * @param  string|null $foreignKey
1091
-     * @param  string|null $otherKey
1092
-     * @throws MappingException
1093
-     * @return \Analogue\ORM\Relationships\MorphToMany
1094
-     */
1095
-    public function morphedByMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null)
1096
-    {
1097
-        // Add the relation to the definition in map
1098
-        list(, $caller) = debug_backtrace(false);
1099
-        $relation = $caller['function'];
1100
-        $this->relatedClasses[$relation] = $related;
1101
-        $this->manyRelations[] = $relation;
1102
-        $this->foreignRelations[] = $relation;
1103
-
1104
-        $foreignKey = $foreignKey ?: $this->getForeignKey();
1105
-
1106
-        // For the inverse of the polymorphic many-to-many relations, we will change
1107
-        // the way we determine the foreign and other keys, as it is the opposite
1108
-        // of the morph-to-many method since we're figuring out these inverses.
1109
-        $otherKey = $otherKey ?: $name . '_id';
1110
-
1111
-        return $this->morphToMany($entity, $related, $name, $table, $foreignKey, $otherKey, true);
1112
-    }
1113
-
1114
-    /**
1115
-     * Get the joining table name for a many-to-many relation.
1116
-     *
1117
-     * @param  EntityMap $relatedMap
1118
-     * @return string
1119
-     */
1120
-    public function joiningTable($relatedMap)
1121
-    {
1122
-        // The joining table name, by convention, is simply the snake cased models
1123
-        // sorted alphabetically and concatenated with an underscore, so we can
1124
-        // just sort the models and join them together to get the table name.
1125
-        $base = $this->getTable();
1126
-
1127
-        $related = $relatedMap->getTable();
1128
-
1129
-        $tables = [$related, $base];
1130
-
1131
-        // Now that we have the model names in an array we can just sort them and
1132
-        // use the implode function to join them together with an underscores,
1133
-        // which is typically used by convention within the database system.
1134
-        sort($tables);
1135
-
1136
-        return strtolower(implode('_', $tables));
1137
-    }
1138
-
1139
-    /**
1140
-     * Get the polymorphic relationship columns.
1141
-     *
1142
-     * @param  string $name
1143
-     * @param  string $type
1144
-     * @param  string $id
1145
-     * @return string[]
1146
-     */
1147
-    protected function getMorphs($name, $type, $id)
1148
-    {
1149
-        $type = $type ?: $name . '_type';
1150
-
1151
-        $id = $id ?: $name . '_id';
1152
-
1153
-        return [$type, $id];
1154
-    }
1155
-
1156
-    /**
1157
-     * Get the class name for polymorphic relations.
1158
-     *
1159
-     * @return string
1160
-     */
1161
-    public function getMorphClass()
1162
-    {
1163
-        $morphClass = Manager::getInstance()->getMorphMap($this->getClass());
1164
-        return $this->morphClass ?: $morphClass;
1165
-    }
1166
-
1167
-    /**
1168
-     * Create a new Entity Collection instance.
1169
-     *
1170
-     * @param  array $entities
1171
-     * @return \Analogue\ORM\EntityCollection
1172
-     */
1173
-    public function newCollection(array $entities = [])
1174
-    {
1175
-        $collection = new EntityCollection($entities, $this);
1176
-        return $collection->keyBy($this->getKeyName());
1177
-    }
1178
-
1179
-    /**
1180
-     * Process EntityMap parsing at initialization time
1181
-     *
1182
-     * @return void
1183
-     */
1184
-    public function initialize()
1185
-    {
1186
-        $userMethods = $this->getCustomMethods();
1187
-
1188
-        // Parse EntityMap for method based relationship
1189
-        if (count($userMethods) > 0) {
1190
-            $this->relationships = $this->parseMethodsForRelationship($userMethods);
1191
-        }
1192
-
1193
-        // Parse EntityMap for dynamic relationships
1194
-        if (count($this->dynamicRelationships) > 0) {
1195
-            $this->relationships = $this->relationships + $this->getDynamicRelationships();
1196
-        }
1197
-    }
1198
-
1199
-    /**
1200
-     * Parse every relationships on the EntityMap and sort
1201
-     * them by type.
1202
-     *
1203
-     * @return void
1204
-     */
1205
-    public function boot()
1206
-    {
1207
-        if (count($this->relationships > 0)) {
1208
-            $this->sortRelationshipsByType();
1209
-        }
1210
-    }
1211
-
1212
-    /**
1213
-     * Get Methods that has been added in the child class.
1214
-     *
1215
-     * @return array
1216
-     */
1217
-    protected function getCustomMethods()
1218
-    {
1219
-        $mapMethods = get_class_methods($this);
1220
-
1221
-        $parentsMethods = get_class_methods('Analogue\ORM\EntityMap');
1222
-
1223
-        return array_diff($mapMethods, $parentsMethods);
1224
-    }
1225
-
1226
-    /**
1227
-     * Parse user's class methods for relationships
1228
-     *
1229
-     * @param  array $customMethods
1230
-     * @return array
1231
-     */
1232
-    protected function parseMethodsForRelationship(array $customMethods)
1233
-    {
1234
-        $relationships = [];
1235
-
1236
-        $class = new ReflectionClass(get_class($this));
1237
-
1238
-        // Get the mapped Entity class, as we will detect relationships
1239
-        // methods by testing that the first argument is type-hinted to
1240
-        // the same class as the mapped Entity.
1241
-        $entityClass = $this->getClass();
1242
-
1243
-        foreach ($customMethods as $methodName) {
1244
-            $method = $class->getMethod($methodName);
1245
-
1246
-            if ($method->getNumberOfParameters() > 0) {
1247
-                $params = $method->getParameters();
1248
-
1249
-                if ($params[0]->getClass() && ($params[0]->getClass()->name == $entityClass || is_subclass_of($entityClass, $params[0]->getClass()->name))) {
1250
-                    $relationships[] = $methodName;
1251
-                }
1252
-            }
1253
-        }
1254
-
1255
-        return $relationships;
1256
-    }
1257
-
1258
-    /**
1259
-     * Sort Relationships methods by type
1260
-     * 
1261
-     * TODO : replace this by direclty setting these value
1262
-     * in the corresponding methods, so we won't need
1263
-     * the correpondancy tabble
1264
-     * 
1265
-     * @return void
1266
-     */
1267
-    protected function sortRelationshipsByType()
1268
-    {
1269
-        $entityClass = $this->getClass();
1270
-
1271
-        // Instantiate a dummy entity which we will pass to relationship methods.
1272
-        $entity = unserialize(sprintf('O:%d:"%s":0:{}', strlen($entityClass), $entityClass));
1273
-
1274
-        foreach ($this->relationships as $relation) {
1275
-            $this->$relation($entity);
1276
-        }
1277
-    }
1278
-
1279
-    /**
1280
-     * Override this method for custom entity instantiation
1281
-     *
1282
-     * @return null
1283
-     */
1284
-    public function activator()
1285
-    {
1286
-        return null;
1287
-    }
1288
-
1289
-    /**
1290
-     * Call dynamic relationship, if it exists
1291
-     *
1292
-     * @param  string $method
1293
-     * @param  array  $parameters
1294
-     * @throws Exception
1295
-     * @return mixed
1296
-     */
1297
-    public function __call($method, $parameters)
1298
-    {
1299
-        if (!array_key_exists($method, $this->dynamicRelationships)) {
1300
-            throw new Exception(get_class($this) . " has no method $method");
1301
-        }
1302
-
1303
-        // Add $this to parameters so the closure can call relationship method on the map.
1304
-        $parameters[] = $this;
1305
-
1306
-        return  call_user_func_array([$this->dynamicRelationships[$method], $parameters]);
1307
-    }
876
+		$mapper = Manager::getInstance()->mapper(get_class($entity));
877
+
878
+		// If the type value is null it is probably safe to assume we're eager loading
879
+		// the relationship. When that is the case we will pass in a dummy query as
880
+		// there are multiple types in the morph and we can't use single queries.
881
+		$factory = new Factory;
882
+		$wrapper = $factory->make($entity);
883
+
884
+		if (is_null($class = $wrapper->getEntityAttribute($type))) {
885
+			return new MorphTo(
886
+				$mapper, $entity, $id, null, $type, $name
887
+			);
888
+		}
889
+
890
+		// If we are not eager loading the relationship we will essentially treat this
891
+		// as a belongs-to style relationship since morph-to extends that class and
892
+		// we will pass in the appropriate values so that it behaves as expected.
893
+		else {
894
+			$class = Manager::getInstance()->getInverseMorphMap($class);
895
+			$relatedMapper = Manager::getInstance()->mapper($class);
896
+
897
+			$foreignKey = $relatedMapper->getEntityMap()->getKeyName();
898
+
899
+			return new MorphTo(
900
+				$relatedMapper, $entity, $id, $foreignKey, $type, $name
901
+			);
902
+		}
903
+	}
904
+
905
+	/**
906
+	 * Define a one-to-many relationship.
907
+	 *
908
+	 * @param  mixed       $entity
909
+	 * @param  string      $related
910
+	 * @param  string|null $foreignKey
911
+	 * @param  string|null $localKey
912
+	 * @throws MappingException
913
+	 * @return \Analogue\ORM\Relationships\HasMany
914
+	 */
915
+	public function hasMany($entity, $related, $foreignKey = null, $localKey = null)
916
+	{
917
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
918
+
919
+		$relatedMapper = Manager::getInstance()->mapper($related);
920
+
921
+		$table = $relatedMapper->getEntityMap()->getTable() . '.' . $foreignKey;
922
+
923
+		$localKey = $localKey ?: $this->getKeyName();
924
+
925
+		// Add the relation to the definition in map
926
+		list(, $caller) = debug_backtrace(false);
927
+		$relation = $caller['function'];
928
+		$this->relatedClasses[$relation] = $related;
929
+		$this->manyRelations[] = $relation;
930
+		$this->foreignRelations[] = $relation;
931
+
932
+		return new HasMany($relatedMapper, $entity, $table, $localKey);
933
+	}
934
+
935
+	/**
936
+	 * Define a has-many-through relationship.
937
+	 *
938
+	 * @param  mixed       $entity
939
+	 * @param  string      $related
940
+	 * @param  string      $through
941
+	 * @param  string|null $firstKey
942
+	 * @param  string|null $secondKey
943
+	 * @throws MappingException
944
+	 * @return \Analogue\ORM\Relationships\HasManyThrough
945
+	 */
946
+	public function hasManyThrough($entity, $related, $through, $firstKey = null, $secondKey = null)
947
+	{
948
+		$relatedMapper = Manager::getInstance()->mapper($related);
949
+
950
+		$throughMapper = Manager::getInstance()->mapper($through);
951
+
952
+
953
+		$firstKey = $firstKey ?: $this->getForeignKey();
954
+
955
+		$throughMap = $throughMapper->getEntityMap();
956
+
957
+		$secondKey = $secondKey ?: $throughMap->getForeignKey();
958
+
959
+		// Add the relation to the definition in map
960
+		list(, $caller) = debug_backtrace(false);
961
+		$relation = $caller['function'];
962
+		$this->relatedClasses[$relation] = $related;
963
+		$this->manyRelations[] = $relation;
964
+		$this->foreignRelations[] = $relation;
965
+
966
+		return new HasManyThrough($relatedMapper, $entity, $throughMap, $firstKey, $secondKey);
967
+	}
968
+
969
+	/**
970
+	 * Define a polymorphic one-to-many relationship.
971
+	 *
972
+	 * @param  mixed       $entity
973
+	 * @param  string      $related
974
+	 * @param  string      $name
975
+	 * @param  string|null $type
976
+	 * @param  string|null $id
977
+	 * @param  string|null $localKey
978
+	 * @return \Analogue\ORM\Relationships\MorphMany
979
+	 */
980
+	public function morphMany($entity, $related, $name, $type = null, $id = null, $localKey = null)
981
+	{
982
+		// Here we will gather up the morph type and ID for the relationship so that we
983
+		// can properly query the intermediate table of a relation. Finally, we will
984
+		// get the table and create the relationship instances for the developers.
985
+		list($type, $id) = $this->getMorphs($name, $type, $id);
986
+
987
+		$relatedMapper = Manager::getInstance()->mapper($related);
988
+
989
+		$table = $relatedMapper->getEntityMap()->getTable();
990
+
991
+		$localKey = $localKey ?: $this->getKeyName();
992
+
993
+		// Add the relation to the definition in map
994
+		list(, $caller) = debug_backtrace(false);
995
+		$relation = $caller['function'];
996
+		$this->relatedClasses[$relation] = $related;
997
+		$this->manyRelations[] = $relation;
998
+		$this->foreignRelations[] = $relation;
999
+
1000
+		return new MorphMany($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
1001
+	}
1002
+
1003
+	/**
1004
+	 * Define a many-to-many relationship.
1005
+	 *
1006
+	 * @param  mixed       $entity
1007
+	 * @param  string      $relatedClass
1008
+	 * @param  string|null $table
1009
+	 * @param  string|null $foreignKey
1010
+	 * @param  string|null $otherKey
1011
+	 * @param  string|null $relation
1012
+	 * @throws MappingException
1013
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
1014
+	 */
1015
+	public function belongsToMany($entity, $related, $table = null, $foreignKey = null, $otherKey = null)
1016
+	{
1017
+		// Add the relation to the definition in map
1018
+		list(, $caller) = debug_backtrace(false);
1019
+		$relation = $caller['function'];
1020
+		$this->relatedClasses[$relation] = $related;
1021
+		$this->manyRelations[] = $relation;
1022
+		$this->foreignRelations[] = $relation;
1023
+		$this->pivotRelations[] = $relation;
1024
+
1025
+		// First, we'll need to determine the foreign key and "other key" for the
1026
+		// relationship. Once we have determined the keys we'll make the query
1027
+		// instances as well as the relationship instances we need for this.
1028
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
1029
+
1030
+		$relatedMapper = Manager::getInstance()->mapper($related);
1031
+
1032
+		$relatedMap = $relatedMapper->getEntityMap();
1033
+
1034
+		$otherKey = $otherKey ?: $relatedMap->getForeignKey();
1035
+
1036
+		// If no table name was provided, we can guess it by concatenating the two
1037
+		// models using underscores in alphabetical order. The two model names
1038
+		// are transformed to snake case from their default CamelCase also.
1039
+		if (is_null($table)) {
1040
+			$table = $this->joiningTable($relatedMap);
1041
+		}
1042
+
1043
+		return new BelongsToMany($relatedMapper, $entity, $table, $foreignKey, $otherKey, $relation);
1044
+	}
1045
+
1046
+	/**
1047
+	 * Define a polymorphic many-to-many relationship.
1048
+	 *
1049
+	 * @param  mixed       $entity
1050
+	 * @param  string      $related
1051
+	 * @param  string      $name
1052
+	 * @param  string|null $table
1053
+	 * @param  string|null $foreignKey
1054
+	 * @param  string|null $otherKey
1055
+	 * @param  bool        $inverse
1056
+	 * @throws MappingException
1057
+	 * @return \Analogue\ORM\Relationships\MorphToMany
1058
+	 */
1059
+	public function morphToMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
1060
+	{
1061
+		// Add the relation to the definition in map
1062
+		list(, $caller) = debug_backtrace(false);
1063
+		$relation = $caller['function'];
1064
+		$this->relatedClasses[$relation] = $related;
1065
+		$this->manyRelations[] = $relation;
1066
+		$this->foreignRelations[] = $relation;
1067
+		$this->pivotRelations[] = $relation;
1068
+
1069
+		// First, we will need to determine the foreign key and "other key" for the
1070
+		// relationship. Once we have determined the keys we will make the query
1071
+		// instances, as well as the relationship instances we need for these.
1072
+		$foreignKey = $foreignKey ?: $name . '_id';
1073
+
1074
+		$relatedMapper = Manager::getInstance()->mapper($related);
1075
+
1076
+		$otherKey = $otherKey ?: $relatedMapper->getEntityMap()->getForeignKey();
1077
+
1078
+		$table = $table ?: str_plural($name);
1079
+
1080
+		return new MorphToMany($relatedMapper, $entity, $name, $table, $foreignKey, $otherKey, $caller, $inverse);
1081
+	}
1082
+
1083
+	/**
1084
+	 * Define a polymorphic, inverse many-to-many relationship.
1085
+	 *
1086
+	 * @param  mixed       $entity
1087
+	 * @param  string      $related
1088
+	 * @param  string      $name
1089
+	 * @param  string|null $table
1090
+	 * @param  string|null $foreignKey
1091
+	 * @param  string|null $otherKey
1092
+	 * @throws MappingException
1093
+	 * @return \Analogue\ORM\Relationships\MorphToMany
1094
+	 */
1095
+	public function morphedByMany($entity, $related, $name, $table = null, $foreignKey = null, $otherKey = null)
1096
+	{
1097
+		// Add the relation to the definition in map
1098
+		list(, $caller) = debug_backtrace(false);
1099
+		$relation = $caller['function'];
1100
+		$this->relatedClasses[$relation] = $related;
1101
+		$this->manyRelations[] = $relation;
1102
+		$this->foreignRelations[] = $relation;
1103
+
1104
+		$foreignKey = $foreignKey ?: $this->getForeignKey();
1105
+
1106
+		// For the inverse of the polymorphic many-to-many relations, we will change
1107
+		// the way we determine the foreign and other keys, as it is the opposite
1108
+		// of the morph-to-many method since we're figuring out these inverses.
1109
+		$otherKey = $otherKey ?: $name . '_id';
1110
+
1111
+		return $this->morphToMany($entity, $related, $name, $table, $foreignKey, $otherKey, true);
1112
+	}
1113
+
1114
+	/**
1115
+	 * Get the joining table name for a many-to-many relation.
1116
+	 *
1117
+	 * @param  EntityMap $relatedMap
1118
+	 * @return string
1119
+	 */
1120
+	public function joiningTable($relatedMap)
1121
+	{
1122
+		// The joining table name, by convention, is simply the snake cased models
1123
+		// sorted alphabetically and concatenated with an underscore, so we can
1124
+		// just sort the models and join them together to get the table name.
1125
+		$base = $this->getTable();
1126
+
1127
+		$related = $relatedMap->getTable();
1128
+
1129
+		$tables = [$related, $base];
1130
+
1131
+		// Now that we have the model names in an array we can just sort them and
1132
+		// use the implode function to join them together with an underscores,
1133
+		// which is typically used by convention within the database system.
1134
+		sort($tables);
1135
+
1136
+		return strtolower(implode('_', $tables));
1137
+	}
1138
+
1139
+	/**
1140
+	 * Get the polymorphic relationship columns.
1141
+	 *
1142
+	 * @param  string $name
1143
+	 * @param  string $type
1144
+	 * @param  string $id
1145
+	 * @return string[]
1146
+	 */
1147
+	protected function getMorphs($name, $type, $id)
1148
+	{
1149
+		$type = $type ?: $name . '_type';
1150
+
1151
+		$id = $id ?: $name . '_id';
1152
+
1153
+		return [$type, $id];
1154
+	}
1155
+
1156
+	/**
1157
+	 * Get the class name for polymorphic relations.
1158
+	 *
1159
+	 * @return string
1160
+	 */
1161
+	public function getMorphClass()
1162
+	{
1163
+		$morphClass = Manager::getInstance()->getMorphMap($this->getClass());
1164
+		return $this->morphClass ?: $morphClass;
1165
+	}
1166
+
1167
+	/**
1168
+	 * Create a new Entity Collection instance.
1169
+	 *
1170
+	 * @param  array $entities
1171
+	 * @return \Analogue\ORM\EntityCollection
1172
+	 */
1173
+	public function newCollection(array $entities = [])
1174
+	{
1175
+		$collection = new EntityCollection($entities, $this);
1176
+		return $collection->keyBy($this->getKeyName());
1177
+	}
1178
+
1179
+	/**
1180
+	 * Process EntityMap parsing at initialization time
1181
+	 *
1182
+	 * @return void
1183
+	 */
1184
+	public function initialize()
1185
+	{
1186
+		$userMethods = $this->getCustomMethods();
1187
+
1188
+		// Parse EntityMap for method based relationship
1189
+		if (count($userMethods) > 0) {
1190
+			$this->relationships = $this->parseMethodsForRelationship($userMethods);
1191
+		}
1192
+
1193
+		// Parse EntityMap for dynamic relationships
1194
+		if (count($this->dynamicRelationships) > 0) {
1195
+			$this->relationships = $this->relationships + $this->getDynamicRelationships();
1196
+		}
1197
+	}
1198
+
1199
+	/**
1200
+	 * Parse every relationships on the EntityMap and sort
1201
+	 * them by type.
1202
+	 *
1203
+	 * @return void
1204
+	 */
1205
+	public function boot()
1206
+	{
1207
+		if (count($this->relationships > 0)) {
1208
+			$this->sortRelationshipsByType();
1209
+		}
1210
+	}
1211
+
1212
+	/**
1213
+	 * Get Methods that has been added in the child class.
1214
+	 *
1215
+	 * @return array
1216
+	 */
1217
+	protected function getCustomMethods()
1218
+	{
1219
+		$mapMethods = get_class_methods($this);
1220
+
1221
+		$parentsMethods = get_class_methods('Analogue\ORM\EntityMap');
1222
+
1223
+		return array_diff($mapMethods, $parentsMethods);
1224
+	}
1225
+
1226
+	/**
1227
+	 * Parse user's class methods for relationships
1228
+	 *
1229
+	 * @param  array $customMethods
1230
+	 * @return array
1231
+	 */
1232
+	protected function parseMethodsForRelationship(array $customMethods)
1233
+	{
1234
+		$relationships = [];
1235
+
1236
+		$class = new ReflectionClass(get_class($this));
1237
+
1238
+		// Get the mapped Entity class, as we will detect relationships
1239
+		// methods by testing that the first argument is type-hinted to
1240
+		// the same class as the mapped Entity.
1241
+		$entityClass = $this->getClass();
1242
+
1243
+		foreach ($customMethods as $methodName) {
1244
+			$method = $class->getMethod($methodName);
1245
+
1246
+			if ($method->getNumberOfParameters() > 0) {
1247
+				$params = $method->getParameters();
1248
+
1249
+				if ($params[0]->getClass() && ($params[0]->getClass()->name == $entityClass || is_subclass_of($entityClass, $params[0]->getClass()->name))) {
1250
+					$relationships[] = $methodName;
1251
+				}
1252
+			}
1253
+		}
1254
+
1255
+		return $relationships;
1256
+	}
1257
+
1258
+	/**
1259
+	 * Sort Relationships methods by type
1260
+	 * 
1261
+	 * TODO : replace this by direclty setting these value
1262
+	 * in the corresponding methods, so we won't need
1263
+	 * the correpondancy tabble
1264
+	 * 
1265
+	 * @return void
1266
+	 */
1267
+	protected function sortRelationshipsByType()
1268
+	{
1269
+		$entityClass = $this->getClass();
1270
+
1271
+		// Instantiate a dummy entity which we will pass to relationship methods.
1272
+		$entity = unserialize(sprintf('O:%d:"%s":0:{}', strlen($entityClass), $entityClass));
1273
+
1274
+		foreach ($this->relationships as $relation) {
1275
+			$this->$relation($entity);
1276
+		}
1277
+	}
1278
+
1279
+	/**
1280
+	 * Override this method for custom entity instantiation
1281
+	 *
1282
+	 * @return null
1283
+	 */
1284
+	public function activator()
1285
+	{
1286
+		return null;
1287
+	}
1288
+
1289
+	/**
1290
+	 * Call dynamic relationship, if it exists
1291
+	 *
1292
+	 * @param  string $method
1293
+	 * @param  array  $parameters
1294
+	 * @throws Exception
1295
+	 * @return mixed
1296
+	 */
1297
+	public function __call($method, $parameters)
1298
+	{
1299
+		if (!array_key_exists($method, $this->dynamicRelationships)) {
1300
+			throw new Exception(get_class($this) . " has no method $method");
1301
+		}
1302
+
1303
+		// Add $this to parameters so the closure can call relationship method on the map.
1304
+		$parameters[] = $this;
1305
+
1306
+		return  call_user_func_array([$this->dynamicRelationships[$method], $parameters]);
1307
+	}
1308 1308
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -397,7 +397,7 @@  discard block
 block discarded – undo
397 397
         if (!is_null($this->sequence)) {
398 398
             return $this->sequence;
399 399
         } else {
400
-            return $this->getTable() . '_id_seq';
400
+            return $this->getTable().'_id_seq';
401 401
         }
402 402
     }
403 403
 
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
      */
599 599
     public function getQualifiedKeyName()
600 600
     {
601
-        return $this->getTable() . '.' . $this->getKeyName();
601
+        return $this->getTable().'.'.$this->getKeyName();
602 602
     }
603 603
 
604 604
     /**
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
      */
680 680
     public function getForeignKey()
681 681
     {
682
-        return snake_case(class_basename($this->getClass())) . '_id';
682
+        return snake_case(class_basename($this->getClass())).'_id';
683 683
     }
684 684
 
685 685
     /**
@@ -755,11 +755,11 @@  discard block
 block discarded – undo
755 755
 
756 756
         // This relationship will always be eager loaded, as proxying it would
757 757
         // mean having an object that doesn't actually exists.
758
-        if(! in_array($relation, $this->with)) {
758
+        if (!in_array($relation, $this->with)) {
759 759
             $this->with[] = $relation;
760 760
         }
761 761
 
762
-        return new HasOne($relatedMapper, $entity, $relatedMap->getTable() . '.' . $foreignKey, $localKey);
762
+        return new HasOne($relatedMapper, $entity, $relatedMap->getTable().'.'.$foreignKey, $localKey);
763 763
     }
764 764
 
765 765
     /**
@@ -794,11 +794,11 @@  discard block
 block discarded – undo
794 794
 
795 795
         // This relationship will always be eager loaded, as proxying it would
796 796
         // mean having an object that doesn't actually exists.
797
-        if(! in_array($relation, $this->with)) {
797
+        if (!in_array($relation, $this->with)) {
798 798
             $this->with[] = $relation;
799 799
         }
800 800
         
801
-        return new MorphOne($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
801
+        return new MorphOne($relatedMapper, $entity, $table.'.'.$type, $table.'.'.$id, $localKey);
802 802
     }
803 803
 
804 804
     /**
@@ -825,7 +825,7 @@  discard block
 block discarded – undo
825 825
         // foreign key name by using the name of the relationship function, which
826 826
         // when combined with an "_id" should conventionally match the columns.
827 827
         if (is_null($foreignKey)) {
828
-            $foreignKey = snake_case($relation) . '_id';
828
+            $foreignKey = snake_case($relation).'_id';
829 829
         }
830 830
 
831 831
         $this->localForeignKeys[$relation] = $foreignKey;
@@ -918,7 +918,7 @@  discard block
 block discarded – undo
918 918
 
919 919
         $relatedMapper = Manager::getInstance()->mapper($related);
920 920
 
921
-        $table = $relatedMapper->getEntityMap()->getTable() . '.' . $foreignKey;
921
+        $table = $relatedMapper->getEntityMap()->getTable().'.'.$foreignKey;
922 922
 
923 923
         $localKey = $localKey ?: $this->getKeyName();
924 924
 
@@ -997,7 +997,7 @@  discard block
 block discarded – undo
997 997
         $this->manyRelations[] = $relation;
998 998
         $this->foreignRelations[] = $relation;
999 999
 
1000
-        return new MorphMany($relatedMapper, $entity, $table . '.' . $type, $table . '.' . $id, $localKey);
1000
+        return new MorphMany($relatedMapper, $entity, $table.'.'.$type, $table.'.'.$id, $localKey);
1001 1001
     }
1002 1002
 
1003 1003
     /**
@@ -1069,7 +1069,7 @@  discard block
 block discarded – undo
1069 1069
         // First, we will need to determine the foreign key and "other key" for the
1070 1070
         // relationship. Once we have determined the keys we will make the query
1071 1071
         // instances, as well as the relationship instances we need for these.
1072
-        $foreignKey = $foreignKey ?: $name . '_id';
1072
+        $foreignKey = $foreignKey ?: $name.'_id';
1073 1073
 
1074 1074
         $relatedMapper = Manager::getInstance()->mapper($related);
1075 1075
 
@@ -1106,7 +1106,7 @@  discard block
 block discarded – undo
1106 1106
         // For the inverse of the polymorphic many-to-many relations, we will change
1107 1107
         // the way we determine the foreign and other keys, as it is the opposite
1108 1108
         // of the morph-to-many method since we're figuring out these inverses.
1109
-        $otherKey = $otherKey ?: $name . '_id';
1109
+        $otherKey = $otherKey ?: $name.'_id';
1110 1110
 
1111 1111
         return $this->morphToMany($entity, $related, $name, $table, $foreignKey, $otherKey, true);
1112 1112
     }
@@ -1146,9 +1146,9 @@  discard block
 block discarded – undo
1146 1146
      */
1147 1147
     protected function getMorphs($name, $type, $id)
1148 1148
     {
1149
-        $type = $type ?: $name . '_type';
1149
+        $type = $type ?: $name.'_type';
1150 1150
 
1151
-        $id = $id ?: $name . '_id';
1151
+        $id = $id ?: $name.'_id';
1152 1152
 
1153 1153
         return [$type, $id];
1154 1154
     }
@@ -1297,7 +1297,7 @@  discard block
 block discarded – undo
1297 1297
     public function __call($method, $parameters)
1298 1298
     {
1299 1299
         if (!array_key_exists($method, $this->dynamicRelationships)) {
1300
-            throw new Exception(get_class($this) . " has no method $method");
1300
+            throw new Exception(get_class($this)." has no method $method");
1301 1301
         }
1302 1302
 
1303 1303
         // Add $this to parameters so the closure can call relationship method on the map.
Please login to merge, or discard this patch.
src/System/Proxies/CollectionProxy.php 5 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -209,7 +209,7 @@
 block discarded – undo
209 209
      *
210 210
      * @param  int  $step
211 211
      * @param  int  $offset
212
-     * @return static
212
+     * @return boolean
213 213
      */
214 214
     public function every($step, $offset = 0)
215 215
     {
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -2,7 +2,6 @@
 block discarded – undo
2 2
 
3 3
 namespace Analogue\ORM\System\Proxies;
4 4
 
5
-use Closure;
6 5
 use CachingIterator;
7 6
 use Analogue\ORM\EntityCollection;
8 7
 use ProxyManager\Proxy\ProxyInterface;
Please login to merge, or discard this patch.
Indentation   +1183 added lines, -1183 removed lines patch added patch discarded remove patch
@@ -10,1191 +10,1191 @@
 block discarded – undo
10 10
 
11 11
 class CollectionProxy extends EntityCollection implements ProxyInterface
12 12
 {
13
-    /** 
14
-     * Indicate if the relationship has been lazy loaded
15
-     * @var boolean
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() ) return true;
13
+	/** 
14
+	 * Indicate if the relationship has been lazy loaded
15
+	 * @var boolean
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() ) return true;
54 54
         
55
-        $relation = $this->relationshipMethod;
56
-        $entity = $this->parentEntity;
57
-
58
-        $entityMap = Manager::getMapper($entity)->getEntityMap();
59
-
60
-        $this->items = $entityMap->$relation($entity)->getResults($relation)->all() + $this->addedItems;
61
-
62
-        $this->relationshipLoaded = true;
63
-
64
-        return true;
65
-    }
66
-
67
-    /**
68
-     * Retrieves current initialization status of the proxy
69
-     *
70
-     * @return bool
71
-     */
72
-    public function isProxyInitialized() : bool
73
-    {
74
-        return $this->relationshipLoaded;
75
-    }
76
-
77
-    /**
78
-     * Get all of the items in the collection.
79
-     *
80
-     * @return array
81
-     */
82
-    public function all()
83
-    {
84
-    	$this->initializeProxy();
85
-
86
-        return parent::all();
87
-    }
88
-
89
-    /**
90
-     * Get the average value of a given key.
91
-     *
92
-     * @param  callable|string|null  $callback
93
-     * @return mixed
94
-     */
95
-    public function avg($callback = null)
96
-    {
97
-        $this->initializeProxy();
98
-
99
-        return parent::avg($callback);
100
-    }
101
-
102
-    /**
103
-     * Get the median of a given key.
104
-     *
105
-     * @param  null $key
106
-     * @return mixed|null
107
-     */
108
-    public function median($key = null)
109
-    {
110
-        $this->initializeProxy();
111
-
112
-        return parent::median($key);
113
-    }
114
-
115
-    /**
116
-     * Get the mode of a given key.
117
-     *
118
-     * @param  mixed  $key
119
-     * @return array
120
-     */
121
-    public function mode($key = null)
122
-    {
123
-        $this->initializeProxy();
124
-
125
-        return parent::mode($key);
126
-    }
127
-
128
-    /**
129
-     * Collapse the collection of items into a single array.
130
-     *
131
-     * @return static
132
-     */
133
-    public function collapse()
134
-    {
135
-    	$this->initializeProxy();
136
-
137
-        return parent::collapse();
138
-    }
139
-
140
-    /**
141
-     * Determine if an item exists in the collection.
142
-     *
143
-     * @param  mixed  $key
144
-     * @param  mixed  $value
145
-     * @return bool
146
-     */
147
-    public function contains($key, $value = null)
148
-    {
149
-        $this->initializeProxy();
150
-
151
-        return parent::contains($key, $value);
152
-    }
153
-
154
-    /**
155
-     * Determine if an item exists in the collection using strict comparison.
156
-     *
157
-     * @param  mixed  $key
158
-     * @param  mixed  $value
159
-     * @return bool
160
-     */
161
-    public function containsStrict($key, $value = null)
162
-    {
163
-        $this->initializeProxy();
164
-
165
-        return parent::containsStrict($key, $value);
166
-    }
167
-
168
-    /**
169
-     * Get the items in the collection that are not present in the given items.
170
-     *
171
-     * @param  mixed  $items
172
-     * @return static
173
-     */
174
-    public function diff($items)
175
-    {
176
-        $this->initializeProxy();
177
-
178
-        return parent::diff($items);
179
-    }
180
-
181
-    /**
182
-     * Get the items in the collection whose keys are not present in the given items.
183
-     *
184
-     * @param  mixed  $items
185
-     * @return static
186
-     */
187
-    public function diffKeys($items)
188
-    {
189
-        $this->initializeProxy();
190
-
191
-        return parent::diffKeys($items);
192
-    }
193
-
194
-    /**
195
-     * Execute a callback over each item.
196
-     *
197
-     * @param  callable  $callback
198
-     * @return $this
199
-     */
200
-    public function each(callable $callback)
201
-    {
202
-        $this->initializeProxy();
203
-
204
-        return parent::each($callback);
205
-    }
206
-
207
-    /**
208
-     * Create a new collection consisting of every n-th element.
209
-     *
210
-     * @param  int  $step
211
-     * @param  int  $offset
212
-     * @return static
213
-     */
214
-    public function every($step, $offset = 0)
215
-    {
216
-        $this->initializeProxy();
217
-
218
-        return parent::every($step, $offset);
219
-    }
220
-
221
-    /**
222
-     * Get all items except for those with the specified keys.
223
-     *
224
-     * @param  mixed  $keys
225
-     * @return static
226
-     */
227
-    public function except($keys)
228
-    {
229
-        $this->initializeProxy();
230
-
231
-        return parent::except($keys);
232
-    }
233
-
234
-    /**
235
-     * Run a filter over each of the items.
236
-     *
237
-     * @param  callable|null  $callback
238
-     * @return static
239
-     */
240
-    public function filter(callable $callback = null)
241
-    {
242
-        $this->initializeProxy();
243
-
244
-        return parent::filter($callback);
245
-    }
246
-
247
-    /**
248
-     * Filter items by the given key value pair.
249
-     *
250
-     * @param  string  $key
251
-     * @param  mixed  $operator
252
-     * @param  mixed  $value
253
-     * @return static
254
-     */
255
-    public function where($key, $operator, $value = null)
256
-    {
257
-        $this->initializeProxy();
258
-
259
-        return parent::where($key, $operator, $value);
260
-    }
261
-
262
-    /**
263
-     * Filter items by the given key value pair using strict comparison.
264
-     *
265
-     * @param  string  $key
266
-     * @param  mixed  $value
267
-     * @return static
268
-     */
269
-    public function whereStrict($key, $value)
270
-    {
271
-        $this->initializeProxy();
272
-
273
-        return parent::whereStrict($key, $value);
274
-    }
275
-
276
-    /**
277
-     * Filter items by the given key value pair.
278
-     *
279
-     * @param  string  $key
280
-     * @param  mixed  $values
281
-     * @param  bool  $strict
282
-     * @return static
283
-     */
284
-    public function whereIn($key, $values, $strict = false)
285
-    {
286
-        $this->initializeProxy();
287
-
288
-        return parent::whereIn($key, $values, $strict);
289
-    }
290
-
291
-    /**
292
-     * Filter items by the given key value pair using strict comparison.
293
-     *
294
-     * @param  string  $key
295
-     * @param  mixed  $values
296
-     * @return static
297
-     */
298
-    public function whereInStrict($key, $values)
299
-    {
300
-    	$this->initializeProxy();
301
-
302
-        return parent::whereInStrict($key, $values);
303
-    }
304
-
305
-    /**
306
-     * Get the first item from the collection.
307
-     *
308
-     * @param  callable|null  $callback
309
-     * @param  mixed  $default
310
-     * @return mixed
311
-     */
312
-    public function first(callable $callback = null, $default = null)
313
-    {
314
-    	// TODO Consider partial loading
315
-    	$this->initializeProxy();
316
-
317
-        return parent::first($callback, $default);
318
-    }
319
-
320
-    /**
321
-     * Get a flattened array of the items in the collection.
322
-     *
323
-     * @param  int  $depth
324
-     * @return static
325
-     */
326
-    public function flatten($depth = INF)
327
-    {
328
-        $this->initializeProxy();
329
-
330
-        return parent::flatten($depth);
331
-    }
332
-
333
-    /**
334
-     * Flip the items in the collection.
335
-     *
336
-     * @return static
337
-     */
338
-    public function flip()
339
-    {
340
-        $this->initializeProxy();
341
-
342
-        return parent::flip();
343
-    }
344
-
345
-    /**
346
-     * Remove an item from the collection by key.
347
-     *
348
-     * @param  string|array  $keys
349
-     * @return $this
350
-     */
351
-    public function forget($keys)
352
-    {
353
-    	// TODO, we could consider these as 
354
-    	// 'pending deletion', the same way that
355
-    	// we treat added items
356
-        $this->initializeProxy();
357
-
358
-        return parent::forget($keys);
359
-    }
360
-
361
-    /**
362
-     * Get an item from the collection by key.
363
-     *
364
-     * @param  mixed  $key
365
-     * @param  mixed  $default
366
-     * @return mixed
367
-     */
368
-    public function get($key, $default = null)
369
-    {
370
-    	// TODO : We could also consider partial loading
371
-    	// here
372
-        $this->initializeProxy();
373
-
374
-        return parent::get($key, $default);
375
-    }
376
-
377
-    /**
378
-     * Group an associative array by a field or using a callback.
379
-     *
380
-     * @param  callable|string  $groupBy
381
-     * @param  bool  $preserveKeys
382
-     * @return static
383
-     */
384
-    public function groupBy($groupBy, $preserveKeys = false)
385
-    {
386
-        $this->initializeProxy();
387
-
388
-        return parent::groupBy($groupBy, $preserveKeys);
389
-    }
390
-
391
-    /**
392
-     * Key an associative array by a field or using a callback.
393
-     *
394
-     * @param  callable|string  $keyBy
395
-     * @return static
396
-     */
397
-    public function keyBy($keyBy)
398
-    {
399
-        $this->initializeProxy();
400
-
401
-        return parent::keyBy($keyBy);
402
-    }
403
-
404
-    /**
405
-     * Determine if an item exists in the collection by key.
406
-     *
407
-     * @param  mixed  $key
408
-     * @return bool
409
-     */
410
-    public function has($key)
411
-    {
412
-    	// TODO : we could do automagic here by directly
413
-    	// calling the database if the collection hasn't 
414
-    	// been initialized yet. 
415
-    	// Potential issue is that several calls to this
416
-    	// could cause a lot queries vs a single get query.
417
-        $this->initializeProxy();
418
-
419
-        return parent::has($key);
420
-    }
421
-
422
-    /**
423
-     * Concatenate values of a given key as a string.
424
-     *
425
-     * @param  string  $value
426
-     * @param  string  $glue
427
-     * @return string
428
-     */
429
-    public function implode($value, $glue = null)
430
-    {
431
-        $this->initializeProxy();
432
-
433
-        return parent::implode($value, $glue);
434
-    }
435
-
436
-    /**
437
-     * Intersect the collection with the given items.
438
-     *
439
-     * @param  mixed  $items
440
-     * @return static
441
-     */
442
-    public function intersect($items)
443
-    {
444
-        $this->initializeProxy();
445
-
446
-        return parent::intersect($items);
447
-    }
448
-
449
-    /**
450
-     * Determine if the collection is empty or not.
451
-     *
452
-     * @return bool
453
-     */
454
-    public function isEmpty()
455
-    {
456
-        $this->initializeProxy();
457
-
458
-        return parent::isEmpty();
459
-    }
460
-
461
-    /**
462
-     * Get the keys of the collection items.
463
-     *
464
-     * @return static
465
-     */
466
-    public function keys()
467
-    {
468
-        $this->initializeProxy();
469
-
470
-        return parent::keys();
471
-    }
472
-
473
-    /**
474
-     * Get the last item from the collection.
475
-     *
476
-     * @param  callable|null  $callback
477
-     * @param  mixed  $default
478
-     * @return mixed
479
-     */
480
-    public function last(callable $callback = null, $default = null)
481
-    {
482
-    	// TODO : we could do partial loading there as well
483
-        $this->initializeProxy();
484
-
485
-        return parent::last($callback, $default);
486
-    }
487
-
488
-    /**
489
-     * Get the values of a given key.
490
-     *
491
-     * @param  string  $value
492
-     * @param  string|null  $key
493
-     * @return static
494
-     */
495
-    public function pluck($value, $key = null)
496
-    {
497
-    	// TODO : automagic call to QB if not initialized
498
-        $this->initializeProxy();
499
-
500
-        return parent::pluck($value, $key);
501
-    }
502
-
503
-    /**
504
-     * Run a map over each of the items.
505
-     *
506
-     * @param  callable  $callback
507
-     * @return static
508
-     */
509
-    public function map(callable $callback)
510
-    {
511
-        $this->initializeProxy();
512
-
513
-        return parent::map($callback);
514
-    }
515
-
516
-    /**
517
-     * Run an associative map over each of the items.
518
-     *
519
-     * The callback should return an associative array with a single key/value pair.
520
-     *
521
-     * @param  callable  $callback
522
-     * @return static
523
-     */
524
-    public function mapWithKeys(callable $callback)
525
-    {
526
-        $this->initializeProxy();
527
-
528
-        return parent::mapWithKeys($callback);
529
-    }
530
-
531
-    /**
532
-     * Map a collection and flatten the result by a single level.
533
-     *
534
-     * @param  callable  $callback
535
-     * @return static
536
-     */
537
-    public function flatMap(callable $callback)
538
-    {
539
-        $this->initializeProxy();
540
-
541
-        return parent::flatMap($callback);
542
-    }
543
-
544
-    /**
545
-     * Get the max value of a given key.
546
-     *
547
-     * @param  callable|string|null  $callback
548
-     * @return mixed
549
-     */
550
-    public function max($callback = null)
551
-    {
552
-        $this->initializeProxy();
553
-
554
-        return parent::max($callback);
555
-    }
556
-
557
-    /**
558
-     * Merge the collection with the given items.
559
-     *
560
-     * @param  mixed  $items
561
-     * @return static
562
-     */
563
-    public function merge($items)
564
-    {
565
-    	// TODO : Check if the EntityCollection
566
-    	// returns a native Collection, as it 
567
-    	// is what we want here
568
-        $this->initializeProxy();
569
-
570
-        return parent::merge($items);
571
-    }
572
-
573
-    /**
574
-     * Create a collection by using this collection for keys and another for its values.
575
-     *
576
-     * @param  mixed  $values
577
-     * @return static
578
-     */
579
-    public function combine($values)
580
-    {
581
-        // TODO : Check if the EntityCollection
582
-    	// returns a native Collection, as it 
583
-    	// is what we want here
584
-        $this->initializeProxy();
585
-
586
-        return parent::combine($values);
587
-    }
588
-
589
-    /**
590
-     * Union the collection with the given items.
591
-     *
592
-     * @param  mixed  $items
593
-     * @return static
594
-     */
595
-    public function union($items)
596
-    {
597
-        // TODO : Check if the EntityCollection
598
-    	// returns a native Collection, as it 
599
-    	// is what we want here
600
-        $this->initializeProxy();
601
-
602
-        return parent::union($items);
603
-    }
604
-
605
-    /**
606
-     * Get the min value of a given key.
607
-     *
608
-     * @param  callable|string|null  $callback
609
-     * @return mixed
610
-     */
611
-    public function min($callback = null)
612
-    {
613
-        // TODO : we could rely on the QB
614
-        // for thos, if initialization has not
615
-        // take place yet
616
-        $this->initializeProxy();
617
-
618
-        return parent::min($callback);
619
-    }
620
-
621
-    /**
622
-     * Get the items with the specified keys.
623
-     *
624
-     * @param  mixed  $keys
625
-     * @return static
626
-     */
627
-    public function only($keys)
628
-    {
629
-        // TODO : we could rely on the QB if
630
-        // the collection hasn't been initialized yet
631
-        $this->initializeProxy();
632
-
633
-        return parent::only($keys);
634
-    }
635
-
636
-    /**
637
-     * "Paginate" the collection by slicing it into a smaller collection.
638
-     *
639
-     * @param  int  $page
640
-     * @param  int  $perPage
641
-     * @return static
642
-     */
643
-    public function forPage($page, $perPage)
644
-    {
645
-    	// TODO : check possibility of partial loading
646
-    	// if not initialized
647
-        $this->initializeProxy();
648
-
649
-        return parent::forPage($page, $perPage);
650
-    }
651
-
652
-    /**
653
-     * Partition the collection into two arrays using the given callback or key.
654
-     *
655
-     * @param  callable|string  $callback
656
-     * @return static
657
-     */
658
-    public function partition($callback)
659
-    {
660
-        $this->initializeProxy();
661
-
662
-        return parent::partition($callback);
663
-    }
664
-
665
-    /**
666
-     * Pass the collection to the given callback and return the result.
667
-     *
668
-     * @param  callable $callback
669
-     * @return mixed
670
-     */
671
-    public function pipe(callable $callback)
672
-    {
673
-        $this->initializeProxy();
674
-
675
-        return parent::pipe($callback);
676
-    }
677
-
678
-    /**
679
-     * Get and remove the last item from the collection.
680
-     *
681
-     * @return mixed
682
-     */
683
-    public function pop()
684
-    {
685
-        $this->initializeProxy();
686
-
687
-        return parent::pop();
688
-    }
689
-
690
-    /**
691
-     * Push an item onto the beginning of the collection.
692
-     *
693
-     * @param  mixed  $value
694
-     * @param  mixed  $key
695
-     * @return $this
696
-     */
697
-    public function prepend($value, $key = null)
698
-    {
699
-    	// TODO : partial adding of values.
700
-    	// we could have a $prepended , and $pushed arrays
701
-    	// which we would combine at full initialization
702
-
703
-        $this->initializeProxy();
704
-
705
-        return parent::prepend($value, $key);
706
-    }
707
-
708
-    /**
709
-     * Push an item onto the end of the collection.
710
-     *
711
-     * @param  mixed  $value
712
-     * @return $this
713
-     */
714
-    public function push($value)
715
-    {
716
-    	// TODO : partial adding of values.
717
-    	// we could have a $prepended , and $pushed arrays
718
-    	// which we would combine at full initialization
55
+		$relation = $this->relationshipMethod;
56
+		$entity = $this->parentEntity;
57
+
58
+		$entityMap = Manager::getMapper($entity)->getEntityMap();
59
+
60
+		$this->items = $entityMap->$relation($entity)->getResults($relation)->all() + $this->addedItems;
61
+
62
+		$this->relationshipLoaded = true;
63
+
64
+		return true;
65
+	}
66
+
67
+	/**
68
+	 * Retrieves current initialization status of the proxy
69
+	 *
70
+	 * @return bool
71
+	 */
72
+	public function isProxyInitialized() : bool
73
+	{
74
+		return $this->relationshipLoaded;
75
+	}
76
+
77
+	/**
78
+	 * Get all of the items in the collection.
79
+	 *
80
+	 * @return array
81
+	 */
82
+	public function all()
83
+	{
84
+		$this->initializeProxy();
85
+
86
+		return parent::all();
87
+	}
88
+
89
+	/**
90
+	 * Get the average value of a given key.
91
+	 *
92
+	 * @param  callable|string|null  $callback
93
+	 * @return mixed
94
+	 */
95
+	public function avg($callback = null)
96
+	{
97
+		$this->initializeProxy();
98
+
99
+		return parent::avg($callback);
100
+	}
101
+
102
+	/**
103
+	 * Get the median of a given key.
104
+	 *
105
+	 * @param  null $key
106
+	 * @return mixed|null
107
+	 */
108
+	public function median($key = null)
109
+	{
110
+		$this->initializeProxy();
111
+
112
+		return parent::median($key);
113
+	}
114
+
115
+	/**
116
+	 * Get the mode of a given key.
117
+	 *
118
+	 * @param  mixed  $key
119
+	 * @return array
120
+	 */
121
+	public function mode($key = null)
122
+	{
123
+		$this->initializeProxy();
124
+
125
+		return parent::mode($key);
126
+	}
127
+
128
+	/**
129
+	 * Collapse the collection of items into a single array.
130
+	 *
131
+	 * @return static
132
+	 */
133
+	public function collapse()
134
+	{
135
+		$this->initializeProxy();
136
+
137
+		return parent::collapse();
138
+	}
139
+
140
+	/**
141
+	 * Determine if an item exists in the collection.
142
+	 *
143
+	 * @param  mixed  $key
144
+	 * @param  mixed  $value
145
+	 * @return bool
146
+	 */
147
+	public function contains($key, $value = null)
148
+	{
149
+		$this->initializeProxy();
150
+
151
+		return parent::contains($key, $value);
152
+	}
153
+
154
+	/**
155
+	 * Determine if an item exists in the collection using strict comparison.
156
+	 *
157
+	 * @param  mixed  $key
158
+	 * @param  mixed  $value
159
+	 * @return bool
160
+	 */
161
+	public function containsStrict($key, $value = null)
162
+	{
163
+		$this->initializeProxy();
164
+
165
+		return parent::containsStrict($key, $value);
166
+	}
167
+
168
+	/**
169
+	 * Get the items in the collection that are not present in the given items.
170
+	 *
171
+	 * @param  mixed  $items
172
+	 * @return static
173
+	 */
174
+	public function diff($items)
175
+	{
176
+		$this->initializeProxy();
177
+
178
+		return parent::diff($items);
179
+	}
180
+
181
+	/**
182
+	 * Get the items in the collection whose keys are not present in the given items.
183
+	 *
184
+	 * @param  mixed  $items
185
+	 * @return static
186
+	 */
187
+	public function diffKeys($items)
188
+	{
189
+		$this->initializeProxy();
190
+
191
+		return parent::diffKeys($items);
192
+	}
193
+
194
+	/**
195
+	 * Execute a callback over each item.
196
+	 *
197
+	 * @param  callable  $callback
198
+	 * @return $this
199
+	 */
200
+	public function each(callable $callback)
201
+	{
202
+		$this->initializeProxy();
203
+
204
+		return parent::each($callback);
205
+	}
206
+
207
+	/**
208
+	 * Create a new collection consisting of every n-th element.
209
+	 *
210
+	 * @param  int  $step
211
+	 * @param  int  $offset
212
+	 * @return static
213
+	 */
214
+	public function every($step, $offset = 0)
215
+	{
216
+		$this->initializeProxy();
217
+
218
+		return parent::every($step, $offset);
219
+	}
220
+
221
+	/**
222
+	 * Get all items except for those with the specified keys.
223
+	 *
224
+	 * @param  mixed  $keys
225
+	 * @return static
226
+	 */
227
+	public function except($keys)
228
+	{
229
+		$this->initializeProxy();
230
+
231
+		return parent::except($keys);
232
+	}
233
+
234
+	/**
235
+	 * Run a filter over each of the items.
236
+	 *
237
+	 * @param  callable|null  $callback
238
+	 * @return static
239
+	 */
240
+	public function filter(callable $callback = null)
241
+	{
242
+		$this->initializeProxy();
243
+
244
+		return parent::filter($callback);
245
+	}
246
+
247
+	/**
248
+	 * Filter items by the given key value pair.
249
+	 *
250
+	 * @param  string  $key
251
+	 * @param  mixed  $operator
252
+	 * @param  mixed  $value
253
+	 * @return static
254
+	 */
255
+	public function where($key, $operator, $value = null)
256
+	{
257
+		$this->initializeProxy();
258
+
259
+		return parent::where($key, $operator, $value);
260
+	}
261
+
262
+	/**
263
+	 * Filter items by the given key value pair using strict comparison.
264
+	 *
265
+	 * @param  string  $key
266
+	 * @param  mixed  $value
267
+	 * @return static
268
+	 */
269
+	public function whereStrict($key, $value)
270
+	{
271
+		$this->initializeProxy();
272
+
273
+		return parent::whereStrict($key, $value);
274
+	}
275
+
276
+	/**
277
+	 * Filter items by the given key value pair.
278
+	 *
279
+	 * @param  string  $key
280
+	 * @param  mixed  $values
281
+	 * @param  bool  $strict
282
+	 * @return static
283
+	 */
284
+	public function whereIn($key, $values, $strict = false)
285
+	{
286
+		$this->initializeProxy();
287
+
288
+		return parent::whereIn($key, $values, $strict);
289
+	}
290
+
291
+	/**
292
+	 * Filter items by the given key value pair using strict comparison.
293
+	 *
294
+	 * @param  string  $key
295
+	 * @param  mixed  $values
296
+	 * @return static
297
+	 */
298
+	public function whereInStrict($key, $values)
299
+	{
300
+		$this->initializeProxy();
301
+
302
+		return parent::whereInStrict($key, $values);
303
+	}
304
+
305
+	/**
306
+	 * Get the first item from the collection.
307
+	 *
308
+	 * @param  callable|null  $callback
309
+	 * @param  mixed  $default
310
+	 * @return mixed
311
+	 */
312
+	public function first(callable $callback = null, $default = null)
313
+	{
314
+		// TODO Consider partial loading
315
+		$this->initializeProxy();
316
+
317
+		return parent::first($callback, $default);
318
+	}
319
+
320
+	/**
321
+	 * Get a flattened array of the items in the collection.
322
+	 *
323
+	 * @param  int  $depth
324
+	 * @return static
325
+	 */
326
+	public function flatten($depth = INF)
327
+	{
328
+		$this->initializeProxy();
329
+
330
+		return parent::flatten($depth);
331
+	}
332
+
333
+	/**
334
+	 * Flip the items in the collection.
335
+	 *
336
+	 * @return static
337
+	 */
338
+	public function flip()
339
+	{
340
+		$this->initializeProxy();
341
+
342
+		return parent::flip();
343
+	}
344
+
345
+	/**
346
+	 * Remove an item from the collection by key.
347
+	 *
348
+	 * @param  string|array  $keys
349
+	 * @return $this
350
+	 */
351
+	public function forget($keys)
352
+	{
353
+		// TODO, we could consider these as 
354
+		// 'pending deletion', the same way that
355
+		// we treat added items
356
+		$this->initializeProxy();
357
+
358
+		return parent::forget($keys);
359
+	}
360
+
361
+	/**
362
+	 * Get an item from the collection by key.
363
+	 *
364
+	 * @param  mixed  $key
365
+	 * @param  mixed  $default
366
+	 * @return mixed
367
+	 */
368
+	public function get($key, $default = null)
369
+	{
370
+		// TODO : We could also consider partial loading
371
+		// here
372
+		$this->initializeProxy();
373
+
374
+		return parent::get($key, $default);
375
+	}
376
+
377
+	/**
378
+	 * Group an associative array by a field or using a callback.
379
+	 *
380
+	 * @param  callable|string  $groupBy
381
+	 * @param  bool  $preserveKeys
382
+	 * @return static
383
+	 */
384
+	public function groupBy($groupBy, $preserveKeys = false)
385
+	{
386
+		$this->initializeProxy();
387
+
388
+		return parent::groupBy($groupBy, $preserveKeys);
389
+	}
390
+
391
+	/**
392
+	 * Key an associative array by a field or using a callback.
393
+	 *
394
+	 * @param  callable|string  $keyBy
395
+	 * @return static
396
+	 */
397
+	public function keyBy($keyBy)
398
+	{
399
+		$this->initializeProxy();
400
+
401
+		return parent::keyBy($keyBy);
402
+	}
403
+
404
+	/**
405
+	 * Determine if an item exists in the collection by key.
406
+	 *
407
+	 * @param  mixed  $key
408
+	 * @return bool
409
+	 */
410
+	public function has($key)
411
+	{
412
+		// TODO : we could do automagic here by directly
413
+		// calling the database if the collection hasn't 
414
+		// been initialized yet. 
415
+		// Potential issue is that several calls to this
416
+		// could cause a lot queries vs a single get query.
417
+		$this->initializeProxy();
418
+
419
+		return parent::has($key);
420
+	}
421
+
422
+	/**
423
+	 * Concatenate values of a given key as a string.
424
+	 *
425
+	 * @param  string  $value
426
+	 * @param  string  $glue
427
+	 * @return string
428
+	 */
429
+	public function implode($value, $glue = null)
430
+	{
431
+		$this->initializeProxy();
432
+
433
+		return parent::implode($value, $glue);
434
+	}
435
+
436
+	/**
437
+	 * Intersect the collection with the given items.
438
+	 *
439
+	 * @param  mixed  $items
440
+	 * @return static
441
+	 */
442
+	public function intersect($items)
443
+	{
444
+		$this->initializeProxy();
445
+
446
+		return parent::intersect($items);
447
+	}
448
+
449
+	/**
450
+	 * Determine if the collection is empty or not.
451
+	 *
452
+	 * @return bool
453
+	 */
454
+	public function isEmpty()
455
+	{
456
+		$this->initializeProxy();
457
+
458
+		return parent::isEmpty();
459
+	}
460
+
461
+	/**
462
+	 * Get the keys of the collection items.
463
+	 *
464
+	 * @return static
465
+	 */
466
+	public function keys()
467
+	{
468
+		$this->initializeProxy();
469
+
470
+		return parent::keys();
471
+	}
472
+
473
+	/**
474
+	 * Get the last item from the collection.
475
+	 *
476
+	 * @param  callable|null  $callback
477
+	 * @param  mixed  $default
478
+	 * @return mixed
479
+	 */
480
+	public function last(callable $callback = null, $default = null)
481
+	{
482
+		// TODO : we could do partial loading there as well
483
+		$this->initializeProxy();
484
+
485
+		return parent::last($callback, $default);
486
+	}
487
+
488
+	/**
489
+	 * Get the values of a given key.
490
+	 *
491
+	 * @param  string  $value
492
+	 * @param  string|null  $key
493
+	 * @return static
494
+	 */
495
+	public function pluck($value, $key = null)
496
+	{
497
+		// TODO : automagic call to QB if not initialized
498
+		$this->initializeProxy();
499
+
500
+		return parent::pluck($value, $key);
501
+	}
502
+
503
+	/**
504
+	 * Run a map over each of the items.
505
+	 *
506
+	 * @param  callable  $callback
507
+	 * @return static
508
+	 */
509
+	public function map(callable $callback)
510
+	{
511
+		$this->initializeProxy();
512
+
513
+		return parent::map($callback);
514
+	}
515
+
516
+	/**
517
+	 * Run an associative map over each of the items.
518
+	 *
519
+	 * The callback should return an associative array with a single key/value pair.
520
+	 *
521
+	 * @param  callable  $callback
522
+	 * @return static
523
+	 */
524
+	public function mapWithKeys(callable $callback)
525
+	{
526
+		$this->initializeProxy();
527
+
528
+		return parent::mapWithKeys($callback);
529
+	}
530
+
531
+	/**
532
+	 * Map a collection and flatten the result by a single level.
533
+	 *
534
+	 * @param  callable  $callback
535
+	 * @return static
536
+	 */
537
+	public function flatMap(callable $callback)
538
+	{
539
+		$this->initializeProxy();
540
+
541
+		return parent::flatMap($callback);
542
+	}
543
+
544
+	/**
545
+	 * Get the max value of a given key.
546
+	 *
547
+	 * @param  callable|string|null  $callback
548
+	 * @return mixed
549
+	 */
550
+	public function max($callback = null)
551
+	{
552
+		$this->initializeProxy();
553
+
554
+		return parent::max($callback);
555
+	}
556
+
557
+	/**
558
+	 * Merge the collection with the given items.
559
+	 *
560
+	 * @param  mixed  $items
561
+	 * @return static
562
+	 */
563
+	public function merge($items)
564
+	{
565
+		// TODO : Check if the EntityCollection
566
+		// returns a native Collection, as it 
567
+		// is what we want here
568
+		$this->initializeProxy();
569
+
570
+		return parent::merge($items);
571
+	}
572
+
573
+	/**
574
+	 * Create a collection by using this collection for keys and another for its values.
575
+	 *
576
+	 * @param  mixed  $values
577
+	 * @return static
578
+	 */
579
+	public function combine($values)
580
+	{
581
+		// TODO : Check if the EntityCollection
582
+		// returns a native Collection, as it 
583
+		// is what we want here
584
+		$this->initializeProxy();
585
+
586
+		return parent::combine($values);
587
+	}
588
+
589
+	/**
590
+	 * Union the collection with the given items.
591
+	 *
592
+	 * @param  mixed  $items
593
+	 * @return static
594
+	 */
595
+	public function union($items)
596
+	{
597
+		// TODO : Check if the EntityCollection
598
+		// returns a native Collection, as it 
599
+		// is what we want here
600
+		$this->initializeProxy();
601
+
602
+		return parent::union($items);
603
+	}
604
+
605
+	/**
606
+	 * Get the min value of a given key.
607
+	 *
608
+	 * @param  callable|string|null  $callback
609
+	 * @return mixed
610
+	 */
611
+	public function min($callback = null)
612
+	{
613
+		// TODO : we could rely on the QB
614
+		// for thos, if initialization has not
615
+		// take place yet
616
+		$this->initializeProxy();
617
+
618
+		return parent::min($callback);
619
+	}
620
+
621
+	/**
622
+	 * Get the items with the specified keys.
623
+	 *
624
+	 * @param  mixed  $keys
625
+	 * @return static
626
+	 */
627
+	public function only($keys)
628
+	{
629
+		// TODO : we could rely on the QB if
630
+		// the collection hasn't been initialized yet
631
+		$this->initializeProxy();
632
+
633
+		return parent::only($keys);
634
+	}
635
+
636
+	/**
637
+	 * "Paginate" the collection by slicing it into a smaller collection.
638
+	 *
639
+	 * @param  int  $page
640
+	 * @param  int  $perPage
641
+	 * @return static
642
+	 */
643
+	public function forPage($page, $perPage)
644
+	{
645
+		// TODO : check possibility of partial loading
646
+		// if not initialized
647
+		$this->initializeProxy();
648
+
649
+		return parent::forPage($page, $perPage);
650
+	}
651
+
652
+	/**
653
+	 * Partition the collection into two arrays using the given callback or key.
654
+	 *
655
+	 * @param  callable|string  $callback
656
+	 * @return static
657
+	 */
658
+	public function partition($callback)
659
+	{
660
+		$this->initializeProxy();
661
+
662
+		return parent::partition($callback);
663
+	}
664
+
665
+	/**
666
+	 * Pass the collection to the given callback and return the result.
667
+	 *
668
+	 * @param  callable $callback
669
+	 * @return mixed
670
+	 */
671
+	public function pipe(callable $callback)
672
+	{
673
+		$this->initializeProxy();
674
+
675
+		return parent::pipe($callback);
676
+	}
677
+
678
+	/**
679
+	 * Get and remove the last item from the collection.
680
+	 *
681
+	 * @return mixed
682
+	 */
683
+	public function pop()
684
+	{
685
+		$this->initializeProxy();
686
+
687
+		return parent::pop();
688
+	}
689
+
690
+	/**
691
+	 * Push an item onto the beginning of the collection.
692
+	 *
693
+	 * @param  mixed  $value
694
+	 * @param  mixed  $key
695
+	 * @return $this
696
+	 */
697
+	public function prepend($value, $key = null)
698
+	{
699
+		// TODO : partial adding of values.
700
+		// we could have a $prepended , and $pushed arrays
701
+		// which we would combine at full initialization
702
+
703
+		$this->initializeProxy();
704
+
705
+		return parent::prepend($value, $key);
706
+	}
707
+
708
+	/**
709
+	 * Push an item onto the end of the collection.
710
+	 *
711
+	 * @param  mixed  $value
712
+	 * @return $this
713
+	 */
714
+	public function push($value)
715
+	{
716
+		// TODO : partial adding of values.
717
+		// we could have a $prepended , and $pushed arrays
718
+		// which we would combine at full initialization
719 719
   
720
-        $this->initializeProxy();
721
-
722
-        return parent::push($value);
723
-    }
724
-
725
-    /**
726
-     * Get and remove an item from the collection.
727
-     *
728
-     * @param  mixed  $key
729
-     * @param  mixed  $default
730
-     * @return mixed
731
-     */
732
-    public function pull($key, $default = null)
733
-    {
734
-    	// TODO : QB query if the collection
735
-    	// hasn't been initialized yet
736
-
737
-        $this->initializeProxy();
738
-
739
-        return parent::pull($key, $default);
740
-    }
741
-
742
-    /**
743
-     * Put an item in the collection by key.
744
-     *
745
-     * @param  mixed  $key
746
-     * @param  mixed  $value
747
-     * @return $this
748
-     */
749
-    public function put($key, $value)
750
-    {
751
-        // TODO : Partial loading ?
752
-
753
-        $this->initializeProxy();
754
-
755
-        return parent::put($key, $value);
756
-    }
757
-
758
-    /**
759
-     * Get one or more items randomly from the collection.
760
-     *
761
-     * @param  int  $amount
762
-     * @return mixed
763
-     *
764
-     * @throws \InvalidArgumentException
765
-     */
766
-    public function random($amount = 1)
767
-    {
768
-    	// TODO : we could optimize this by only 
769
-    	// fetching the keys from the database
770
-    	// and performing partial loading
771
-
772
-        $this->initializeProxy();
773
-
774
-        return parent::random($amount);
775
-    }
776
-
777
-    /**
778
-     * Reduce the collection to a single value.
779
-     *
780
-     * @param  callable  $callback
781
-     * @param  mixed     $initial
782
-     * @return mixed
783
-     */
784
-    public function reduce(callable $callback, $initial = null)
785
-    {
786
-        $this->initializeProxy();
787
-
788
-        return parent::reduce($callback, $initial);
789
-    }
790
-
791
-    /**
792
-     * Create a collection of all elements that do not pass a given truth test.
793
-     *
794
-     * @param  callable|mixed  $callback
795
-     * @return static
796
-     */
797
-    public function reject($callback)
798
-    {
799
-        $this->initializeProxy();
800
-
801
-        return parent::reject($callback);
802
-    }
803
-
804
-    /**
805
-     * Reverse items order.
806
-     *
807
-     * @return static
808
-     */
809
-    public function reverse()
810
-    {
811
-        $this->initializeProxy();
812
-
813
-        return parent::reverse();
814
-    }
815
-
816
-    /**
817
-     * Search the collection for a given value and return the corresponding key if successful.
818
-     *
819
-     * @param  mixed  $value
820
-     * @param  bool   $strict
821
-     * @return mixed
822
-     */
823
-    public function search($value, $strict = false)
824
-    {
825
-        $this->initializeProxy();
826
-
827
-        return parent::search($value, $strict);
828
-    }
829
-
830
-    /**
831
-     * Get and remove the first item from the collection.
832
-     *
833
-     * @return mixed
834
-     */
835
-    public function shift()
836
-    {
837
-    	// Todo : Partial Removing
838
-    	// we could have a pending removal array
839
-        $this->initializeProxy();
840
-
841
-        return parent::shift();
842
-    }
843
-
844
-    /**
845
-     * Shuffle the items in the collection.
846
-     *
847
-     * @param int $seed
848
-     * @return static
849
-     */
850
-    public function shuffle($seed = null)
851
-    {
852
-    	$this->initializeProxy();
853
-
854
-        return parent::shuffle($seed);
855
-    }
856
-
857
-    /**
858
-     * Slice the underlying collection array.
859
-     *
860
-     * @param  int   $offset
861
-     * @param  int   $length
862
-     * @return static
863
-     */
864
-    public function slice($offset, $length = null)
865
-    {
866
-        $this->initializeProxy();
867
-
868
-        return parent::slice($offset, $length);
869
-    }
870
-
871
-    /**
872
-     * Split a collection into a certain number of groups.
873
-     *
874
-     * @param  int  $numberOfGroups
875
-     * @return static
876
-     */
877
-    public function split($numberOfGroups)
878
-    {
879
-        $this->initializeProxy();
880
-
881
-        return parent::split($numberOfGroups);
882
-    }
883
-
884
-    /**
885
-     * Chunk the underlying collection array.
886
-     *
887
-     * @param  int   $size
888
-     * @return static
889
-     */
890
-    public function chunk($size)
891
-    {
892
-    	// TODO : partial loading ?
893
-        $this->initializeProxy();
894
-
895
-        return parent::chunk($size);
896
-    }
897
-
898
-    /**
899
-     * Sort through each item with a callback.
900
-     *
901
-     * @param  callable|null  $callback
902
-     * @return static
903
-     */
904
-    public function sort(callable $callback = null)
905
-    {
906
-        $this->initializeProxy();
907
-
908
-        return parent::sort($callback);
909
-    }
910
-
911
-    /**
912
-     * Sort the collection using the given callback.
913
-     *
914
-     * @param  callable|string  $callback
915
-     * @param  int   $options
916
-     * @param  bool  $descending
917
-     * @return static
918
-     */
919
-    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
920
-    {
921
-        $this->initializeProxy();
922
-
923
-        return parent::sort($callback, $options, $descending);
924
-    }
925
-
926
-    /**
927
-     * Splice a portion of the underlying collection array.
928
-     *
929
-     * @param  int  $offset
930
-     * @param  int|null  $length
931
-     * @param  mixed  $replacement
932
-     * @return static
933
-     */
934
-    public function splice($offset, $length = null, $replacement = [])
935
-    {
936
-        $this->initializeProxy();
937
-
938
-        return parent::splice($offset, $length, $replacement);
939
-    }
940
-
941
-    /**
942
-     * Get the sum of the given values.
943
-     *
944
-     * @param  callable|string|null  $callback
945
-     * @return mixed
946
-     */
947
-    public function sum($callback = null)
948
-    {
949
-        $this->initializeProxy();
950
-
951
-        return parent::sum($callback);
952
-    }
953
-
954
-    /**
955
-     * Take the first or last {$limit} items.
956
-     *
957
-     * @param  int  $limit
958
-     * @return static
959
-     */
960
-    public function take($limit)
961
-    {	
962
-    	// TODO: partial loading
963
-        $this->initializeProxy();
964
-
965
-        return parent::take($limit);
966
-    }
967
-
968
-    /**
969
-     * Transform each item in the collection using a callback.
970
-     *
971
-     * @param  callable  $callback
972
-     * @return $this
973
-     */
974
-    public function transform(callable $callback)
975
-    {
976
-        $this->initializeProxy();
977
-
978
-        return parent::transform($callback);
979
-    }
980
-
981
-    /**
982
-     * Return only unique items from the collection array.
983
-     *
984
-     * @param  string|callable|null  $key
985
-     * @param  bool  $strict
986
-     *
987
-     * @return static
988
-     */
989
-    public function unique($key = null, $strict = false)
990
-    {
991
-        $this->initializeProxy();
992
-
993
-        return parent::unique($key, $strict);
994
-    }
995
-
996
-    /**
997
-     * Reset the keys on the underlying array.
998
-     *
999
-     * @return static
1000
-     */
1001
-    public function values()
1002
-    {
1003
-        $this->initializeProxy();
1004
-
1005
-        return parent::values();
1006
-    }
1007
-
1008
-    /**
1009
-     * Zip the collection together with one or more arrays.
1010
-     *
1011
-     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1012
-     *      => [[1, 4], [2, 5], [3, 6]]
1013
-     *
1014
-     * @param  mixed ...$items
1015
-     * @return static
1016
-     */
1017
-    public function zip($items)
1018
-    {
1019
-        $this->initializeProxy();
1020
-
1021
-        return parent::zip($items);
1022
-    }
1023
-
1024
-    /**
1025
-     * Get the collection of items as a plain array.
1026
-     *
1027
-     * @return array
1028
-     */
1029
-    public function toArray()
1030
-    {
1031
-    	// If this is called on all subsequent proxy, 
1032
-    	// this would eventually trigger all lazy loading,
1033
-    	// which is NOT what we would expect... 
1034
-    	// TODO : must think of this. 
1035
-        $this->initializeProxy();
1036
-
1037
-        return parent::toArray();
1038
-    }
1039
-
1040
-    /**
1041
-     * Convert the object into something JSON serializable.
1042
-     *
1043
-     * @return array
1044
-     */
1045
-    public function jsonSerialize()
1046
-    {
1047
-        // If this is called on all subsequent proxy, 
1048
-    	// this would eventually trigger all lazy loading,
1049
-    	// which is NOT what we would expect... 
1050
-    	// TODO : must think of this. 
1051
-        $this->initializeProxy();
1052
-
1053
-        return parent::jsonSerialize();
1054
-    }
1055
-
1056
-    /**
1057
-     * Get the collection of items as JSON.
1058
-     *
1059
-     * @param  int  $options
1060
-     * @return string
1061
-     */
1062
-    public function toJson($options = 0)
1063
-    {
1064
-        // If this is called on all subsequent proxy, 
1065
-    	// this would eventually trigger all lazy loading,
1066
-    	// which is NOT what we would expect... 
1067
-    	// TODO : must think of this. 
1068
-        $this->initializeProxy();
1069
-
1070
-        return parent::toJson($options);
1071
-    }
1072
-
1073
-    /**
1074
-     * Get an iterator for the items.
1075
-     *
1076
-     * @return \ArrayIterator
1077
-     */
1078
-    public function getIterator()
1079
-    {
1080
-        $this->initializeProxy();
1081
-
1082
-        return parent::getIterator();
1083
-    }
1084
-
1085
-    /**
1086
-     * Get a CachingIterator instance.
1087
-     *
1088
-     * @param  int  $flags
1089
-     * @return \CachingIterator
1090
-     */
1091
-    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1092
-    {
1093
-        $this->initializeProxy();
1094
-
1095
-        return parent::getCachingIterator($flags);
1096
-    }
1097
-
1098
-    /**
1099
-     * Count the number of items in the collection.
1100
-     *
1101
-     * @return int
1102
-     */
1103
-    public function count()
1104
-    {
1105
-    	// TODO rely on QB if not initialized
1106
-        $this->initializeProxy();
720
+		$this->initializeProxy();
721
+
722
+		return parent::push($value);
723
+	}
724
+
725
+	/**
726
+	 * Get and remove an item from the collection.
727
+	 *
728
+	 * @param  mixed  $key
729
+	 * @param  mixed  $default
730
+	 * @return mixed
731
+	 */
732
+	public function pull($key, $default = null)
733
+	{
734
+		// TODO : QB query if the collection
735
+		// hasn't been initialized yet
736
+
737
+		$this->initializeProxy();
738
+
739
+		return parent::pull($key, $default);
740
+	}
741
+
742
+	/**
743
+	 * Put an item in the collection by key.
744
+	 *
745
+	 * @param  mixed  $key
746
+	 * @param  mixed  $value
747
+	 * @return $this
748
+	 */
749
+	public function put($key, $value)
750
+	{
751
+		// TODO : Partial loading ?
752
+
753
+		$this->initializeProxy();
754
+
755
+		return parent::put($key, $value);
756
+	}
757
+
758
+	/**
759
+	 * Get one or more items randomly from the collection.
760
+	 *
761
+	 * @param  int  $amount
762
+	 * @return mixed
763
+	 *
764
+	 * @throws \InvalidArgumentException
765
+	 */
766
+	public function random($amount = 1)
767
+	{
768
+		// TODO : we could optimize this by only 
769
+		// fetching the keys from the database
770
+		// and performing partial loading
771
+
772
+		$this->initializeProxy();
773
+
774
+		return parent::random($amount);
775
+	}
776
+
777
+	/**
778
+	 * Reduce the collection to a single value.
779
+	 *
780
+	 * @param  callable  $callback
781
+	 * @param  mixed     $initial
782
+	 * @return mixed
783
+	 */
784
+	public function reduce(callable $callback, $initial = null)
785
+	{
786
+		$this->initializeProxy();
787
+
788
+		return parent::reduce($callback, $initial);
789
+	}
790
+
791
+	/**
792
+	 * Create a collection of all elements that do not pass a given truth test.
793
+	 *
794
+	 * @param  callable|mixed  $callback
795
+	 * @return static
796
+	 */
797
+	public function reject($callback)
798
+	{
799
+		$this->initializeProxy();
800
+
801
+		return parent::reject($callback);
802
+	}
803
+
804
+	/**
805
+	 * Reverse items order.
806
+	 *
807
+	 * @return static
808
+	 */
809
+	public function reverse()
810
+	{
811
+		$this->initializeProxy();
812
+
813
+		return parent::reverse();
814
+	}
815
+
816
+	/**
817
+	 * Search the collection for a given value and return the corresponding key if successful.
818
+	 *
819
+	 * @param  mixed  $value
820
+	 * @param  bool   $strict
821
+	 * @return mixed
822
+	 */
823
+	public function search($value, $strict = false)
824
+	{
825
+		$this->initializeProxy();
826
+
827
+		return parent::search($value, $strict);
828
+	}
829
+
830
+	/**
831
+	 * Get and remove the first item from the collection.
832
+	 *
833
+	 * @return mixed
834
+	 */
835
+	public function shift()
836
+	{
837
+		// Todo : Partial Removing
838
+		// we could have a pending removal array
839
+		$this->initializeProxy();
840
+
841
+		return parent::shift();
842
+	}
843
+
844
+	/**
845
+	 * Shuffle the items in the collection.
846
+	 *
847
+	 * @param int $seed
848
+	 * @return static
849
+	 */
850
+	public function shuffle($seed = null)
851
+	{
852
+		$this->initializeProxy();
853
+
854
+		return parent::shuffle($seed);
855
+	}
856
+
857
+	/**
858
+	 * Slice the underlying collection array.
859
+	 *
860
+	 * @param  int   $offset
861
+	 * @param  int   $length
862
+	 * @return static
863
+	 */
864
+	public function slice($offset, $length = null)
865
+	{
866
+		$this->initializeProxy();
867
+
868
+		return parent::slice($offset, $length);
869
+	}
870
+
871
+	/**
872
+	 * Split a collection into a certain number of groups.
873
+	 *
874
+	 * @param  int  $numberOfGroups
875
+	 * @return static
876
+	 */
877
+	public function split($numberOfGroups)
878
+	{
879
+		$this->initializeProxy();
880
+
881
+		return parent::split($numberOfGroups);
882
+	}
883
+
884
+	/**
885
+	 * Chunk the underlying collection array.
886
+	 *
887
+	 * @param  int   $size
888
+	 * @return static
889
+	 */
890
+	public function chunk($size)
891
+	{
892
+		// TODO : partial loading ?
893
+		$this->initializeProxy();
894
+
895
+		return parent::chunk($size);
896
+	}
897
+
898
+	/**
899
+	 * Sort through each item with a callback.
900
+	 *
901
+	 * @param  callable|null  $callback
902
+	 * @return static
903
+	 */
904
+	public function sort(callable $callback = null)
905
+	{
906
+		$this->initializeProxy();
907
+
908
+		return parent::sort($callback);
909
+	}
910
+
911
+	/**
912
+	 * Sort the collection using the given callback.
913
+	 *
914
+	 * @param  callable|string  $callback
915
+	 * @param  int   $options
916
+	 * @param  bool  $descending
917
+	 * @return static
918
+	 */
919
+	public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
920
+	{
921
+		$this->initializeProxy();
922
+
923
+		return parent::sort($callback, $options, $descending);
924
+	}
925
+
926
+	/**
927
+	 * Splice a portion of the underlying collection array.
928
+	 *
929
+	 * @param  int  $offset
930
+	 * @param  int|null  $length
931
+	 * @param  mixed  $replacement
932
+	 * @return static
933
+	 */
934
+	public function splice($offset, $length = null, $replacement = [])
935
+	{
936
+		$this->initializeProxy();
937
+
938
+		return parent::splice($offset, $length, $replacement);
939
+	}
940
+
941
+	/**
942
+	 * Get the sum of the given values.
943
+	 *
944
+	 * @param  callable|string|null  $callback
945
+	 * @return mixed
946
+	 */
947
+	public function sum($callback = null)
948
+	{
949
+		$this->initializeProxy();
950
+
951
+		return parent::sum($callback);
952
+	}
953
+
954
+	/**
955
+	 * Take the first or last {$limit} items.
956
+	 *
957
+	 * @param  int  $limit
958
+	 * @return static
959
+	 */
960
+	public function take($limit)
961
+	{	
962
+		// TODO: partial loading
963
+		$this->initializeProxy();
964
+
965
+		return parent::take($limit);
966
+	}
967
+
968
+	/**
969
+	 * Transform each item in the collection using a callback.
970
+	 *
971
+	 * @param  callable  $callback
972
+	 * @return $this
973
+	 */
974
+	public function transform(callable $callback)
975
+	{
976
+		$this->initializeProxy();
977
+
978
+		return parent::transform($callback);
979
+	}
980
+
981
+	/**
982
+	 * Return only unique items from the collection array.
983
+	 *
984
+	 * @param  string|callable|null  $key
985
+	 * @param  bool  $strict
986
+	 *
987
+	 * @return static
988
+	 */
989
+	public function unique($key = null, $strict = false)
990
+	{
991
+		$this->initializeProxy();
992
+
993
+		return parent::unique($key, $strict);
994
+	}
995
+
996
+	/**
997
+	 * Reset the keys on the underlying array.
998
+	 *
999
+	 * @return static
1000
+	 */
1001
+	public function values()
1002
+	{
1003
+		$this->initializeProxy();
1004
+
1005
+		return parent::values();
1006
+	}
1007
+
1008
+	/**
1009
+	 * Zip the collection together with one or more arrays.
1010
+	 *
1011
+	 * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1012
+	 *      => [[1, 4], [2, 5], [3, 6]]
1013
+	 *
1014
+	 * @param  mixed ...$items
1015
+	 * @return static
1016
+	 */
1017
+	public function zip($items)
1018
+	{
1019
+		$this->initializeProxy();
1020
+
1021
+		return parent::zip($items);
1022
+	}
1023
+
1024
+	/**
1025
+	 * Get the collection of items as a plain array.
1026
+	 *
1027
+	 * @return array
1028
+	 */
1029
+	public function toArray()
1030
+	{
1031
+		// If this is called on all subsequent proxy, 
1032
+		// this would eventually trigger all lazy loading,
1033
+		// which is NOT what we would expect... 
1034
+		// TODO : must think of this. 
1035
+		$this->initializeProxy();
1036
+
1037
+		return parent::toArray();
1038
+	}
1039
+
1040
+	/**
1041
+	 * Convert the object into something JSON serializable.
1042
+	 *
1043
+	 * @return array
1044
+	 */
1045
+	public function jsonSerialize()
1046
+	{
1047
+		// If this is called on all subsequent proxy, 
1048
+		// this would eventually trigger all lazy loading,
1049
+		// which is NOT what we would expect... 
1050
+		// TODO : must think of this. 
1051
+		$this->initializeProxy();
1052
+
1053
+		return parent::jsonSerialize();
1054
+	}
1055
+
1056
+	/**
1057
+	 * Get the collection of items as JSON.
1058
+	 *
1059
+	 * @param  int  $options
1060
+	 * @return string
1061
+	 */
1062
+	public function toJson($options = 0)
1063
+	{
1064
+		// If this is called on all subsequent proxy, 
1065
+		// this would eventually trigger all lazy loading,
1066
+		// which is NOT what we would expect... 
1067
+		// TODO : must think of this. 
1068
+		$this->initializeProxy();
1069
+
1070
+		return parent::toJson($options);
1071
+	}
1072
+
1073
+	/**
1074
+	 * Get an iterator for the items.
1075
+	 *
1076
+	 * @return \ArrayIterator
1077
+	 */
1078
+	public function getIterator()
1079
+	{
1080
+		$this->initializeProxy();
1081
+
1082
+		return parent::getIterator();
1083
+	}
1084
+
1085
+	/**
1086
+	 * Get a CachingIterator instance.
1087
+	 *
1088
+	 * @param  int  $flags
1089
+	 * @return \CachingIterator
1090
+	 */
1091
+	public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
1092
+	{
1093
+		$this->initializeProxy();
1094
+
1095
+		return parent::getCachingIterator($flags);
1096
+	}
1097
+
1098
+	/**
1099
+	 * Count the number of items in the collection.
1100
+	 *
1101
+	 * @return int
1102
+	 */
1103
+	public function count()
1104
+	{
1105
+		// TODO rely on QB if not initialized
1106
+		$this->initializeProxy();
1107 1107
         
1108
-        return parent::count();
1109
-    }
1110
-
1111
-    /**
1112
-     * Get a base Support collection instance from this collection.
1113
-     *
1114
-     * @return \Illuminate\Support\Collection
1115
-     */
1116
-    public function toBase()
1117
-    {
1118
-    	$this->initializeProxy();
1119
-
1120
-        return parent::toBase();
1121
-    }
1122
-
1123
-    /**
1124
-     * Determine if an item exists at an offset.
1125
-     *
1126
-     * @param  mixed  $key
1127
-     * @return bool
1128
-     */
1129
-    public function offsetExists($key)
1130
-    {
1131
-    	// TODO rely on QB if no collection
1132
-    	// initialized
1133
-    	$this->initializeProxy();
1134
-
1135
-        return parent::offsetExists($key);
1136
-    }
1137
-
1138
-    /**
1139
-     * Get an item at a given offset.
1140
-     *
1141
-     * @param  mixed  $key
1142
-     * @return mixed
1143
-     */
1144
-    public function offsetGet($key)
1145
-    {
1146
-    	// TODO rely on partial init if no collection
1147
-    	// initialized
1148
-    	$this->initializeProxy();
1149
-
1150
-        return parent::offsetGet($key);
1151
-    }
1152
-
1153
-    /**
1154
-     * Set the item at a given offset.
1155
-     *
1156
-     * @param  mixed  $key
1157
-     * @param  mixed  $value
1158
-     * @return void
1159
-     */
1160
-    public function offsetSet($key, $value)
1161
-    {
1162
-    	// TODO : think of the use of it into a ProxyCollection
1163
-    	// context
1164
-        $this->initializeProxy();
1165
-
1166
-        return parent::offsetSet($key, $value);
1167
-    }
1168
-
1169
-    /**
1170
-     * Unset the item at a given offset.
1171
-     *
1172
-     * @param  string  $key
1173
-     * @return void
1174
-     */
1175
-    public function offsetUnset($key)
1176
-    {
1177
-        // TODO : think of the use of it into a ProxyCollection
1178
-    	// context
1179
-        $this->initializeProxy();
1180
-
1181
-        return parent::offsetUnset($key);
1182
-    }
1183
-
1184
-    /**
1185
-     * Dynamically handle calls to the class.
1186
-     *
1187
-     * @param  string  $method
1188
-     * @param  array   $parameters
1189
-     * @return mixed
1190
-     *
1191
-     * @throws \BadMethodCallException
1192
-     */
1193
-    public function __call($method, $parameters)
1194
-    {
1195
-        $this->initializeProxy();
1196
-
1197
-        return parent::__call($method, $parameters);
1198
-    }
1108
+		return parent::count();
1109
+	}
1110
+
1111
+	/**
1112
+	 * Get a base Support collection instance from this collection.
1113
+	 *
1114
+	 * @return \Illuminate\Support\Collection
1115
+	 */
1116
+	public function toBase()
1117
+	{
1118
+		$this->initializeProxy();
1119
+
1120
+		return parent::toBase();
1121
+	}
1122
+
1123
+	/**
1124
+	 * Determine if an item exists at an offset.
1125
+	 *
1126
+	 * @param  mixed  $key
1127
+	 * @return bool
1128
+	 */
1129
+	public function offsetExists($key)
1130
+	{
1131
+		// TODO rely on QB if no collection
1132
+		// initialized
1133
+		$this->initializeProxy();
1134
+
1135
+		return parent::offsetExists($key);
1136
+	}
1137
+
1138
+	/**
1139
+	 * Get an item at a given offset.
1140
+	 *
1141
+	 * @param  mixed  $key
1142
+	 * @return mixed
1143
+	 */
1144
+	public function offsetGet($key)
1145
+	{
1146
+		// TODO rely on partial init if no collection
1147
+		// initialized
1148
+		$this->initializeProxy();
1149
+
1150
+		return parent::offsetGet($key);
1151
+	}
1152
+
1153
+	/**
1154
+	 * Set the item at a given offset.
1155
+	 *
1156
+	 * @param  mixed  $key
1157
+	 * @param  mixed  $value
1158
+	 * @return void
1159
+	 */
1160
+	public function offsetSet($key, $value)
1161
+	{
1162
+		// TODO : think of the use of it into a ProxyCollection
1163
+		// context
1164
+		$this->initializeProxy();
1165
+
1166
+		return parent::offsetSet($key, $value);
1167
+	}
1168
+
1169
+	/**
1170
+	 * Unset the item at a given offset.
1171
+	 *
1172
+	 * @param  string  $key
1173
+	 * @return void
1174
+	 */
1175
+	public function offsetUnset($key)
1176
+	{
1177
+		// TODO : think of the use of it into a ProxyCollection
1178
+		// context
1179
+		$this->initializeProxy();
1180
+
1181
+		return parent::offsetUnset($key);
1182
+	}
1183
+
1184
+	/**
1185
+	 * Dynamically handle calls to the class.
1186
+	 *
1187
+	 * @param  string  $method
1188
+	 * @param  array   $parameters
1189
+	 * @return mixed
1190
+	 *
1191
+	 * @throws \BadMethodCallException
1192
+	 */
1193
+	public function __call($method, $parameters)
1194
+	{
1195
+		$this->initializeProxy();
1196
+
1197
+		return parent::__call($method, $parameters);
1198
+	}
1199 1199
 
1200 1200
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@
 block discarded – undo
50 50
      */
51 51
     public function initializeProxy() : bool
52 52
     {
53
-        if($this->isProxyInitialized() ) return true;
53
+        if ($this->isProxyInitialized()) return true;
54 54
         
55 55
         $relation = $this->relationshipMethod;
56 56
         $entity = $this->parentEntity;
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -50,7 +50,9 @@
 block discarded – undo
50 50
      */
51 51
     public function initializeProxy() : bool
52 52
     {
53
-        if($this->isProxyInitialized() ) return true;
53
+        if($this->isProxyInitialized() ) {
54
+        	return true;
55
+        }
54 56
         
55 57
         $relation = $this->relationshipMethod;
56 58
         $entity = $this->parentEntity;
Please login to merge, or discard this patch.