Passed
Push — v2 ( bb80e3...7e0bb1 )
by Berend
02:24
created
src/AbstractActiveRecord.php 1 patch
Indentation   +699 added lines, -699 removed lines patch added patch discarded remove patch
@@ -18,710 +18,710 @@
 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
-	 * Register a new hook for a specific column that gets called before execution of the update() method
138
-	 * Only one hook per column can be registered at a time
139
-	 * @param string $columnName The name of the column that is registered.
140
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
141
-	 */
142
-	public function registerUpdateHook($columnName, $fn)
143
-	{
144
-		$this->checkHookConstraints($columnName, $this->registeredUpdateHooks);
145
-
146
-		if (is_string($fn) && is_callable([$this, $fn])) {
147
-			$this->registeredUpdateHooks[$columnName] = [$this, $fn];
148
-		} else if (is_callable($fn)) {
149
-			$this->registeredUpdateHooks[$columnName] = $fn;
150
-		} else {
151
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * Register a new hook for a specific column that gets called before execution of the delete() method
157
-	 * Only one hook per column can be registered at a time
158
-	 * @param string $columnName The name of the column that is registered.
159
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
160
-	 */
161
-	public function registerDeleteHook($columnName, $fn)
162
-	{
163
-		$this->checkHookConstraints($columnName, $this->registeredDeleteHooks);
164
-
165
-		if (is_string($fn) && is_callable([$this, $fn])) {
166
-			$this->registeredDeleteHooks[$columnName] = [$this, $fn];
167
-		} else if (is_callable($fn)) {
168
-			$this->registeredDeleteHooks[$columnName] = $fn;
169
-		} else {
170
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
171
-		}
172
-	}
173
-
174
-	/**
175
-	 * Register a new hook for a specific column that gets called before execution of the search() method
176
-	 * Only one hook per column can be registered at a time
177
-	 * @param string $columnName The name of the column that is registered.
178
-	 * @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; 
179
-	 */
180
-	public function registerSearchHook($columnName, $fn)
181
-	{
182
-		$this->checkHookConstraints($columnName, $this->registeredSearchHooks);
183
-
184
-		if (is_string($fn) && is_callable([$this, $fn])) {
185
-			$this->registeredSearchHooks[$columnName] = [$this, $fn];
186
-		} else if (is_callable($fn)) {
187
-			$this->registeredSearchHooks[$columnName] = $fn;
188
-		} else {
189
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
190
-		}
191
-	}
192
-
193
-	/**
194
-	 * Adds a new column definition to the table.
195
-	 * @param string $columnName The name of the column that is registered.
196
-	 * @param Array $definition The definition of that column.
197
-	 */
198
-	public function extendTableDefinition($columnName, $definition)
199
-	{
200
-		if ($this->tableDefinition === null) {
201
-			throw new ActiveRecordException("tableDefinition is null, most likely due to parent class not having been initialized in constructor");
202
-		}
203
-
204
-		// Enforcing table can only be extended with new columns
205
-		if (array_key_exists($columnName, $this->tableDefinition)) {
206
-			$message = "Table is being extended with a column that already exists, ";
207
-			$message .= "\"$columnName\" conflicts with your table definition";
208
-			throw new ActiveRecordException($message, 0);
209
-		}
210
-
211
-		$this->tableDefinition[$columnName] = $definition;
212
-	}
213
-
214
-	/**
215
-	 * Returns the type string as it should appear in the mysql create table statement for the given column
216
-	 * @return string The type string
217
-	 */
218
-	private function getDatabaseTypeString($colName, $type, $length)
219
-	{
220
-		switch (strtoupper($type)) {
221
-			case '':
222
-				throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
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
+     * Register a new hook for a specific column that gets called before execution of the update() method
138
+     * Only one hook per column can be registered at a time
139
+     * @param string $columnName The name of the column that is registered.
140
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
141
+     */
142
+    public function registerUpdateHook($columnName, $fn)
143
+    {
144
+        $this->checkHookConstraints($columnName, $this->registeredUpdateHooks);
145
+
146
+        if (is_string($fn) && is_callable([$this, $fn])) {
147
+            $this->registeredUpdateHooks[$columnName] = [$this, $fn];
148
+        } else if (is_callable($fn)) {
149
+            $this->registeredUpdateHooks[$columnName] = $fn;
150
+        } else {
151
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
152
+        }
153
+    }
154
+
155
+    /**
156
+     * Register a new hook for a specific column that gets called before execution of the delete() method
157
+     * Only one hook per column can be registered at a time
158
+     * @param string $columnName The name of the column that is registered.
159
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
160
+     */
161
+    public function registerDeleteHook($columnName, $fn)
162
+    {
163
+        $this->checkHookConstraints($columnName, $this->registeredDeleteHooks);
164
+
165
+        if (is_string($fn) && is_callable([$this, $fn])) {
166
+            $this->registeredDeleteHooks[$columnName] = [$this, $fn];
167
+        } else if (is_callable($fn)) {
168
+            $this->registeredDeleteHooks[$columnName] = $fn;
169
+        } else {
170
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
171
+        }
172
+    }
173
+
174
+    /**
175
+     * Register a new hook for a specific column that gets called before execution of the search() method
176
+     * Only one hook per column can be registered at a time
177
+     * @param string $columnName The name of the column that is registered.
178
+     * @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; 
179
+     */
180
+    public function registerSearchHook($columnName, $fn)
181
+    {
182
+        $this->checkHookConstraints($columnName, $this->registeredSearchHooks);
183
+
184
+        if (is_string($fn) && is_callable([$this, $fn])) {
185
+            $this->registeredSearchHooks[$columnName] = [$this, $fn];
186
+        } else if (is_callable($fn)) {
187
+            $this->registeredSearchHooks[$columnName] = $fn;
188
+        } else {
189
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
190
+        }
191
+    }
192
+
193
+    /**
194
+     * Adds a new column definition to the table.
195
+     * @param string $columnName The name of the column that is registered.
196
+     * @param Array $definition The definition of that column.
197
+     */
198
+    public function extendTableDefinition($columnName, $definition)
199
+    {
200
+        if ($this->tableDefinition === null) {
201
+            throw new ActiveRecordException("tableDefinition is null, most likely due to parent class not having been initialized in constructor");
202
+        }
203
+
204
+        // Enforcing table can only be extended with new columns
205
+        if (array_key_exists($columnName, $this->tableDefinition)) {
206
+            $message = "Table is being extended with a column that already exists, ";
207
+            $message .= "\"$columnName\" conflicts with your table definition";
208
+            throw new ActiveRecordException($message, 0);
209
+        }
210
+
211
+        $this->tableDefinition[$columnName] = $definition;
212
+    }
213
+
214
+    /**
215
+     * Returns the type string as it should appear in the mysql create table statement for the given column
216
+     * @return string The type string
217
+     */
218
+    private function getDatabaseTypeString($colName, $type, $length)
219
+    {
220
+        switch (strtoupper($type)) {
221
+            case '':
222
+                throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
223 223
 				
224
-			case 'DATETIME':
225
-			case 'DATE':
226
-			case 'TIME':
227
-			case 'TEXT':
228
-			case 'INT UNSIGNED':
229
-				return $type;
230
-
231
-			case 'VARCHAR':
232
-				if ($length === null) {
233
-					throw new ActiveRecordException(sprintf("field type %s requires specified column field \"LENGTH\"", $colName));
234
-				} else {
235
-					return sprintf('%s(%d)', $type, $length);	
236
-				}
237
-
238
-			case 'INT':
239
-			case 'TINYINT':
240
-			case 'BIGINT':
241
-			default: 	
242
-			// @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
243
-				if ($length === null) {
244
-					return $type;
245
-				} else {
246
-					return sprintf('%s(%d)', $type, $length);	
247
-				}
248
-		}
249
-	}
250
-
251
-	/**
252
-	 * Builds the part of a MySQL create table statement that corresponds to the supplied column
253
-	 * @param string $colName 	Name of the database column
254
-	 * @param string $type 		The type of the string
255
-	 * @param int $properties 	The set of Column properties that apply to this column (See ColumnProperty for options)
256
-	 * @return string
257
-	 */
258
-	private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
259
-	{
260
-		$stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
261
-		if ($properties & ColumnProperty::NOT_NULL) {
262
-			$stmnt .= 'NOT NULL ';
263
-		} else {
264
-			$stmnt .= 'NULL ';
265
-		}
266
-
267
-		if ($default !== NULL) {
268
-			$stmnt .= ' DEFAULT ' . $default . ' ';
269
-		}
270
-
271
-		if ($properties & ColumnProperty::AUTO_INCREMENT) {
272
-			$stmnt .= 'AUTO_INCREMENT ';
273
-		}
274
-
275
-		if ($properties & ColumnProperty::UNIQUE) {
276
-			$stmnt .= 'UNIQUE ';
277
-		}
278
-
279
-		if ($properties & ColumnProperty::PRIMARY_KEY) {
280
-			$stmnt .= 'PRIMARY KEY ';
281
-		}
282
-
283
-		return $stmnt;
284
-	}
285
-
286
-	/**
287
-	 * Sorts the column statement components in the order such that the id appears first, 
288
-	 * 		followed by all other columns in alphabetical ascending order
289
-	 * @param   Array $colStatements Array of column statements
290
-	 * @return  Array
291
-	 */
292
-	private function sortColumnStatements($colStatements)
293
-	{
294
-		// Find ID statement and put it first
295
-		$sortedStatements = [];
296
-
297
-		$sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
298
-		unset($colStatements[self::COLUMN_NAME_ID]);
299
-
300
-		// Sort remaining columns in alphabetical order
301
-		$columns = array_keys($colStatements);
302
-		sort($columns);
303
-		foreach ($columns as $colName) {
304
-			$sortedStatements[] = $colStatements[$colName];
305
-		}
306
-
307
-		return $sortedStatements;
308
-	}
309
-
310
-	/**
311
-	 * Builds the MySQL Create Table statement for the internal table definition
312
-	 * @return string
313
-	 */
314
-	public function buildCreateTableSQL()
315
-	{
316
-		$columnStatements = [];
317
-		foreach ($this->tableDefinition as $colName => $definition) {
318
-			// Destructure column definition
319
-			$type    = $definition['type'] ?? null;
320
-			$default = $definition['default'] ?? null;
321
-			$length  = $definition['length'] ?? null;
322
-			$properties = $definition['properties'] ?? null;
323
-
324
-			if (isset($definition['relation']) && $type !== null) {
325
-				$msg = "Column \"$colName\": ";
326
-				$msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
327
-				throw new ActiveRecordException($msg);
328
-			} else if (isset($definition['relation'])) {
329
-				$type = self::COLUMN_TYPE_ID;
330
-			}
331
-
332
-			$columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
333
-		}
334
-
335
-		// Sort table (first column is id, the remaining are alphabetically sorted)
336
-		$columnStatements = $this->sortColumnStatements($columnStatements);
337
-
338
-		$sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
339
-		$sql .= "(\n";
340
-		$sql .= join($columnStatements, ",\n");
341
-		$sql .= "\n);";
342
-
343
-		return $sql;
344
-	}
345
-
346
-	/**
347
-	 * Creates the entity as a table in the database
348
-	 */
349
-	public function createTable()
350
-	{
351
-		$this->pdo->query($this->buildCreateTableSQL());
352
-	}
353
-
354
-	/**
355
-	 * builds a MySQL constraint statement for the given parameters
356
-	 * @param string $parentTable
357
-	 * @param string $parentColumn
358
-	 * @param string $childTable
359
-	 * @param string $childColumn
360
-	 * @return string The MySQL table constraint string
361
-	 */
362
-	protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
363
-	{
364
-		$template = <<<SQL
224
+            case 'DATETIME':
225
+            case 'DATE':
226
+            case 'TIME':
227
+            case 'TEXT':
228
+            case 'INT UNSIGNED':
229
+                return $type;
230
+
231
+            case 'VARCHAR':
232
+                if ($length === null) {
233
+                    throw new ActiveRecordException(sprintf("field type %s requires specified column field \"LENGTH\"", $colName));
234
+                } else {
235
+                    return sprintf('%s(%d)', $type, $length);	
236
+                }
237
+
238
+            case 'INT':
239
+            case 'TINYINT':
240
+            case 'BIGINT':
241
+            default: 	
242
+            // @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
243
+                if ($length === null) {
244
+                    return $type;
245
+                } else {
246
+                    return sprintf('%s(%d)', $type, $length);	
247
+                }
248
+        }
249
+    }
250
+
251
+    /**
252
+     * Builds the part of a MySQL create table statement that corresponds to the supplied column
253
+     * @param string $colName 	Name of the database column
254
+     * @param string $type 		The type of the string
255
+     * @param int $properties 	The set of Column properties that apply to this column (See ColumnProperty for options)
256
+     * @return string
257
+     */
258
+    private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
259
+    {
260
+        $stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
261
+        if ($properties & ColumnProperty::NOT_NULL) {
262
+            $stmnt .= 'NOT NULL ';
263
+        } else {
264
+            $stmnt .= 'NULL ';
265
+        }
266
+
267
+        if ($default !== NULL) {
268
+            $stmnt .= ' DEFAULT ' . $default . ' ';
269
+        }
270
+
271
+        if ($properties & ColumnProperty::AUTO_INCREMENT) {
272
+            $stmnt .= 'AUTO_INCREMENT ';
273
+        }
274
+
275
+        if ($properties & ColumnProperty::UNIQUE) {
276
+            $stmnt .= 'UNIQUE ';
277
+        }
278
+
279
+        if ($properties & ColumnProperty::PRIMARY_KEY) {
280
+            $stmnt .= 'PRIMARY KEY ';
281
+        }
282
+
283
+        return $stmnt;
284
+    }
285
+
286
+    /**
287
+     * Sorts the column statement components in the order such that the id appears first, 
288
+     * 		followed by all other columns in alphabetical ascending order
289
+     * @param   Array $colStatements Array of column statements
290
+     * @return  Array
291
+     */
292
+    private function sortColumnStatements($colStatements)
293
+    {
294
+        // Find ID statement and put it first
295
+        $sortedStatements = [];
296
+
297
+        $sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
298
+        unset($colStatements[self::COLUMN_NAME_ID]);
299
+
300
+        // Sort remaining columns in alphabetical order
301
+        $columns = array_keys($colStatements);
302
+        sort($columns);
303
+        foreach ($columns as $colName) {
304
+            $sortedStatements[] = $colStatements[$colName];
305
+        }
306
+
307
+        return $sortedStatements;
308
+    }
309
+
310
+    /**
311
+     * Builds the MySQL Create Table statement for the internal table definition
312
+     * @return string
313
+     */
314
+    public function buildCreateTableSQL()
315
+    {
316
+        $columnStatements = [];
317
+        foreach ($this->tableDefinition as $colName => $definition) {
318
+            // Destructure column definition
319
+            $type    = $definition['type'] ?? null;
320
+            $default = $definition['default'] ?? null;
321
+            $length  = $definition['length'] ?? null;
322
+            $properties = $definition['properties'] ?? null;
323
+
324
+            if (isset($definition['relation']) && $type !== null) {
325
+                $msg = "Column \"$colName\": ";
326
+                $msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
327
+                throw new ActiveRecordException($msg);
328
+            } else if (isset($definition['relation'])) {
329
+                $type = self::COLUMN_TYPE_ID;
330
+            }
331
+
332
+            $columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
333
+        }
334
+
335
+        // Sort table (first column is id, the remaining are alphabetically sorted)
336
+        $columnStatements = $this->sortColumnStatements($columnStatements);
337
+
338
+        $sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
339
+        $sql .= "(\n";
340
+        $sql .= join($columnStatements, ",\n");
341
+        $sql .= "\n);";
342
+
343
+        return $sql;
344
+    }
345
+
346
+    /**
347
+     * Creates the entity as a table in the database
348
+     */
349
+    public function createTable()
350
+    {
351
+        $this->pdo->query($this->buildCreateTableSQL());
352
+    }
353
+
354
+    /**
355
+     * builds a MySQL constraint statement for the given parameters
356
+     * @param string $parentTable
357
+     * @param string $parentColumn
358
+     * @param string $childTable
359
+     * @param string $childColumn
360
+     * @return string The MySQL table constraint string
361
+     */
362
+    protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
363
+    {
364
+        $template = <<<SQL
365 365
 ALTER TABLE `%s`
366 366
 ADD CONSTRAINT
367 367
 FOREIGN KEY (`%s`)
368 368
 REFERENCES `%s`(`%s`)
369 369
 ON DELETE CASCADE;
370 370
 SQL;
371
-		return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
372
-	}
373
-
374
-	/**
375
-	 * Iterates over the specified constraints in the table definition, 
376
-	 * 		and applies these to the database.
377
-	 */
378
-	public function createTableConstraints()
379
-	{
380
-		// Iterate over columns, check whether "relation" field exists, if so create constraint
381
-		foreach ($this->tableDefinition as $colName => $definition) {
382
-			if (isset($definition['relation']) && $definition['relation'] instanceof AbstractActiveRecord) {
383
-				// Forge new relation
384
-				$target = $definition['relation'];
385
-				$constraintSql = $this->buildConstraint($target->getActiveRecordTable(), 'id', $this->getActiveRecordTable(), $colName);
386
-
387
-				$this->pdo->query($constraintSql);
388
-			}
389
-		}
390
-	}
391
-
392
-	/**
393
-	 * Returns the name -> variable mapping for the table definition.
394
-	 * @return Array The mapping
395
-	 */
396
-	protected function getActiveRecordColumns()
397
-	{
398
-		$bindings = [];
399
-		foreach ($this->tableDefinition as $colName => $definition) {
400
-
401
-			// Ignore the id column (key) when inserting or updating
402
-			if ($colName == self::COLUMN_NAME_ID) {
403
-				continue;
404
-			}
405
-
406
-			$bindings[$colName] = &$definition['value'];
407
-		}
408
-		return $bindings;
409
-	}
410
-
411
-	/**
412
-	 * {@inheritdoc}
413
-	 */
414
-	public function create()
415
-	{
416
-		foreach ($this->registeredCreateHooks as $colName => $fn) {
417
-			// @TODO: Would it be better to pass the Query to the function?
418
-			$fn();
419
-		}
420
-
421
-		try {
422
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
423
-				->insert($this->getActiveRecordColumns())
424
-				->execute();
425
-
426
-			$this->setId(intval($this->getPdo()->lastInsertId()));
427
-		} catch (\PDOException $e) {
428
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
429
-		}
430
-
431
-		return $this;
432
-	}
433
-
434
-	/**
435
-	 * {@inheritdoc}
436
-	 */
437
-	public function read($id)
438
-	{
439
-		foreach ($this->registeredReadHooks as $colName => $fn) {
440
-			// @TODO: Would it be better to pass the Query to the function?
441
-			$fn();
442
-		}
443
-
444
-		try {
445
-			$row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
446
-				->select()
447
-				->where('id', '=', $id)
448
-				->execute()
449
-				->fetch();
450
-
451
-			if ($row === false) {
452
-				throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
453
-			}
454
-
455
-			$this->fill($row)->setId($id);
456
-		} catch (\PDOException $e) {
457
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
458
-		}
459
-
460
-		return $this;
461
-	}
462
-
463
-	/**
464
-	 * {@inheritdoc}
465
-	 */
466
-	public function update()
467
-	{
468
-		foreach ($this->registeredUpdateHooks as $colName => $fn) {
469
-			// @TODO: Would it be better to pass the Query to the function?
470
-			$fn();
471
-		}
472
-
473
-		try {
474
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
475
-				->update($this->getActiveRecordColumns())
476
-				->where('id', '=', $this->getId())
477
-				->execute();
478
-		} catch (\PDOException $e) {
479
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
480
-		}
481
-
482
-		return $this;
483
-	}
484
-
485
-	/**
486
-	 * {@inheritdoc}
487
-	 */
488
-	public function delete()
489
-	{
490
-		foreach ($this->registeredDeleteHooks as $colName => $fn) {
491
-			// @TODO: Would it be better to pass the Query to the function?
492
-			$fn();
493
-		}
494
-
495
-		try {
496
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
497
-				->delete()
498
-				->where('id', '=', $this->getId())
499
-				->execute();
500
-
501
-			$this->setId(null);
502
-		} catch (\PDOException $e) {
503
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
504
-		}
505
-
506
-		return $this;
507
-	}
508
-
509
-	/**
510
-	 * {@inheritdoc}
511
-	 */
512
-	public function sync()
513
-	{
514
-		if (!$this->exists()) {
515
-			return $this->create();
516
-		}
517
-
518
-		return $this->update();
519
-	}
520
-
521
-	/**
522
-	 * {@inheritdoc}
523
-	 */
524
-	public function exists()
525
-	{
526
-		return $this->getId() !== null;
527
-	}
528
-
529
-	/**
530
-	 * {@inheritdoc}
531
-	 */
532
-	public function fill(array $attributes)
533
-	{
534
-		$columns = $this->getActiveRecordColumns();
535
-		$columns['id'] = &$this->id;
536
-
537
-		foreach ($attributes as $key => $value) {
538
-			if (array_key_exists($key, $columns)) {
539
-				$columns[$key] = $value;
540
-			}
541
-		}
542
-
543
-		return $this;
544
-	}
545
-
546
-	/**
547
-	 * {@inheritdoc}
548
-	 */
549
-	public function searchOne(array $where = [], array $orderBy = [])
550
-	{
551
-		try {
552
-			$row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
553
-
554
-			if ($row === false) {
555
-				throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
556
-			}
557
-
558
-			return $this->fill($row)->setId($row['id']);
559
-		} catch (\PDOException $e) {
560
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
561
-		}
562
-	}
563
-
564
-	/**
565
-	 * {@inheritdoc}
566
-	 */
567
-	public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
568
-	{
569
-		try {
570
-			$queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
571
-			$result = [];
572
-
573
-			foreach ($queryResult as $row) {
574
-				$new = clone $this;
575
-
576
-				$result[] = $new->fill($row)->setId($row['id']);
577
-			}
578
-
579
-			return $result;
580
-		} catch (\PDOException $e) {
581
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
582
-		}
583
-	}
584
-
585
-	/**
586
-	 * Returns the search query result with the given where, order by, limit and offset clauses.
587
-	 *
588
-	 * @param array $where = []
589
-	 * @param array $orderBy = []
590
-	 * @param int $limit = -1
591
-	 * @param int $offset = 0
592
-	 * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
593
-	 */
594
-	private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
595
-	{
596
-		$query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
597
-			->select();
598
-
599
-		$this->getSearchQueryWhere($query, $where);
600
-		$this->getSearchQueryOrderBy($query, $orderBy);
601
-		$this->getSearchQueryLimit($query, $limit, $offset);
602
-
603
-		// Ignore all trait modifiers for which a where clause was specified
604
-		$registeredSearchHooks = $this->registeredSearchHooks;
605
-		foreach ($where as $index => $clause) {
606
-			$colName = $clause[0];
607
-			unset($registeredSearchHooks[$colName]);
608
-		}
609
-
610
-		// Allow traits to modify the query
611
-		foreach ($registeredSearchHooks as $column => $searchFunction) {
612
-			$searchFunction($query);
613
-		}
614
-
615
-		return $query->execute();
616
-	}
617
-
618
-	/**
619
-	 * Returns the given query after adding the given where conditions.
620
-	 *
621
-	 * @param \miBadger\Query\Query $query
622
-	 * @param array $where
623
-	 * @return \miBadger\Query\Query the given query after adding the given where conditions.
624
-	 */
625
-	private function getSearchQueryWhere($query, $where)
626
-	{
627
-		foreach ($where as $key => $value) {
628
-			$query->where($value[0], $value[1], $value[2]);
629
-		}
630
-
631
-		return $query;
632
-	}
633
-
634
-	/**
635
-	 * Returns the given query after adding the given order by conditions.
636
-	 *
637
-	 * @param \miBadger\Query\Query $query
638
-	 * @param array $orderBy
639
-	 * @return \miBadger\Query\Query the given query after adding the given order by conditions.
640
-	 */
641
-	private function getSearchQueryOrderBy($query, $orderBy)
642
-	{
643
-		foreach ($orderBy as $key => $value) {
644
-			$query->orderBy($key, $value);
645
-		}
646
-
647
-		return $query;
648
-	}
649
-
650
-	/**
651
-	 * Returns the given query after adding the given limit and offset conditions.
652
-	 *
653
-	 * @param \miBadger\Query\Query $query
654
-	 * @param int $limit
655
-	 * @param int $offset
656
-	 * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
657
-	 */
658
-	private function getSearchQueryLimit($query, $limit, $offset)
659
-	{
660
-		if ($limit > -1) {
661
-			$query->limit($limit);
662
-			$query->offset($offset);
663
-		}
664
-
665
-		return $query;
666
-	}
667
-
668
-	/**
669
-	 * Returns the PDO.
670
-	 *
671
-	 * @return \PDO the PDO.
672
-	 */
673
-	public function getPdo()
674
-	{
675
-		return $this->pdo;
676
-	}
677
-
678
-	/**
679
-	 * Set the PDO.
680
-	 *
681
-	 * @param \PDO $pdo
682
-	 * @return $this
683
-	 */
684
-	protected function setPdo($pdo)
685
-	{
686
-		$this->pdo = $pdo;
687
-
688
-		return $this;
689
-	}
690
-
691
-	/**
692
-	 * Returns the ID.
693
-	 *
694
-	 * @return null|int The ID.
695
-	 */
696
-	public function getId()
697
-	{
698
-		return $this->id;
699
-	}
700
-
701
-	/**
702
-	 * Set the ID.
703
-	 *
704
-	 * @param int $id
705
-	 * @return $this
706
-	 */
707
-	protected function setId($id)
708
-	{
709
-		$this->id = $id;
710
-
711
-		return $this;
712
-	}
713
-
714
-	/**
715
-	 * Returns the active record table.
716
-	 *
717
-	 * @return string the active record table.
718
-	 */
719
-	abstract protected function getActiveRecordTable();
720
-
721
-	/**
722
-	 * Returns the active record columns.
723
-	 *
724
-	 * @return array the active record columns.
725
-	 */
726
-	abstract protected function getActiveRecordTableDefinition();
371
+        return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
372
+    }
373
+
374
+    /**
375
+     * Iterates over the specified constraints in the table definition, 
376
+     * 		and applies these to the database.
377
+     */
378
+    public function createTableConstraints()
379
+    {
380
+        // Iterate over columns, check whether "relation" field exists, if so create constraint
381
+        foreach ($this->tableDefinition as $colName => $definition) {
382
+            if (isset($definition['relation']) && $definition['relation'] instanceof AbstractActiveRecord) {
383
+                // Forge new relation
384
+                $target = $definition['relation'];
385
+                $constraintSql = $this->buildConstraint($target->getActiveRecordTable(), 'id', $this->getActiveRecordTable(), $colName);
386
+
387
+                $this->pdo->query($constraintSql);
388
+            }
389
+        }
390
+    }
391
+
392
+    /**
393
+     * Returns the name -> variable mapping for the table definition.
394
+     * @return Array The mapping
395
+     */
396
+    protected function getActiveRecordColumns()
397
+    {
398
+        $bindings = [];
399
+        foreach ($this->tableDefinition as $colName => $definition) {
400
+
401
+            // Ignore the id column (key) when inserting or updating
402
+            if ($colName == self::COLUMN_NAME_ID) {
403
+                continue;
404
+            }
405
+
406
+            $bindings[$colName] = &$definition['value'];
407
+        }
408
+        return $bindings;
409
+    }
410
+
411
+    /**
412
+     * {@inheritdoc}
413
+     */
414
+    public function create()
415
+    {
416
+        foreach ($this->registeredCreateHooks as $colName => $fn) {
417
+            // @TODO: Would it be better to pass the Query to the function?
418
+            $fn();
419
+        }
420
+
421
+        try {
422
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
423
+                ->insert($this->getActiveRecordColumns())
424
+                ->execute();
425
+
426
+            $this->setId(intval($this->getPdo()->lastInsertId()));
427
+        } catch (\PDOException $e) {
428
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
429
+        }
430
+
431
+        return $this;
432
+    }
433
+
434
+    /**
435
+     * {@inheritdoc}
436
+     */
437
+    public function read($id)
438
+    {
439
+        foreach ($this->registeredReadHooks as $colName => $fn) {
440
+            // @TODO: Would it be better to pass the Query to the function?
441
+            $fn();
442
+        }
443
+
444
+        try {
445
+            $row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
446
+                ->select()
447
+                ->where('id', '=', $id)
448
+                ->execute()
449
+                ->fetch();
450
+
451
+            if ($row === false) {
452
+                throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
453
+            }
454
+
455
+            $this->fill($row)->setId($id);
456
+        } catch (\PDOException $e) {
457
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
458
+        }
459
+
460
+        return $this;
461
+    }
462
+
463
+    /**
464
+     * {@inheritdoc}
465
+     */
466
+    public function update()
467
+    {
468
+        foreach ($this->registeredUpdateHooks as $colName => $fn) {
469
+            // @TODO: Would it be better to pass the Query to the function?
470
+            $fn();
471
+        }
472
+
473
+        try {
474
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
475
+                ->update($this->getActiveRecordColumns())
476
+                ->where('id', '=', $this->getId())
477
+                ->execute();
478
+        } catch (\PDOException $e) {
479
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
480
+        }
481
+
482
+        return $this;
483
+    }
484
+
485
+    /**
486
+     * {@inheritdoc}
487
+     */
488
+    public function delete()
489
+    {
490
+        foreach ($this->registeredDeleteHooks as $colName => $fn) {
491
+            // @TODO: Would it be better to pass the Query to the function?
492
+            $fn();
493
+        }
494
+
495
+        try {
496
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
497
+                ->delete()
498
+                ->where('id', '=', $this->getId())
499
+                ->execute();
500
+
501
+            $this->setId(null);
502
+        } catch (\PDOException $e) {
503
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
504
+        }
505
+
506
+        return $this;
507
+    }
508
+
509
+    /**
510
+     * {@inheritdoc}
511
+     */
512
+    public function sync()
513
+    {
514
+        if (!$this->exists()) {
515
+            return $this->create();
516
+        }
517
+
518
+        return $this->update();
519
+    }
520
+
521
+    /**
522
+     * {@inheritdoc}
523
+     */
524
+    public function exists()
525
+    {
526
+        return $this->getId() !== null;
527
+    }
528
+
529
+    /**
530
+     * {@inheritdoc}
531
+     */
532
+    public function fill(array $attributes)
533
+    {
534
+        $columns = $this->getActiveRecordColumns();
535
+        $columns['id'] = &$this->id;
536
+
537
+        foreach ($attributes as $key => $value) {
538
+            if (array_key_exists($key, $columns)) {
539
+                $columns[$key] = $value;
540
+            }
541
+        }
542
+
543
+        return $this;
544
+    }
545
+
546
+    /**
547
+     * {@inheritdoc}
548
+     */
549
+    public function searchOne(array $where = [], array $orderBy = [])
550
+    {
551
+        try {
552
+            $row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
553
+
554
+            if ($row === false) {
555
+                throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
556
+            }
557
+
558
+            return $this->fill($row)->setId($row['id']);
559
+        } catch (\PDOException $e) {
560
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
561
+        }
562
+    }
563
+
564
+    /**
565
+     * {@inheritdoc}
566
+     */
567
+    public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
568
+    {
569
+        try {
570
+            $queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
571
+            $result = [];
572
+
573
+            foreach ($queryResult as $row) {
574
+                $new = clone $this;
575
+
576
+                $result[] = $new->fill($row)->setId($row['id']);
577
+            }
578
+
579
+            return $result;
580
+        } catch (\PDOException $e) {
581
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
582
+        }
583
+    }
584
+
585
+    /**
586
+     * Returns the search query result with the given where, order by, limit and offset clauses.
587
+     *
588
+     * @param array $where = []
589
+     * @param array $orderBy = []
590
+     * @param int $limit = -1
591
+     * @param int $offset = 0
592
+     * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
593
+     */
594
+    private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
595
+    {
596
+        $query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
597
+            ->select();
598
+
599
+        $this->getSearchQueryWhere($query, $where);
600
+        $this->getSearchQueryOrderBy($query, $orderBy);
601
+        $this->getSearchQueryLimit($query, $limit, $offset);
602
+
603
+        // Ignore all trait modifiers for which a where clause was specified
604
+        $registeredSearchHooks = $this->registeredSearchHooks;
605
+        foreach ($where as $index => $clause) {
606
+            $colName = $clause[0];
607
+            unset($registeredSearchHooks[$colName]);
608
+        }
609
+
610
+        // Allow traits to modify the query
611
+        foreach ($registeredSearchHooks as $column => $searchFunction) {
612
+            $searchFunction($query);
613
+        }
614
+
615
+        return $query->execute();
616
+    }
617
+
618
+    /**
619
+     * Returns the given query after adding the given where conditions.
620
+     *
621
+     * @param \miBadger\Query\Query $query
622
+     * @param array $where
623
+     * @return \miBadger\Query\Query the given query after adding the given where conditions.
624
+     */
625
+    private function getSearchQueryWhere($query, $where)
626
+    {
627
+        foreach ($where as $key => $value) {
628
+            $query->where($value[0], $value[1], $value[2]);
629
+        }
630
+
631
+        return $query;
632
+    }
633
+
634
+    /**
635
+     * Returns the given query after adding the given order by conditions.
636
+     *
637
+     * @param \miBadger\Query\Query $query
638
+     * @param array $orderBy
639
+     * @return \miBadger\Query\Query the given query after adding the given order by conditions.
640
+     */
641
+    private function getSearchQueryOrderBy($query, $orderBy)
642
+    {
643
+        foreach ($orderBy as $key => $value) {
644
+            $query->orderBy($key, $value);
645
+        }
646
+
647
+        return $query;
648
+    }
649
+
650
+    /**
651
+     * Returns the given query after adding the given limit and offset conditions.
652
+     *
653
+     * @param \miBadger\Query\Query $query
654
+     * @param int $limit
655
+     * @param int $offset
656
+     * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
657
+     */
658
+    private function getSearchQueryLimit($query, $limit, $offset)
659
+    {
660
+        if ($limit > -1) {
661
+            $query->limit($limit);
662
+            $query->offset($offset);
663
+        }
664
+
665
+        return $query;
666
+    }
667
+
668
+    /**
669
+     * Returns the PDO.
670
+     *
671
+     * @return \PDO the PDO.
672
+     */
673
+    public function getPdo()
674
+    {
675
+        return $this->pdo;
676
+    }
677
+
678
+    /**
679
+     * Set the PDO.
680
+     *
681
+     * @param \PDO $pdo
682
+     * @return $this
683
+     */
684
+    protected function setPdo($pdo)
685
+    {
686
+        $this->pdo = $pdo;
687
+
688
+        return $this;
689
+    }
690
+
691
+    /**
692
+     * Returns the ID.
693
+     *
694
+     * @return null|int The ID.
695
+     */
696
+    public function getId()
697
+    {
698
+        return $this->id;
699
+    }
700
+
701
+    /**
702
+     * Set the ID.
703
+     *
704
+     * @param int $id
705
+     * @return $this
706
+     */
707
+    protected function setId($id)
708
+    {
709
+        $this->id = $id;
710
+
711
+        return $this;
712
+    }
713
+
714
+    /**
715
+     * Returns the active record table.
716
+     *
717
+     * @return string the active record table.
718
+     */
719
+    abstract protected function getActiveRecordTable();
720
+
721
+    /**
722
+     * Returns the active record columns.
723
+     *
724
+     * @return array the active record columns.
725
+     */
726
+    abstract protected function getActiveRecordTableDefinition();
727 727
 }
Please login to merge, or discard this patch.