Passed
Push — v2 ( 9961a6...bb80e3 )
by Berend
02:35
created
src/AbstractActiveRecord.php 2 patches
Doc Comments   +5 added lines patch added patch discarded remove patch
@@ -79,6 +79,9 @@  discard block
 block discarded – undo
79 79
 		];
80 80
 	}
81 81
 
82
+	/**
83
+	 * @param string $columnName
84
+	 */
82 85
 	private function checkHookConstraints($columnName, $hookMap)
83 86
 	{
84 87
 		// Check whether column exists
@@ -216,6 +219,8 @@  discard block
 block discarded – undo
216 219
 
217 220
 	/**
218 221
 	 * Returns the type string as it should appear in the mysql create table statement for the given column
222
+	 * @param string $colName
223
+	 * @param string $type
219 224
 	 * @return string The type string
220 225
 	 */
221 226
 	private function getDatabaseTypeString($colName, $type, $length)
Please login to merge, or discard this patch.
Indentation   +706 added lines, -706 removed lines patch added patch discarded remove patch
@@ -18,716 +18,716 @@
 block discarded – undo
18 18
  */
19 19
 abstract class AbstractActiveRecord implements ActiveRecordInterface
20 20
 {
21
-	const COLUMN_NAME_ID = 'id';
22
-	const COLUMN_TYPE_ID = 'INT UNSIGNED';
23
-
24
-	/** @var \PDO The PDO object. */
25
-	protected $pdo;
26
-
27
-	/** @var null|int The ID. */
28
-	private $id;
29
-
30
-	/** @var array A map of column name to functions that hook the insert function */
31
-	protected $registeredCreateHooks;
32
-
33
-	/** @var array A map of column name to functions that hook the read function */
34
-	protected $registeredReadHooks;
35
-
36
-	/** @var array A map of column name to functions that hook the update function */
37
-	protected $registeredUpdateHooks;
38
-
39
-	/** @var array A map of column name to functions that hook the update function */
40
-	protected $registeredDeleteHooks;	
41
-
42
-	/** @var array A map of column name to functions that hook the search function */
43
-	protected $registeredSearchHooks;
44
-
45
-	/** @var array A list of table column definitions */
46
-	protected $tableDefinition;
47
-
48
-	/**
49
-	 * Construct an abstract active record with the given PDO.
50
-	 *
51
-	 * @param \PDO $pdo
52
-	 */
53
-	public function __construct(\PDO $pdo)
54
-	{
55
-		$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
56
-		$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
57
-
58
-		$this->setPdo($pdo);
59
-		$this->tableDefinition = $this->getActiveRecordTableDefinition();
60
-		$this->registeredCreateHooks = [];
61
-		$this->registeredReadHooks = [];
62
-		$this->registeredUpdateHooks = [];
63
-		$this->registeredDeleteHooks = [];
64
-		$this->registeredSearchHooks = [];
65
-
66
-		// Extend table definition with default ID field, throw exception if field already exists
67
-		if (array_key_exists('id', $this->tableDefinition)) {
68
-			$message = "Table definition in record contains a field with name \"id\"";
69
-			$message .= ", which is a reserved name by ActiveRecord";
70
-			throw new ActiveRecordException($message, 0);
71
-		}
72
-
73
-		$this->tableDefinition[self::COLUMN_NAME_ID] =
74
-		[
75
-			'value' => &$this->id,
76
-			'validate' => null,
77
-			'type' => self::COLUMN_TYPE_ID,
78
-			'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE | ColumnProperty::AUTO_INCREMENT | ColumnProperty::PRIMARY_KEY
79
-		];
80
-	}
81
-
82
-	private function checkHookConstraints($columnName, $hookMap)
83
-	{
84
-		// Check whether column exists
85
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
86
-		{
87
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
88
-		}
89
-
90
-		// Enforcing 1 hook per table column
91
-		if (array_key_exists($columnName, $hookMap)) {
92
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
93
-			$message .= "do you have conflicting traits?";
94
-			throw new ActiveRecordException($message, 0);
95
-		}
96
-	}
97
-
98
-	/**
99
-	 * Register a new hook for a specific column that gets called before execution of the create() method
100
-	 * Only one hook per column can be registered at a time
101
-	 * @param string $columnName The name of the column that is registered.
102
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
103
-	 */
104
-	public function registerCreateHook($columnName, $fn)
105
-	{
106
-		$this->checkHookConstraints($columnName, $this->registeredCreateHooks);
107
-
108
-		if (is_string($fn) && is_callable([$this, $fn])) {
109
-			$this->registeredCreateHooks[$columnName] = [$this, $fn];
110
-		} else if (is_callable($fn)) {
111
-			$this->registeredCreateHooks[$columnName] = $fn;
112
-		} else {
113
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
114
-		}
115
-	}
116
-
117
-	/**
118
-	 * Register a new hook for a specific column that gets called before execution of the read() method
119
-	 * Only one hook per column can be registered at a time
120
-	 * @param string $columnName The name of the column that is registered.
121
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
122
-	 */
123
-	public function registerReadHook($columnName, $fn)
124
-	{
125
-		$this->checkHookConstraints($columnName, $this->registeredReadHooks);
126
-
127
-		if (is_string($fn) && is_callable([$this, $fn])) {
128
-			$this->registeredReadHooks[$columnName] = [$this, $fn];
129
-		} else if (is_callable($fn)) {
130
-			$this->registeredReadHooks[$columnName] = $fn;
131
-		} else {
132
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
133
-		}
134
-	}
135
-
136
-
137
-
138
-
139
-	/**
140
-	 * Register a new hook for a specific column that gets called before execution of the update() method
141
-	 * Only one hook per column can be registered at a time
142
-	 * @param string $columnName The name of the column that is registered.
143
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
144
-	 */
145
-	public function registerUpdateHook($columnName, $fn)
146
-	{
147
-		$this->checkHookConstraints($columnName, $this->registeredUpdateHooks);
148
-
149
-		if (is_string($fn) && is_callable([$this, $fn])) {
150
-			$this->registeredUpdateHooks[$columnName] = [$this, $fn];
151
-		} else if (is_callable($fn)) {
152
-			$this->registeredUpdateHooks[$columnName] = $fn;
153
-		} else {
154
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
155
-		}
156
-	}
157
-
158
-	/**
159
-	 * Register a new hook for a specific column that gets called before execution of the delete() method
160
-	 * Only one hook per column can be registered at a time
161
-	 * @param string $columnName The name of the column that is registered.
162
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
163
-	 */
164
-	public function registerDeleteHook($columnName, $fn)
165
-	{
166
-		$this->checkHookConstraints($columnName, $this->registeredDeleteHooks);
167
-
168
-		if (is_string($fn) && is_callable([$this, $fn])) {
169
-			$this->registeredDeleteHooks[$columnName] = [$this, $fn];
170
-		} else if (is_callable($fn)) {
171
-			$this->registeredDeleteHooks[$columnName] = $fn;
172
-		} else {
173
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
174
-		}
175
-	}
176
-
177
-	/**
178
-	 * Register a new hook for a specific column that gets called before execution of the search() method
179
-	 * Only one hook per column can be registered at a time
180
-	 * @param string $columnName The name of the column that is registered.
181
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object. The callable is required to take one argument: an instance of miBadger\Query\Query; 
182
-	 */
183
-	public function registerSearchHook($columnName, $fn)
184
-	{
185
-		$this->checkHookConstraints($columnName, $this->registeredSearchHooks);
186
-
187
-		if (is_string($fn) && is_callable([$this, $fn])) {
188
-			$this->registeredSearchHooks[$columnName] = [$this, $fn];
189
-		} else if (is_callable($fn)) {
190
-			$this->registeredSearchHooks[$columnName] = $fn;
191
-		} else {
192
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
193
-		}
194
-	}
195
-
196
-	/**
197
-	 * Adds a new column definition to the table.
198
-	 * @param string $columnName The name of the column that is registered.
199
-	 * @param Array $definition The definition of that column.
200
-	 */
201
-	public function extendTableDefinition($columnName, $definition)
202
-	{
203
-		if ($this->tableDefinition === null) {
204
-			throw new ActiveRecordException("tableDefinition is null, most likely due to parent class not having been initialized in constructor");
205
-		}
206
-
207
-		// Enforcing table can only be extended with new columns
208
-		if (array_key_exists($columnName, $this->tableDefinition)) {
209
-			$message = "Table is being extended with a column that already exists, ";
210
-			$message .= "\"$columnName\" conflicts with your table definition";
211
-			throw new ActiveRecordException($message, 0);
212
-		}
213
-
214
-		$this->tableDefinition[$columnName] = $definition;
215
-	}
216
-
217
-	/**
218
-	 * Returns the type string as it should appear in the mysql create table statement for the given column
219
-	 * @return string The type string
220
-	 */
221
-	private function getDatabaseTypeString($colName, $type, $length)
222
-	{
223
-		if ($type === null) 
224
-		{
225
-			throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
226
-		}
227
-
228
-		switch (strtoupper($type)) {
229
-			case 'DATETIME':
230
-			case 'DATE':
231
-			case 'TIME':
232
-			case 'TEXT':
233
-			case 'INT UNSIGNED':
234
-				return $type;
235
-
236
-			case 'VARCHAR':
237
-				if ($length === null) {
238
-					throw new ActiveRecordException(sprintf("field type %s requires specified column field \"LENGTH\"", $colName));
239
-				} else {
240
-					return sprintf('%s(%d)', $type, $length);	
241
-				}
242
-
243
-			case 'INT':
244
-			case 'TINYINT':
245
-			case 'BIGINT':
246
-			default: 	
247
-			// @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
248
-				if ($length === null) {
249
-					return $type;
250
-				} else {
251
-					return sprintf('%s(%d)', $type, $length);	
252
-				}
253
-		}
254
-	}
255
-
256
-	/**
257
-	 * Builds the part of a MySQL create table statement that corresponds to the supplied column
258
-	 * @param string $colName 	Name of the database column
259
-	 * @param string $type 		The type of the string
260
-	 * @param int $properties 	The set of Column properties that apply to this column (See ColumnProperty for options)
261
-	 * @return string
262
-	 */
263
-	private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
264
-	{
265
-
266
-		$stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
267
-		if ($properties & ColumnProperty::NOT_NULL) {
268
-			$stmnt .= 'NOT NULL ';
269
-		} else {
270
-			$stmnt .= 'NULL ';
271
-		}
272
-
273
-		if ($default !== NULL) {
274
-			$stmnt .= ' DEFAULT ' . $default . ' ';
275
-		}
276
-
277
-		if ($properties & ColumnProperty::AUTO_INCREMENT) {
278
-			$stmnt .= 'AUTO_INCREMENT ';
279
-		}
280
-
281
-		if ($properties & ColumnProperty::UNIQUE) {
282
-			$stmnt .= 'UNIQUE ';
283
-		}
284
-
285
-		if ($properties & ColumnProperty::PRIMARY_KEY) {
286
-			$stmnt .= 'PRIMARY KEY ';
287
-		}
288
-
289
-		return $stmnt;
290
-	}
291
-
292
-	/**
293
-	 * Sorts the column statement components in the order such that the id appears first, 
294
-	 * 		followed by all other columns in alphabetical ascending order
295
-	 * @param   Array $colStatements Array of column statements
296
-	 * @return  Array
297
-	 */
298
-	private function sortColumnStatements($colStatements)
299
-	{
300
-		// Find ID statement and put it first
301
-		$sortedStatements = [];
302
-
303
-		$sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
304
-		unset($colStatements[self::COLUMN_NAME_ID]);
305
-
306
-		// Sort remaining columns in alphabetical order
307
-		$columns = array_keys($colStatements);
308
-		sort($columns);
309
-		foreach ($columns as $colName) {
310
-			$sortedStatements[] = $colStatements[$colName];
311
-		}
312
-
313
-		return $sortedStatements;
314
-	}
315
-
316
-	/**
317
-	 * Builds the MySQL Create Table statement for the internal table definition
318
-	 * @return string
319
-	 */
320
-	public function buildCreateTableSQL()
321
-	{
322
-		$columnStatements = [];
323
-		foreach ($this->tableDefinition as $colName => $definition) {
324
-			// Destructure column definition
325
-			$type    = $definition['type'] ?? null;
326
-			$default = $definition['default'] ?? null;
327
-			$length  = $definition['length'] ?? null;
328
-			$properties = $definition['properties'] ?? null;
329
-
330
-			if (isset($definition['relation']) && $type !== null) {
331
-				$msg = "Column \"$colName\": ";
332
-				$msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
333
-				throw new ActiveRecordException($msg);
334
-			} else if (isset($definition['relation'])) {
335
-				$type = self::COLUMN_TYPE_ID;
336
-			}
337
-
338
-			$columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
339
-		}
340
-
341
-		// Sort table (first column is id, the remaining are alphabetically sorted)
342
-		$columnStatements = $this->sortColumnStatements($columnStatements);
343
-
344
-		$sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
345
-		$sql .= "(\n";
346
-		$sql .= join($columnStatements, ",\n");
347
-		$sql .= "\n);";
348
-
349
-		return $sql;
350
-	}
351
-
352
-	/**
353
-	 * Creates the entity as a table in the database
354
-	 */
355
-	public function createTable()
356
-	{
357
-		$this->pdo->query($this->buildCreateTableSQL());
358
-	}
359
-
360
-	/**
361
-	 * builds a MySQL constraint statement for the given parameters
362
-	 * @param string $parentTable
363
-	 * @param string $parentColumn
364
-	 * @param string $childTable
365
-	 * @param string $childColumn
366
-	 * @return string The MySQL table constraint string
367
-	 */
368
-	protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
369
-	{
370
-		$template = <<<SQL
21
+    const COLUMN_NAME_ID = 'id';
22
+    const COLUMN_TYPE_ID = 'INT UNSIGNED';
23
+
24
+    /** @var \PDO The PDO object. */
25
+    protected $pdo;
26
+
27
+    /** @var null|int The ID. */
28
+    private $id;
29
+
30
+    /** @var array A map of column name to functions that hook the insert function */
31
+    protected $registeredCreateHooks;
32
+
33
+    /** @var array A map of column name to functions that hook the read function */
34
+    protected $registeredReadHooks;
35
+
36
+    /** @var array A map of column name to functions that hook the update function */
37
+    protected $registeredUpdateHooks;
38
+
39
+    /** @var array A map of column name to functions that hook the update function */
40
+    protected $registeredDeleteHooks;	
41
+
42
+    /** @var array A map of column name to functions that hook the search function */
43
+    protected $registeredSearchHooks;
44
+
45
+    /** @var array A list of table column definitions */
46
+    protected $tableDefinition;
47
+
48
+    /**
49
+     * Construct an abstract active record with the given PDO.
50
+     *
51
+     * @param \PDO $pdo
52
+     */
53
+    public function __construct(\PDO $pdo)
54
+    {
55
+        $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
56
+        $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
57
+
58
+        $this->setPdo($pdo);
59
+        $this->tableDefinition = $this->getActiveRecordTableDefinition();
60
+        $this->registeredCreateHooks = [];
61
+        $this->registeredReadHooks = [];
62
+        $this->registeredUpdateHooks = [];
63
+        $this->registeredDeleteHooks = [];
64
+        $this->registeredSearchHooks = [];
65
+
66
+        // Extend table definition with default ID field, throw exception if field already exists
67
+        if (array_key_exists('id', $this->tableDefinition)) {
68
+            $message = "Table definition in record contains a field with name \"id\"";
69
+            $message .= ", which is a reserved name by ActiveRecord";
70
+            throw new ActiveRecordException($message, 0);
71
+        }
72
+
73
+        $this->tableDefinition[self::COLUMN_NAME_ID] =
74
+        [
75
+            'value' => &$this->id,
76
+            'validate' => null,
77
+            'type' => self::COLUMN_TYPE_ID,
78
+            'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE | ColumnProperty::AUTO_INCREMENT | ColumnProperty::PRIMARY_KEY
79
+        ];
80
+    }
81
+
82
+    private function checkHookConstraints($columnName, $hookMap)
83
+    {
84
+        // Check whether column exists
85
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
86
+        {
87
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
88
+        }
89
+
90
+        // Enforcing 1 hook per table column
91
+        if (array_key_exists($columnName, $hookMap)) {
92
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
93
+            $message .= "do you have conflicting traits?";
94
+            throw new ActiveRecordException($message, 0);
95
+        }
96
+    }
97
+
98
+    /**
99
+     * Register a new hook for a specific column that gets called before execution of the create() method
100
+     * Only one hook per column can be registered at a time
101
+     * @param string $columnName The name of the column that is registered.
102
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
103
+     */
104
+    public function registerCreateHook($columnName, $fn)
105
+    {
106
+        $this->checkHookConstraints($columnName, $this->registeredCreateHooks);
107
+
108
+        if (is_string($fn) && is_callable([$this, $fn])) {
109
+            $this->registeredCreateHooks[$columnName] = [$this, $fn];
110
+        } else if (is_callable($fn)) {
111
+            $this->registeredCreateHooks[$columnName] = $fn;
112
+        } else {
113
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
114
+        }
115
+    }
116
+
117
+    /**
118
+     * Register a new hook for a specific column that gets called before execution of the read() method
119
+     * Only one hook per column can be registered at a time
120
+     * @param string $columnName The name of the column that is registered.
121
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
122
+     */
123
+    public function registerReadHook($columnName, $fn)
124
+    {
125
+        $this->checkHookConstraints($columnName, $this->registeredReadHooks);
126
+
127
+        if (is_string($fn) && is_callable([$this, $fn])) {
128
+            $this->registeredReadHooks[$columnName] = [$this, $fn];
129
+        } else if (is_callable($fn)) {
130
+            $this->registeredReadHooks[$columnName] = $fn;
131
+        } else {
132
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
133
+        }
134
+    }
135
+
136
+
137
+
138
+
139
+    /**
140
+     * Register a new hook for a specific column that gets called before execution of the update() method
141
+     * Only one hook per column can be registered at a time
142
+     * @param string $columnName The name of the column that is registered.
143
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
144
+     */
145
+    public function registerUpdateHook($columnName, $fn)
146
+    {
147
+        $this->checkHookConstraints($columnName, $this->registeredUpdateHooks);
148
+
149
+        if (is_string($fn) && is_callable([$this, $fn])) {
150
+            $this->registeredUpdateHooks[$columnName] = [$this, $fn];
151
+        } else if (is_callable($fn)) {
152
+            $this->registeredUpdateHooks[$columnName] = $fn;
153
+        } else {
154
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
155
+        }
156
+    }
157
+
158
+    /**
159
+     * Register a new hook for a specific column that gets called before execution of the delete() method
160
+     * Only one hook per column can be registered at a time
161
+     * @param string $columnName The name of the column that is registered.
162
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
163
+     */
164
+    public function registerDeleteHook($columnName, $fn)
165
+    {
166
+        $this->checkHookConstraints($columnName, $this->registeredDeleteHooks);
167
+
168
+        if (is_string($fn) && is_callable([$this, $fn])) {
169
+            $this->registeredDeleteHooks[$columnName] = [$this, $fn];
170
+        } else if (is_callable($fn)) {
171
+            $this->registeredDeleteHooks[$columnName] = $fn;
172
+        } else {
173
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
174
+        }
175
+    }
176
+
177
+    /**
178
+     * Register a new hook for a specific column that gets called before execution of the search() method
179
+     * Only one hook per column can be registered at a time
180
+     * @param string $columnName The name of the column that is registered.
181
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object. The callable is required to take one argument: an instance of miBadger\Query\Query; 
182
+     */
183
+    public function registerSearchHook($columnName, $fn)
184
+    {
185
+        $this->checkHookConstraints($columnName, $this->registeredSearchHooks);
186
+
187
+        if (is_string($fn) && is_callable([$this, $fn])) {
188
+            $this->registeredSearchHooks[$columnName] = [$this, $fn];
189
+        } else if (is_callable($fn)) {
190
+            $this->registeredSearchHooks[$columnName] = $fn;
191
+        } else {
192
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
193
+        }
194
+    }
195
+
196
+    /**
197
+     * Adds a new column definition to the table.
198
+     * @param string $columnName The name of the column that is registered.
199
+     * @param Array $definition The definition of that column.
200
+     */
201
+    public function extendTableDefinition($columnName, $definition)
202
+    {
203
+        if ($this->tableDefinition === null) {
204
+            throw new ActiveRecordException("tableDefinition is null, most likely due to parent class not having been initialized in constructor");
205
+        }
206
+
207
+        // Enforcing table can only be extended with new columns
208
+        if (array_key_exists($columnName, $this->tableDefinition)) {
209
+            $message = "Table is being extended with a column that already exists, ";
210
+            $message .= "\"$columnName\" conflicts with your table definition";
211
+            throw new ActiveRecordException($message, 0);
212
+        }
213
+
214
+        $this->tableDefinition[$columnName] = $definition;
215
+    }
216
+
217
+    /**
218
+     * Returns the type string as it should appear in the mysql create table statement for the given column
219
+     * @return string The type string
220
+     */
221
+    private function getDatabaseTypeString($colName, $type, $length)
222
+    {
223
+        if ($type === null) 
224
+        {
225
+            throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
226
+        }
227
+
228
+        switch (strtoupper($type)) {
229
+            case 'DATETIME':
230
+            case 'DATE':
231
+            case 'TIME':
232
+            case 'TEXT':
233
+            case 'INT UNSIGNED':
234
+                return $type;
235
+
236
+            case 'VARCHAR':
237
+                if ($length === null) {
238
+                    throw new ActiveRecordException(sprintf("field type %s requires specified column field \"LENGTH\"", $colName));
239
+                } else {
240
+                    return sprintf('%s(%d)', $type, $length);	
241
+                }
242
+
243
+            case 'INT':
244
+            case 'TINYINT':
245
+            case 'BIGINT':
246
+            default: 	
247
+            // @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
248
+                if ($length === null) {
249
+                    return $type;
250
+                } else {
251
+                    return sprintf('%s(%d)', $type, $length);	
252
+                }
253
+        }
254
+    }
255
+
256
+    /**
257
+     * Builds the part of a MySQL create table statement that corresponds to the supplied column
258
+     * @param string $colName 	Name of the database column
259
+     * @param string $type 		The type of the string
260
+     * @param int $properties 	The set of Column properties that apply to this column (See ColumnProperty for options)
261
+     * @return string
262
+     */
263
+    private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
264
+    {
265
+
266
+        $stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
267
+        if ($properties & ColumnProperty::NOT_NULL) {
268
+            $stmnt .= 'NOT NULL ';
269
+        } else {
270
+            $stmnt .= 'NULL ';
271
+        }
272
+
273
+        if ($default !== NULL) {
274
+            $stmnt .= ' DEFAULT ' . $default . ' ';
275
+        }
276
+
277
+        if ($properties & ColumnProperty::AUTO_INCREMENT) {
278
+            $stmnt .= 'AUTO_INCREMENT ';
279
+        }
280
+
281
+        if ($properties & ColumnProperty::UNIQUE) {
282
+            $stmnt .= 'UNIQUE ';
283
+        }
284
+
285
+        if ($properties & ColumnProperty::PRIMARY_KEY) {
286
+            $stmnt .= 'PRIMARY KEY ';
287
+        }
288
+
289
+        return $stmnt;
290
+    }
291
+
292
+    /**
293
+     * Sorts the column statement components in the order such that the id appears first, 
294
+     * 		followed by all other columns in alphabetical ascending order
295
+     * @param   Array $colStatements Array of column statements
296
+     * @return  Array
297
+     */
298
+    private function sortColumnStatements($colStatements)
299
+    {
300
+        // Find ID statement and put it first
301
+        $sortedStatements = [];
302
+
303
+        $sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
304
+        unset($colStatements[self::COLUMN_NAME_ID]);
305
+
306
+        // Sort remaining columns in alphabetical order
307
+        $columns = array_keys($colStatements);
308
+        sort($columns);
309
+        foreach ($columns as $colName) {
310
+            $sortedStatements[] = $colStatements[$colName];
311
+        }
312
+
313
+        return $sortedStatements;
314
+    }
315
+
316
+    /**
317
+     * Builds the MySQL Create Table statement for the internal table definition
318
+     * @return string
319
+     */
320
+    public function buildCreateTableSQL()
321
+    {
322
+        $columnStatements = [];
323
+        foreach ($this->tableDefinition as $colName => $definition) {
324
+            // Destructure column definition
325
+            $type    = $definition['type'] ?? null;
326
+            $default = $definition['default'] ?? null;
327
+            $length  = $definition['length'] ?? null;
328
+            $properties = $definition['properties'] ?? null;
329
+
330
+            if (isset($definition['relation']) && $type !== null) {
331
+                $msg = "Column \"$colName\": ";
332
+                $msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
333
+                throw new ActiveRecordException($msg);
334
+            } else if (isset($definition['relation'])) {
335
+                $type = self::COLUMN_TYPE_ID;
336
+            }
337
+
338
+            $columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
339
+        }
340
+
341
+        // Sort table (first column is id, the remaining are alphabetically sorted)
342
+        $columnStatements = $this->sortColumnStatements($columnStatements);
343
+
344
+        $sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
345
+        $sql .= "(\n";
346
+        $sql .= join($columnStatements, ",\n");
347
+        $sql .= "\n);";
348
+
349
+        return $sql;
350
+    }
351
+
352
+    /**
353
+     * Creates the entity as a table in the database
354
+     */
355
+    public function createTable()
356
+    {
357
+        $this->pdo->query($this->buildCreateTableSQL());
358
+    }
359
+
360
+    /**
361
+     * builds a MySQL constraint statement for the given parameters
362
+     * @param string $parentTable
363
+     * @param string $parentColumn
364
+     * @param string $childTable
365
+     * @param string $childColumn
366
+     * @return string The MySQL table constraint string
367
+     */
368
+    protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
369
+    {
370
+        $template = <<<SQL
371 371
 ALTER TABLE `%s`
372 372
 ADD CONSTRAINT
373 373
 FOREIGN KEY (`%s`)
374 374
 REFERENCES `%s`(`%s`)
375 375
 ON DELETE CASCADE;
376 376
 SQL;
377
-		return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
378
-	}
379
-
380
-	/**
381
-	 * Iterates over the specified constraints in the table definition, 
382
-	 * 		and applies these to the database.
383
-	 */
384
-	public function createTableConstraints()
385
-	{
386
-		// Iterate over columns, check whether "relation" field exists, if so create constraint
387
-		foreach ($this->tableDefinition as $colName => $definition) {
388
-			if (isset($definition['relation']) && $definition['relation'] instanceof AbstractActiveRecord) {
389
-				// Forge new relation
390
-				$target = $definition['relation'];
391
-				$constraintSql = $this->buildConstraint($target->getActiveRecordTable(), 'id', $this->getActiveRecordTable(), $colName);
392
-
393
-				$this->pdo->query($constraintSql);
394
-			}
395
-		}
396
-	}
397
-
398
-	/**
399
-	 * Returns the name -> variable mapping for the table definition.
400
-	 * @return Array The mapping
401
-	 */
402
-	protected function getActiveRecordColumns()
403
-	{
404
-		$bindings = [];
405
-		foreach ($this->tableDefinition as $colName => $definition) {
406
-
407
-			// Ignore the id column (key) when inserting or updating
408
-			if ($colName == self::COLUMN_NAME_ID) {
409
-				continue;
410
-			}
411
-
412
-			$bindings[$colName] = &$definition['value'];
413
-		}
414
-		return $bindings;
415
-	}
416
-
417
-	/**
418
-	 * {@inheritdoc}
419
-	 */
420
-	public function create()
421
-	{
422
-		foreach ($this->registeredCreateHooks as $colName => $fn) {
423
-			// @TODO: Would it be better to pass the Query to the function?
424
-			$fn();
425
-		}
426
-
427
-		try {
428
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
429
-				->insert($this->getActiveRecordColumns())
430
-				->execute();
431
-
432
-			$this->setId(intval($this->getPdo()->lastInsertId()));
433
-		} catch (\PDOException $e) {
434
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
435
-		}
436
-
437
-		return $this;
438
-	}
439
-
440
-	/**
441
-	 * {@inheritdoc}
442
-	 */
443
-	public function read($id)
444
-	{
445
-		foreach ($this->registeredReadHooks as $colName => $fn) {
446
-			// @TODO: Would it be better to pass the Query to the function?
447
-			$fn();
448
-		}
449
-
450
-		try {
451
-			$row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
452
-				->select()
453
-				->where('id', '=', $id)
454
-				->execute()
455
-				->fetch();
456
-
457
-			if ($row === false) {
458
-				throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
459
-			}
460
-
461
-			$this->fill($row)->setId($id);
462
-		} catch (\PDOException $e) {
463
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
464
-		}
465
-
466
-		return $this;
467
-	}
468
-
469
-	/**
470
-	 * {@inheritdoc}
471
-	 */
472
-	public function update()
473
-	{
474
-		foreach ($this->registeredUpdateHooks as $colName => $fn) {
475
-			// @TODO: Would it be better to pass the Query to the function?
476
-			$fn();
477
-		}
478
-
479
-		try {
480
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
481
-				->update($this->getActiveRecordColumns())
482
-				->where('id', '=', $this->getId())
483
-				->execute();
484
-		} catch (\PDOException $e) {
485
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
486
-		}
487
-
488
-		return $this;
489
-	}
490
-
491
-	/**
492
-	 * {@inheritdoc}
493
-	 */
494
-	public function delete()
495
-	{
496
-		foreach ($this->registeredDeleteHooks as $colName => $fn) {
497
-			// @TODO: Would it be better to pass the Query to the function?
498
-			$fn();
499
-		}
500
-
501
-		try {
502
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
503
-				->delete()
504
-				->where('id', '=', $this->getId())
505
-				->execute();
506
-
507
-			$this->setId(null);
508
-		} catch (\PDOException $e) {
509
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
510
-		}
511
-
512
-		return $this;
513
-	}
514
-
515
-	/**
516
-	 * {@inheritdoc}
517
-	 */
518
-	public function sync()
519
-	{
520
-		if (!$this->exists()) {
521
-			return $this->create();
522
-		}
523
-
524
-		return $this->update();
525
-	}
526
-
527
-	/**
528
-	 * {@inheritdoc}
529
-	 */
530
-	public function exists()
531
-	{
532
-		return $this->getId() !== null;
533
-	}
534
-
535
-	/**
536
-	 * {@inheritdoc}
537
-	 */
538
-	public function fill(array $attributes)
539
-	{
540
-		$columns = $this->getActiveRecordColumns();
541
-		$columns['id'] = &$this->id;
542
-
543
-		foreach ($attributes as $key => $value) {
544
-			if (array_key_exists($key, $columns)) {
545
-				$columns[$key] = $value;
546
-			}
547
-		}
548
-
549
-		return $this;
550
-	}
551
-
552
-	/**
553
-	 * {@inheritdoc}
554
-	 */
555
-	public function searchOne(array $where = [], array $orderBy = [])
556
-	{
557
-		try {
558
-			$row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
559
-
560
-			if ($row === false) {
561
-				throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
562
-			}
563
-
564
-			return $this->fill($row)->setId($row['id']);
565
-		} catch (\PDOException $e) {
566
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
567
-		}
568
-	}
569
-
570
-	/**
571
-	 * {@inheritdoc}
572
-	 */
573
-	public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
574
-	{
575
-		try {
576
-			$queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
577
-			$result = [];
578
-
579
-			foreach ($queryResult as $row) {
580
-				$new = clone $this;
581
-
582
-				$result[] = $new->fill($row)->setId($row['id']);
583
-			}
584
-
585
-			return $result;
586
-		} catch (\PDOException $e) {
587
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
588
-		}
589
-	}
590
-
591
-	/**
592
-	 * Returns the search query result with the given where, order by, limit and offset clauses.
593
-	 *
594
-	 * @param array $where = []
595
-	 * @param array $orderBy = []
596
-	 * @param int $limit = -1
597
-	 * @param int $offset = 0
598
-	 * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
599
-	 */
600
-	private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
601
-	{
602
-		$query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
603
-			->select();
604
-
605
-		$this->getSearchQueryWhere($query, $where);
606
-		$this->getSearchQueryOrderBy($query, $orderBy);
607
-		$this->getSearchQueryLimit($query, $limit, $offset);
608
-
609
-		// Ignore all trait modifiers for which a where clause was specified
610
-		$registeredSearchHooks = $this->registeredSearchHooks;
611
-		foreach ($where as $index => $clause) {
612
-			$colName = $clause[0];
613
-			unset($registeredSearchHooks[$colName]);
614
-		}
615
-
616
-		// Allow traits to modify the query
617
-		foreach ($registeredSearchHooks as $column => $searchFunction) {
618
-			$searchFunction($query);
619
-		}
620
-
621
-		return $query->execute();
622
-	}
623
-
624
-	/**
625
-	 * Returns the given query after adding the given where conditions.
626
-	 *
627
-	 * @param \miBadger\Query\Query $query
628
-	 * @param array $where
629
-	 * @return \miBadger\Query\Query the given query after adding the given where conditions.
630
-	 */
631
-	private function getSearchQueryWhere($query, $where)
632
-	{
633
-		foreach ($where as $key => $value) {
634
-			$query->where($value[0], $value[1], $value[2]);
635
-		}
636
-
637
-		return $query;
638
-	}
639
-
640
-	/**
641
-	 * Returns the given query after adding the given order by conditions.
642
-	 *
643
-	 * @param \miBadger\Query\Query $query
644
-	 * @param array $orderBy
645
-	 * @return \miBadger\Query\Query the given query after adding the given order by conditions.
646
-	 */
647
-	private function getSearchQueryOrderBy($query, $orderBy)
648
-	{
649
-		foreach ($orderBy as $key => $value) {
650
-			$query->orderBy($key, $value);
651
-		}
652
-
653
-		return $query;
654
-	}
655
-
656
-	/**
657
-	 * Returns the given query after adding the given limit and offset conditions.
658
-	 *
659
-	 * @param \miBadger\Query\Query $query
660
-	 * @param int $limit
661
-	 * @param int $offset
662
-	 * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
663
-	 */
664
-	private function getSearchQueryLimit($query, $limit, $offset)
665
-	{
666
-		if ($limit > -1) {
667
-			$query->limit($limit);
668
-			$query->offset($offset);
669
-		}
670
-
671
-		return $query;
672
-	}
673
-
674
-	/**
675
-	 * Returns the PDO.
676
-	 *
677
-	 * @return \PDO the PDO.
678
-	 */
679
-	public function getPdo()
680
-	{
681
-		return $this->pdo;
682
-	}
683
-
684
-	/**
685
-	 * Set the PDO.
686
-	 *
687
-	 * @param \PDO $pdo
688
-	 * @return $this
689
-	 */
690
-	protected function setPdo($pdo)
691
-	{
692
-		$this->pdo = $pdo;
693
-
694
-		return $this;
695
-	}
696
-
697
-	/**
698
-	 * Returns the ID.
699
-	 *
700
-	 * @return null|int The ID.
701
-	 */
702
-	public function getId()
703
-	{
704
-		return $this->id;
705
-	}
706
-
707
-	/**
708
-	 * Set the ID.
709
-	 *
710
-	 * @param int $id
711
-	 * @return $this
712
-	 */
713
-	protected function setId($id)
714
-	{
715
-		$this->id = $id;
716
-
717
-		return $this;
718
-	}
719
-
720
-	/**
721
-	 * Returns the active record table.
722
-	 *
723
-	 * @return string the active record table.
724
-	 */
725
-	abstract protected function getActiveRecordTable();
726
-
727
-	/**
728
-	 * Returns the active record columns.
729
-	 *
730
-	 * @return array the active record columns.
731
-	 */
732
-	abstract protected function getActiveRecordTableDefinition();
377
+        return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
378
+    }
379
+
380
+    /**
381
+     * Iterates over the specified constraints in the table definition, 
382
+     * 		and applies these to the database.
383
+     */
384
+    public function createTableConstraints()
385
+    {
386
+        // Iterate over columns, check whether "relation" field exists, if so create constraint
387
+        foreach ($this->tableDefinition as $colName => $definition) {
388
+            if (isset($definition['relation']) && $definition['relation'] instanceof AbstractActiveRecord) {
389
+                // Forge new relation
390
+                $target = $definition['relation'];
391
+                $constraintSql = $this->buildConstraint($target->getActiveRecordTable(), 'id', $this->getActiveRecordTable(), $colName);
392
+
393
+                $this->pdo->query($constraintSql);
394
+            }
395
+        }
396
+    }
397
+
398
+    /**
399
+     * Returns the name -> variable mapping for the table definition.
400
+     * @return Array The mapping
401
+     */
402
+    protected function getActiveRecordColumns()
403
+    {
404
+        $bindings = [];
405
+        foreach ($this->tableDefinition as $colName => $definition) {
406
+
407
+            // Ignore the id column (key) when inserting or updating
408
+            if ($colName == self::COLUMN_NAME_ID) {
409
+                continue;
410
+            }
411
+
412
+            $bindings[$colName] = &$definition['value'];
413
+        }
414
+        return $bindings;
415
+    }
416
+
417
+    /**
418
+     * {@inheritdoc}
419
+     */
420
+    public function create()
421
+    {
422
+        foreach ($this->registeredCreateHooks as $colName => $fn) {
423
+            // @TODO: Would it be better to pass the Query to the function?
424
+            $fn();
425
+        }
426
+
427
+        try {
428
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
429
+                ->insert($this->getActiveRecordColumns())
430
+                ->execute();
431
+
432
+            $this->setId(intval($this->getPdo()->lastInsertId()));
433
+        } catch (\PDOException $e) {
434
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
435
+        }
436
+
437
+        return $this;
438
+    }
439
+
440
+    /**
441
+     * {@inheritdoc}
442
+     */
443
+    public function read($id)
444
+    {
445
+        foreach ($this->registeredReadHooks as $colName => $fn) {
446
+            // @TODO: Would it be better to pass the Query to the function?
447
+            $fn();
448
+        }
449
+
450
+        try {
451
+            $row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
452
+                ->select()
453
+                ->where('id', '=', $id)
454
+                ->execute()
455
+                ->fetch();
456
+
457
+            if ($row === false) {
458
+                throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
459
+            }
460
+
461
+            $this->fill($row)->setId($id);
462
+        } catch (\PDOException $e) {
463
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
464
+        }
465
+
466
+        return $this;
467
+    }
468
+
469
+    /**
470
+     * {@inheritdoc}
471
+     */
472
+    public function update()
473
+    {
474
+        foreach ($this->registeredUpdateHooks as $colName => $fn) {
475
+            // @TODO: Would it be better to pass the Query to the function?
476
+            $fn();
477
+        }
478
+
479
+        try {
480
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
481
+                ->update($this->getActiveRecordColumns())
482
+                ->where('id', '=', $this->getId())
483
+                ->execute();
484
+        } catch (\PDOException $e) {
485
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
486
+        }
487
+
488
+        return $this;
489
+    }
490
+
491
+    /**
492
+     * {@inheritdoc}
493
+     */
494
+    public function delete()
495
+    {
496
+        foreach ($this->registeredDeleteHooks as $colName => $fn) {
497
+            // @TODO: Would it be better to pass the Query to the function?
498
+            $fn();
499
+        }
500
+
501
+        try {
502
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
503
+                ->delete()
504
+                ->where('id', '=', $this->getId())
505
+                ->execute();
506
+
507
+            $this->setId(null);
508
+        } catch (\PDOException $e) {
509
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
510
+        }
511
+
512
+        return $this;
513
+    }
514
+
515
+    /**
516
+     * {@inheritdoc}
517
+     */
518
+    public function sync()
519
+    {
520
+        if (!$this->exists()) {
521
+            return $this->create();
522
+        }
523
+
524
+        return $this->update();
525
+    }
526
+
527
+    /**
528
+     * {@inheritdoc}
529
+     */
530
+    public function exists()
531
+    {
532
+        return $this->getId() !== null;
533
+    }
534
+
535
+    /**
536
+     * {@inheritdoc}
537
+     */
538
+    public function fill(array $attributes)
539
+    {
540
+        $columns = $this->getActiveRecordColumns();
541
+        $columns['id'] = &$this->id;
542
+
543
+        foreach ($attributes as $key => $value) {
544
+            if (array_key_exists($key, $columns)) {
545
+                $columns[$key] = $value;
546
+            }
547
+        }
548
+
549
+        return $this;
550
+    }
551
+
552
+    /**
553
+     * {@inheritdoc}
554
+     */
555
+    public function searchOne(array $where = [], array $orderBy = [])
556
+    {
557
+        try {
558
+            $row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
559
+
560
+            if ($row === false) {
561
+                throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
562
+            }
563
+
564
+            return $this->fill($row)->setId($row['id']);
565
+        } catch (\PDOException $e) {
566
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
567
+        }
568
+    }
569
+
570
+    /**
571
+     * {@inheritdoc}
572
+     */
573
+    public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
574
+    {
575
+        try {
576
+            $queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
577
+            $result = [];
578
+
579
+            foreach ($queryResult as $row) {
580
+                $new = clone $this;
581
+
582
+                $result[] = $new->fill($row)->setId($row['id']);
583
+            }
584
+
585
+            return $result;
586
+        } catch (\PDOException $e) {
587
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
588
+        }
589
+    }
590
+
591
+    /**
592
+     * Returns the search query result with the given where, order by, limit and offset clauses.
593
+     *
594
+     * @param array $where = []
595
+     * @param array $orderBy = []
596
+     * @param int $limit = -1
597
+     * @param int $offset = 0
598
+     * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
599
+     */
600
+    private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
601
+    {
602
+        $query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
603
+            ->select();
604
+
605
+        $this->getSearchQueryWhere($query, $where);
606
+        $this->getSearchQueryOrderBy($query, $orderBy);
607
+        $this->getSearchQueryLimit($query, $limit, $offset);
608
+
609
+        // Ignore all trait modifiers for which a where clause was specified
610
+        $registeredSearchHooks = $this->registeredSearchHooks;
611
+        foreach ($where as $index => $clause) {
612
+            $colName = $clause[0];
613
+            unset($registeredSearchHooks[$colName]);
614
+        }
615
+
616
+        // Allow traits to modify the query
617
+        foreach ($registeredSearchHooks as $column => $searchFunction) {
618
+            $searchFunction($query);
619
+        }
620
+
621
+        return $query->execute();
622
+    }
623
+
624
+    /**
625
+     * Returns the given query after adding the given where conditions.
626
+     *
627
+     * @param \miBadger\Query\Query $query
628
+     * @param array $where
629
+     * @return \miBadger\Query\Query the given query after adding the given where conditions.
630
+     */
631
+    private function getSearchQueryWhere($query, $where)
632
+    {
633
+        foreach ($where as $key => $value) {
634
+            $query->where($value[0], $value[1], $value[2]);
635
+        }
636
+
637
+        return $query;
638
+    }
639
+
640
+    /**
641
+     * Returns the given query after adding the given order by conditions.
642
+     *
643
+     * @param \miBadger\Query\Query $query
644
+     * @param array $orderBy
645
+     * @return \miBadger\Query\Query the given query after adding the given order by conditions.
646
+     */
647
+    private function getSearchQueryOrderBy($query, $orderBy)
648
+    {
649
+        foreach ($orderBy as $key => $value) {
650
+            $query->orderBy($key, $value);
651
+        }
652
+
653
+        return $query;
654
+    }
655
+
656
+    /**
657
+     * Returns the given query after adding the given limit and offset conditions.
658
+     *
659
+     * @param \miBadger\Query\Query $query
660
+     * @param int $limit
661
+     * @param int $offset
662
+     * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
663
+     */
664
+    private function getSearchQueryLimit($query, $limit, $offset)
665
+    {
666
+        if ($limit > -1) {
667
+            $query->limit($limit);
668
+            $query->offset($offset);
669
+        }
670
+
671
+        return $query;
672
+    }
673
+
674
+    /**
675
+     * Returns the PDO.
676
+     *
677
+     * @return \PDO the PDO.
678
+     */
679
+    public function getPdo()
680
+    {
681
+        return $this->pdo;
682
+    }
683
+
684
+    /**
685
+     * Set the PDO.
686
+     *
687
+     * @param \PDO $pdo
688
+     * @return $this
689
+     */
690
+    protected function setPdo($pdo)
691
+    {
692
+        $this->pdo = $pdo;
693
+
694
+        return $this;
695
+    }
696
+
697
+    /**
698
+     * Returns the ID.
699
+     *
700
+     * @return null|int The ID.
701
+     */
702
+    public function getId()
703
+    {
704
+        return $this->id;
705
+    }
706
+
707
+    /**
708
+     * Set the ID.
709
+     *
710
+     * @param int $id
711
+     * @return $this
712
+     */
713
+    protected function setId($id)
714
+    {
715
+        $this->id = $id;
716
+
717
+        return $this;
718
+    }
719
+
720
+    /**
721
+     * Returns the active record table.
722
+     *
723
+     * @return string the active record table.
724
+     */
725
+    abstract protected function getActiveRecordTable();
726
+
727
+    /**
728
+     * Returns the active record columns.
729
+     *
730
+     * @return array the active record columns.
731
+     */
732
+    abstract protected function getActiveRecordTableDefinition();
733 733
 }
Please login to merge, or discard this patch.
src/Traits/AutoApi.php 2 patches
Doc Comments   +11 added lines patch added patch discarded remove patch
@@ -62,6 +62,8 @@  discard block
 block discarded – undo
62 62
 
63 63
 	/**
64 64
 	 * Copy all table variables between two instances
65
+	 * @param AutoApi $to
66
+	 * @param AutoApi $from
65 67
 	 */
66 68
 	private function syncInstances($to, $from)
67 69
 	{
@@ -290,12 +292,21 @@  discard block
 block discarded – undo
290 292
 
291 293
 	abstract public function read($id);
292 294
 
295
+	/**
296
+	 * @return \PDO
297
+	 */
293 298
 	abstract public function getPdo();
294 299
 
300
+	/**
301
+	 * @param integer $id
302
+	 */
295 303
 	abstract function setId($id);
296 304
 
297 305
 	abstract function getId();
298 306
 
307
+	/**
308
+	 * @return string
309
+	 */
299 310
 	abstract function getActiveRecordTable();
300 311
 
301 312
 	abstract function getActiveRecordColumns();
Please login to merge, or discard this patch.
Indentation   +270 added lines, -270 removed lines patch added patch discarded remove patch
@@ -8,295 +8,295 @@
 block discarded – undo
8 8
 
9 9
 trait AutoApi
10 10
 {
11
-	/* =======================================================================
11
+    /* =======================================================================
12 12
 	 * ===================== Automatic API Support ===========================
13 13
 	 * ======================================================================= */
14 14
 
15
-	/** @var array A map of column name to functions that hook the insert function */
16
-	protected $registeredCreateHooks;
15
+    /** @var array A map of column name to functions that hook the insert function */
16
+    protected $registeredCreateHooks;
17 17
 
18
-	/** @var array A map of column name to functions that hook the read function */
19
-	protected $registeredReadHooks;
18
+    /** @var array A map of column name to functions that hook the read function */
19
+    protected $registeredReadHooks;
20 20
 
21
-	/** @var array A map of column name to functions that hook the update function */
22
-	protected $registeredUpdateHooks;
21
+    /** @var array A map of column name to functions that hook the update function */
22
+    protected $registeredUpdateHooks;
23 23
 
24
-	/** @var array A map of column name to functions that hook the update function */
25
-	protected $registeredDeleteHooks;	
24
+    /** @var array A map of column name to functions that hook the update function */
25
+    protected $registeredDeleteHooks;	
26 26
 
27
-	/** @var array A map of column name to functions that hook the search function */
28
-	protected $registeredSearchHooks;
27
+    /** @var array A map of column name to functions that hook the search function */
28
+    protected $registeredSearchHooks;
29 29
 
30
-	/** @var array A list of table column definitions */
31
-	protected $tableDefinition;
30
+    /** @var array A list of table column definitions */
31
+    protected $tableDefinition;
32 32
 
33
-	public function apiSearch($inputs, $fieldWhitelist)
34
-	{
35
-		// @TODO: How to handle this case?
36
-		// => Default parameter names for searching? (limit, pagination, sort order etc)
37
-		//		Find default names for this and store in class
38
-		// => Limited search parameters? (We don't want to be able to search on a password field for example)
39
-	}
33
+    public function apiSearch($inputs, $fieldWhitelist)
34
+    {
35
+        // @TODO: How to handle this case?
36
+        // => Default parameter names for searching? (limit, pagination, sort order etc)
37
+        //		Find default names for this and store in class
38
+        // => Limited search parameters? (We don't want to be able to search on a password field for example)
39
+    }
40 40
 
41
-	public function toArray($fieldWhitelist)
42
-	{
43
-		$output = [];
44
-		foreach ($this->tableDefinition as $colName => $definition) {
45
-			if (in_array($colName, $fieldWhitelist)) {
46
-				$output[$colName] = $definition['value'];
47
-			}
48
-		}
41
+    public function toArray($fieldWhitelist)
42
+    {
43
+        $output = [];
44
+        foreach ($this->tableDefinition as $colName => $definition) {
45
+            if (in_array($colName, $fieldWhitelist)) {
46
+                $output[$colName] = $definition['value'];
47
+            }
48
+        }
49 49
 
50
-		return $output;
51
-	}
50
+        return $output;
51
+    }
52 52
 
53
-	public function apiRead($id, $fieldWhitelist)
54
-	{
55
-		$this->read($id);
56
-		return $this->toArray($fieldWhitelist);
57
-	}
53
+    public function apiRead($id, $fieldWhitelist)
54
+    {
55
+        $this->read($id);
56
+        return $this->toArray($fieldWhitelist);
57
+    }
58 58
 
59
-	/* =============================================================
59
+    /* =============================================================
60 60
 	 * ===================== Constraint validation =================
61 61
 	 * ============================================================= */
62 62
 
63
-	/**
64
-	 * Copy all table variables between two instances
65
-	 */
66
-	private function syncInstances($to, $from)
67
-	{
68
-		foreach ($to->tableDefinition as $colName => $definition) {
69
-			$definition['value'] = $from->tableDefinition[$colName]['value'];
70
-		}
71
-	}
72
-
73
-	private function filterInputColumns($input, $whitelist)
74
-	{
75
-		$filteredInput = $input;
76
-		foreach ($input as $colName => $value) {
77
-			if (!in_array($colName, $whitelist)) {
78
-				unset($filteredInput[$colName]);
79
-			}
80
-		}
81
-		return $filteredInput;
82
-	}
83
-
84
-	private function validateExcessKeys($input)
85
-	{
86
-		$errors = [];
87
-		foreach ($input as $colName => $value) {
88
-			if (!array_key_exists($colName, $this->tableDefinition)) {
89
-				$errors[$colName] = "Unknown input field";
90
-				continue;
91
-			}
92
-		}
93
-		return $errors;
94
-	}
95
-
96
-	private function validateImmutableColumns($input)
97
-	{
98
-		$errors = [];
99
-		foreach ($this->tableDefinition as $colName => $definition) {
100
-			$property = $definition['properties'] ?? null;
101
-			if (array_key_exists($colName, $input)
102
-				&& $property & ColumnProperty::IMMUTABLE) {
103
-				$errors[$colName] = "Field cannot be changed";
104
-			}
105
-		}
106
-		return $errors;
107
-	}
108
-
109
-	private function validateInputValues($input)
110
-	{
111
-		$errors = [];
112
-		foreach ($this->tableDefinition as $colName => $definition) {
113
-			// Validation check 1: If validate function is present
114
-			if (array_key_exists($colName, $input) 
115
-				&& is_callable($definition['validate'] ?? null)) {
116
-				$inputValue = $input[$colName];
117
-
118
-				// If validation function fails
119
-				[$status, $message] = $definition['validate']($inputValue);
120
-				if (!$status) {
121
-					$errors[$colName] = $message;
122
-				}	
123
-			}
124
-
125
-			// Validation check 2: If relation column, check whether entity exists
126
-			$properties = $definition['properties'] ?? null;
127
-			if (isset($definition['relation'])
128
-				&& ($properties & ColumnProperty::NOT_NULL)) {
129
-				$instance = clone $definition['relation'];
130
-				try {
131
-					$instance->read($input[$colName] ?? null);
132
-				} catch (ActiveRecordException $e) {
133
-					$errors[$colName] = "Entity for this value doesn't exist";
134
-				}
135
-			}
136
-		}
137
-		return $errors;
138
-	}
139
-
140
-	/**
141
-	 * This function is only used for API Update calls (direct getter/setter functions are unconstrained)
142
-	 */
143
-	private function validateMissingKeys()
144
-	{
145
-		$errors = [];
146
-
147
-		foreach ($this->tableDefinition as $colName => $colDefinition) {
148
-			$default = $colDefinition['default'] ?? null;
149
-			$properties = $colDefinition['properties'] ?? null;
150
-			$value = $colDefinition['value'];
151
-
152
-			// If nullable and default not set => null
153
-			// If nullable and default null => default (null)
154
-			// If nullable and default set => default (value)
155
-
156
-			// if not nullable and default not set => error
157
-			// if not nullable and default null => error
158
-			// if not nullable and default st => default (value)
159
-			// => if not nullable and default null and value not set => error message in this method
160
-			if ($properties & ColumnProperty::NOT_NULL
161
-				&& $default === null
162
-				&& !($properties & ColumnProperty::AUTO_INCREMENT)
163
-				// && !array_key_exists($colName, $input)
164
-				&& $value === null) {
165
-				$errors[$colName] = sprintf("The required field \"%s\" is missing", $colName);
166
-			}
167
-		}
168
-
169
-		return $errors;
170
-	}
171
-
172
-	/**
173
-	 * Copies the values for entries in the input with matching variable names in the record definition
174
-	 * @param Array $input The input data to be loaded into $this record
175
-	 */
176
-	private function loadData($input)
177
-	{
178
-		foreach ($this->tableDefinition as $colName => $definition) {
179
-			if (array_key_exists($colName, $input)) {
180
-				$definition['value'] = $input[$colName];
181
-			}
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * @param Array $input Associative array of input values
187
-	 * @param Array $fieldWhitelist array of column names that are allowed to be filled by the input array 
188
-	 * @return Array Array containing the set of optional errors (associative array) and an optional array representation (associative)
189
-	 * 					of the modified data.
190
-	 */
191
-	public function apiCreate($input, $fieldWhitelist)
192
-	{
193
-		// Clone $this to new instance (for restoring if validation goes wrong)
194
-		$transaction = clone $this;
195
-		$errors = [];
196
-
197
-		// Filter out all non-whitelisted input values
198
-		$input = $this->filterInputColumns($input, $fieldWhitelist);
199
-
200
-		// Validate excess keys
201
-		$errors += $transaction->validateExcessKeys($input);
202
-
203
-		// Validate input values (using validation function)
204
-		$errors += $transaction->validateInputValues($input);
205
-
206
-		// "Copy" data into transaction
207
-		$transaction->loadData($input);
208
-
209
-		// Run create hooks
210
-		foreach ($this->registeredCreateHooks as $colName => $fn) {
211
-			$fn();
212
-		}
213
-
214
-		// Validate missing keys
215
-		$errors += $transaction->validateMissingKeys();
216
-
217
-		// If no errors, commit the pending data
218
-		if (empty($errors)) {
219
-			$this->syncInstances($this, $transaction);
220
-
221
-			try {
222
-				$q = (new Query($this->getPdo(), $this->getActiveRecordTable()))
223
-					->insert($this->getActiveRecordColumns())
224
-					->execute();
225
-
226
-				$this->setId(intval($this->getPdo()->lastInsertId()));
227
-			} catch (\PDOException $e) {
228
-				// @TODO: Potentially filter and store mysql messages (where possible) in error messages
229
-				throw new ActiveRecordException($e->getMessage(), 0, $e);
230
-			}
231
-
232
-			return [null, $this->toArray($fieldWhitelist)];
233
-		} else {
234
-			return [$errors, null];
235
-		}
236
-	}
237
-
238
-	/**
239
-	 * @param Array $input Associative array of input values
240
-	 * @param Array $fieldWhitelist array of column names that are allowed to be filled by the input array 
241
-	 * @return Array Array containing the set of optional errors (associative array) and an optional array representation (associative)
242
-	 * 					of the modified data.
243
-	 */
244
-	public function apiUpdate($input, $fieldWhitelist)
245
-	{
246
-		$transaction = clone $this;
247
-		$errors = [];
248
-
249
-		// Filter out all non-whitelisted input values
250
-		$input = $this->filterInputColumns($input, $fieldWhitelist);
251
-
252
-		// Check for excess keys
253
-		$errors += $transaction->validateExcessKeys($input);
254
-
255
-		// Check for immutable keys
256
-		$errors += $transaction->validateImmutableColumns($input);
257
-
258
-		// Validate input values (using validation function)
259
-		$errors += $transaction->validateInputValues($input);
260
-
261
-		// "Copy" data into transaction
262
-		$transaction->loadData($input);
263
-
264
-		// Run create hooks
265
-		foreach ($this->registeredUpdateHooks as $colName => $fn) {
266
-			$fn();
267
-		}
268
-
269
-		// Validate missing keys
270
-		$errors += $transaction->validateMissingKeys();
271
-
272
-		// Update database
273
-		if (empty($errors)) {
274
-			$this->syncInstances($this, $transaction);
275
-
276
-			try {
277
-				(new Query($this->getPdo(), $this->getActiveRecordTable()))
278
-					->update($this->getActiveRecordColumns())
279
-					->where('id', '=', $this->getId())
280
-					->execute();
281
-			} catch (\PDOException $e) {
282
-				throw new ActiveRecordException($e->getMessage(), 0, $e);
283
-			}
284
-
285
-			return [null, $this->toArray($fieldWhitelist)];
286
-		} else {
287
-			return [$errors, null];
288
-		}
289
-	}
290
-
291
-	abstract public function read($id);
63
+    /**
64
+     * Copy all table variables between two instances
65
+     */
66
+    private function syncInstances($to, $from)
67
+    {
68
+        foreach ($to->tableDefinition as $colName => $definition) {
69
+            $definition['value'] = $from->tableDefinition[$colName]['value'];
70
+        }
71
+    }
72
+
73
+    private function filterInputColumns($input, $whitelist)
74
+    {
75
+        $filteredInput = $input;
76
+        foreach ($input as $colName => $value) {
77
+            if (!in_array($colName, $whitelist)) {
78
+                unset($filteredInput[$colName]);
79
+            }
80
+        }
81
+        return $filteredInput;
82
+    }
83
+
84
+    private function validateExcessKeys($input)
85
+    {
86
+        $errors = [];
87
+        foreach ($input as $colName => $value) {
88
+            if (!array_key_exists($colName, $this->tableDefinition)) {
89
+                $errors[$colName] = "Unknown input field";
90
+                continue;
91
+            }
92
+        }
93
+        return $errors;
94
+    }
95
+
96
+    private function validateImmutableColumns($input)
97
+    {
98
+        $errors = [];
99
+        foreach ($this->tableDefinition as $colName => $definition) {
100
+            $property = $definition['properties'] ?? null;
101
+            if (array_key_exists($colName, $input)
102
+                && $property & ColumnProperty::IMMUTABLE) {
103
+                $errors[$colName] = "Field cannot be changed";
104
+            }
105
+        }
106
+        return $errors;
107
+    }
108
+
109
+    private function validateInputValues($input)
110
+    {
111
+        $errors = [];
112
+        foreach ($this->tableDefinition as $colName => $definition) {
113
+            // Validation check 1: If validate function is present
114
+            if (array_key_exists($colName, $input) 
115
+                && is_callable($definition['validate'] ?? null)) {
116
+                $inputValue = $input[$colName];
117
+
118
+                // If validation function fails
119
+                [$status, $message] = $definition['validate']($inputValue);
120
+                if (!$status) {
121
+                    $errors[$colName] = $message;
122
+                }	
123
+            }
124
+
125
+            // Validation check 2: If relation column, check whether entity exists
126
+            $properties = $definition['properties'] ?? null;
127
+            if (isset($definition['relation'])
128
+                && ($properties & ColumnProperty::NOT_NULL)) {
129
+                $instance = clone $definition['relation'];
130
+                try {
131
+                    $instance->read($input[$colName] ?? null);
132
+                } catch (ActiveRecordException $e) {
133
+                    $errors[$colName] = "Entity for this value doesn't exist";
134
+                }
135
+            }
136
+        }
137
+        return $errors;
138
+    }
139
+
140
+    /**
141
+     * This function is only used for API Update calls (direct getter/setter functions are unconstrained)
142
+     */
143
+    private function validateMissingKeys()
144
+    {
145
+        $errors = [];
146
+
147
+        foreach ($this->tableDefinition as $colName => $colDefinition) {
148
+            $default = $colDefinition['default'] ?? null;
149
+            $properties = $colDefinition['properties'] ?? null;
150
+            $value = $colDefinition['value'];
151
+
152
+            // If nullable and default not set => null
153
+            // If nullable and default null => default (null)
154
+            // If nullable and default set => default (value)
155
+
156
+            // if not nullable and default not set => error
157
+            // if not nullable and default null => error
158
+            // if not nullable and default st => default (value)
159
+            // => if not nullable and default null and value not set => error message in this method
160
+            if ($properties & ColumnProperty::NOT_NULL
161
+                && $default === null
162
+                && !($properties & ColumnProperty::AUTO_INCREMENT)
163
+                // && !array_key_exists($colName, $input)
164
+                && $value === null) {
165
+                $errors[$colName] = sprintf("The required field \"%s\" is missing", $colName);
166
+            }
167
+        }
168
+
169
+        return $errors;
170
+    }
171
+
172
+    /**
173
+     * Copies the values for entries in the input with matching variable names in the record definition
174
+     * @param Array $input The input data to be loaded into $this record
175
+     */
176
+    private function loadData($input)
177
+    {
178
+        foreach ($this->tableDefinition as $colName => $definition) {
179
+            if (array_key_exists($colName, $input)) {
180
+                $definition['value'] = $input[$colName];
181
+            }
182
+        }
183
+    }
184
+
185
+    /**
186
+     * @param Array $input Associative array of input values
187
+     * @param Array $fieldWhitelist array of column names that are allowed to be filled by the input array 
188
+     * @return Array Array containing the set of optional errors (associative array) and an optional array representation (associative)
189
+     * 					of the modified data.
190
+     */
191
+    public function apiCreate($input, $fieldWhitelist)
192
+    {
193
+        // Clone $this to new instance (for restoring if validation goes wrong)
194
+        $transaction = clone $this;
195
+        $errors = [];
196
+
197
+        // Filter out all non-whitelisted input values
198
+        $input = $this->filterInputColumns($input, $fieldWhitelist);
199
+
200
+        // Validate excess keys
201
+        $errors += $transaction->validateExcessKeys($input);
202
+
203
+        // Validate input values (using validation function)
204
+        $errors += $transaction->validateInputValues($input);
205
+
206
+        // "Copy" data into transaction
207
+        $transaction->loadData($input);
208
+
209
+        // Run create hooks
210
+        foreach ($this->registeredCreateHooks as $colName => $fn) {
211
+            $fn();
212
+        }
213
+
214
+        // Validate missing keys
215
+        $errors += $transaction->validateMissingKeys();
216
+
217
+        // If no errors, commit the pending data
218
+        if (empty($errors)) {
219
+            $this->syncInstances($this, $transaction);
220
+
221
+            try {
222
+                $q = (new Query($this->getPdo(), $this->getActiveRecordTable()))
223
+                    ->insert($this->getActiveRecordColumns())
224
+                    ->execute();
225
+
226
+                $this->setId(intval($this->getPdo()->lastInsertId()));
227
+            } catch (\PDOException $e) {
228
+                // @TODO: Potentially filter and store mysql messages (where possible) in error messages
229
+                throw new ActiveRecordException($e->getMessage(), 0, $e);
230
+            }
231
+
232
+            return [null, $this->toArray($fieldWhitelist)];
233
+        } else {
234
+            return [$errors, null];
235
+        }
236
+    }
237
+
238
+    /**
239
+     * @param Array $input Associative array of input values
240
+     * @param Array $fieldWhitelist array of column names that are allowed to be filled by the input array 
241
+     * @return Array Array containing the set of optional errors (associative array) and an optional array representation (associative)
242
+     * 					of the modified data.
243
+     */
244
+    public function apiUpdate($input, $fieldWhitelist)
245
+    {
246
+        $transaction = clone $this;
247
+        $errors = [];
248
+
249
+        // Filter out all non-whitelisted input values
250
+        $input = $this->filterInputColumns($input, $fieldWhitelist);
251
+
252
+        // Check for excess keys
253
+        $errors += $transaction->validateExcessKeys($input);
254
+
255
+        // Check for immutable keys
256
+        $errors += $transaction->validateImmutableColumns($input);
257
+
258
+        // Validate input values (using validation function)
259
+        $errors += $transaction->validateInputValues($input);
260
+
261
+        // "Copy" data into transaction
262
+        $transaction->loadData($input);
263
+
264
+        // Run create hooks
265
+        foreach ($this->registeredUpdateHooks as $colName => $fn) {
266
+            $fn();
267
+        }
268
+
269
+        // Validate missing keys
270
+        $errors += $transaction->validateMissingKeys();
271
+
272
+        // Update database
273
+        if (empty($errors)) {
274
+            $this->syncInstances($this, $transaction);
275
+
276
+            try {
277
+                (new Query($this->getPdo(), $this->getActiveRecordTable()))
278
+                    ->update($this->getActiveRecordColumns())
279
+                    ->where('id', '=', $this->getId())
280
+                    ->execute();
281
+            } catch (\PDOException $e) {
282
+                throw new ActiveRecordException($e->getMessage(), 0, $e);
283
+            }
284
+
285
+            return [null, $this->toArray($fieldWhitelist)];
286
+        } else {
287
+            return [$errors, null];
288
+        }
289
+    }
290
+
291
+    abstract public function read($id);
292 292
 
293
-	abstract public function getPdo();
293
+    abstract public function getPdo();
294 294
 
295
-	abstract function setId($id);
295
+    abstract function setId($id);
296 296
 
297
-	abstract function getId();
297
+    abstract function getId();
298 298
 
299
-	abstract function getActiveRecordTable();
299
+    abstract function getActiveRecordTable();
300 300
 
301
-	abstract function getActiveRecordColumns();
301
+    abstract function getActiveRecordColumns();
302 302
 }
Please login to merge, or discard this patch.
src/Traits/ManyToManyRelation.php 2 patches
Doc Comments   +2 added lines patch added patch discarded remove patch
@@ -85,11 +85,13 @@
 block discarded – undo
85 85
 	abstract function getActiveRecordTable();
86 86
 
87 87
 	/**
88
+	 * @param string $parentColumn
88 89
 	 * @return void
89 90
 	 */
90 91
 	abstract function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn);
91 92
 
92 93
 	/**
94
+	 * @param string $columnName
93 95
 	 * @return void
94 96
 	 */
95 97
 	abstract function extendTableDefinition($columnName, $definition);
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -8,115 +8,115 @@
 block discarded – undo
8 8
 
9 9
 Trait ManyToManyRelation
10 10
 {
11
-	// These variables are relevant for internal bookkeeping (constraint generation etc)
12
-
13
-	/** @var string The name of the left column of the relation. */
14
-	private $_leftColumnName;
15
-
16
-	/** @var string The name of the right column of the relation. */
17
-	private $_rightColumnName;
18
-
19
-	/** @var string The name of the left table of the relation. */
20
-	private $_leftEntityTable;
21
-
22
-	/** @var string The name of the right table of the relation. */
23
-	private $_rightEntityTable;
24
-
25
-	/** @var \PDO The PDO object. */
26
-	protected $pdo;
27
-	/**
28
-	 * Initializes the the ManyToManyRelation trait on the included object
29
-	 * 
30
-	 * @param AbstractActiveRecord $leftEntity The left entity of the relation
31
-	 * @param &variable $leftVariable The variable where the id for the left entity will be stored
32
-	 * @param AbstractActiveRecord $rightEntity The left entity of the relation
33
-	 * @param &variable $leftVariable The variable where the id for the right entity will be stored
34
-	 * @return void
35
-	 */
36
-	protected function initManyToManyRelation(AbstractActiveRecord $leftEntity, &$leftVariable, AbstractActiveRecord $rightEntity, &$rightVariable)
37
-	{
38
-		$this->_leftEntityTable = $leftEntity->getActiveRecordTable();
39
-		$this->_rightEntityTable = $rightEntity->getActiveRecordTable();
40
-
41
-		if (get_class($leftEntity) === get_class($rightEntity)) {
42
-			$this->_leftColumnName = sprintf("id_%s_left", $leftEntity->getActiveRecordTable());
43
-			$this->_rightColumnName = sprintf("id_%s_right", $rightEntity->getActiveRecordTable());
44
-		} else {
45
-			$this->_leftColumnName = sprintf("id_%s", $leftEntity->getActiveRecordTable());
46
-			$this->_rightColumnName = sprintf("id_%s", $rightEntity->getActiveRecordTable());
47
-		}
48
-
49
-		$this->extendTableDefinition($this->_leftColumnName, [
50
-			'value' => &$leftVariable,
51
-			'validate' => null,
52
-			'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
53
-			'properties' => ColumnProperty::NOT_NULL
54
-		]);
55
-
56
-		$this->extendTableDefinition($this->_rightColumnName, [
57
-			'value' => &$rightVariable,
58
-			'validate' => null,
59
-			'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
60
-			'properties' => ColumnProperty::NOT_NULL
61
-		]);
62
-	}
63
-
64
-	/**
65
-	 * Build the constraints for the many-to-many relation table
66
-	 * @return void
67
-	 */
68
-	public function createTableConstraints()
69
-	{
70
-		$childTable = $this->getActiveRecordTable();
71
-
72
-		$leftParentTable = $this->_leftEntityTable;
73
-		$rightParentTable = $this->_rightEntityTable;
74
-
75
-		$leftConstraint = $this->buildConstraint($leftParentTable, 'id', $childTable, $this->_leftColumnName);
76
-		$rightConstraint = $this->buildConstraint($rightParentTable, 'id', $childTable, $this->_rightColumnName);
77
-
78
-		$this->pdo->query($leftConstraint);
79
-		$this->pdo->query($rightConstraint);
80
-	}
81
-
82
-	/**
83
-	 * @return void
84
-	 */	
85
-	abstract function getActiveRecordTable();
86
-
87
-	/**
88
-	 * @return void
89
-	 */
90
-	abstract function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn);
91
-
92
-	/**
93
-	 * @return void
94
-	 */
95
-	abstract function extendTableDefinition($columnName, $definition);
11
+    // These variables are relevant for internal bookkeeping (constraint generation etc)
12
+
13
+    /** @var string The name of the left column of the relation. */
14
+    private $_leftColumnName;
15
+
16
+    /** @var string The name of the right column of the relation. */
17
+    private $_rightColumnName;
18
+
19
+    /** @var string The name of the left table of the relation. */
20
+    private $_leftEntityTable;
21
+
22
+    /** @var string The name of the right table of the relation. */
23
+    private $_rightEntityTable;
24
+
25
+    /** @var \PDO The PDO object. */
26
+    protected $pdo;
27
+    /**
28
+     * Initializes the the ManyToManyRelation trait on the included object
29
+     * 
30
+     * @param AbstractActiveRecord $leftEntity The left entity of the relation
31
+     * @param &variable $leftVariable The variable where the id for the left entity will be stored
32
+     * @param AbstractActiveRecord $rightEntity The left entity of the relation
33
+     * @param &variable $leftVariable The variable where the id for the right entity will be stored
34
+     * @return void
35
+     */
36
+    protected function initManyToManyRelation(AbstractActiveRecord $leftEntity, &$leftVariable, AbstractActiveRecord $rightEntity, &$rightVariable)
37
+    {
38
+        $this->_leftEntityTable = $leftEntity->getActiveRecordTable();
39
+        $this->_rightEntityTable = $rightEntity->getActiveRecordTable();
40
+
41
+        if (get_class($leftEntity) === get_class($rightEntity)) {
42
+            $this->_leftColumnName = sprintf("id_%s_left", $leftEntity->getActiveRecordTable());
43
+            $this->_rightColumnName = sprintf("id_%s_right", $rightEntity->getActiveRecordTable());
44
+        } else {
45
+            $this->_leftColumnName = sprintf("id_%s", $leftEntity->getActiveRecordTable());
46
+            $this->_rightColumnName = sprintf("id_%s", $rightEntity->getActiveRecordTable());
47
+        }
48
+
49
+        $this->extendTableDefinition($this->_leftColumnName, [
50
+            'value' => &$leftVariable,
51
+            'validate' => null,
52
+            'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
53
+            'properties' => ColumnProperty::NOT_NULL
54
+        ]);
55
+
56
+        $this->extendTableDefinition($this->_rightColumnName, [
57
+            'value' => &$rightVariable,
58
+            'validate' => null,
59
+            'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
60
+            'properties' => ColumnProperty::NOT_NULL
61
+        ]);
62
+    }
63
+
64
+    /**
65
+     * Build the constraints for the many-to-many relation table
66
+     * @return void
67
+     */
68
+    public function createTableConstraints()
69
+    {
70
+        $childTable = $this->getActiveRecordTable();
71
+
72
+        $leftParentTable = $this->_leftEntityTable;
73
+        $rightParentTable = $this->_rightEntityTable;
74
+
75
+        $leftConstraint = $this->buildConstraint($leftParentTable, 'id', $childTable, $this->_leftColumnName);
76
+        $rightConstraint = $this->buildConstraint($rightParentTable, 'id', $childTable, $this->_rightColumnName);
77
+
78
+        $this->pdo->query($leftConstraint);
79
+        $this->pdo->query($rightConstraint);
80
+    }
81
+
82
+    /**
83
+     * @return void
84
+     */	
85
+    abstract function getActiveRecordTable();
86
+
87
+    /**
88
+     * @return void
89
+     */
90
+    abstract function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn);
91
+
92
+    /**
93
+     * @return void
94
+     */
95
+    abstract function extendTableDefinition($columnName, $definition);
96 96
 	
97
-	/**
98
-	 * @return void
99
-	 */
100
-	abstract function registerSearchHook($columnName, $fn);
101
-
102
-	/**
103
-	 * @return void
104
-	 */
105
-	abstract function registerDeleteHook($columnName, $fn);
106
-
107
-	/**
108
-	 * @return void
109
-	 */
110
-	abstract function registerUpdateHook($columnName, $fn);
111
-
112
-	/**
113
-	 * @return void
114
-	 */
115
-	abstract function registerReadHook($columnName, $fn);
116
-
117
-	/**
118
-	 * @return void
119
-	 */
120
-	abstract function registerCreateHook($columnName, $fn);
97
+    /**
98
+     * @return void
99
+     */
100
+    abstract function registerSearchHook($columnName, $fn);
101
+
102
+    /**
103
+     * @return void
104
+     */
105
+    abstract function registerDeleteHook($columnName, $fn);
106
+
107
+    /**
108
+     * @return void
109
+     */
110
+    abstract function registerUpdateHook($columnName, $fn);
111
+
112
+    /**
113
+     * @return void
114
+     */
115
+    abstract function registerReadHook($columnName, $fn);
116
+
117
+    /**
118
+     * @return void
119
+     */
120
+    abstract function registerCreateHook($columnName, $fn);
121 121
 
122 122
 }
Please login to merge, or discard this patch.