Test Failed
Push — v2 ( 737a06 )
by Berend
03:55
created
src/AbstractActiveRecord.php 3 patches
Doc Comments   +4 added lines patch added patch discarded remove patch
@@ -363,6 +363,10 @@
 block discarded – undo
363 363
 		$this->pdo->query($this->buildCreateTableSQL());
364 364
 	}
365 365
 
366
+	/**
367
+	 * @param string $parentColumn
368
+	 * @param string $childTable
369
+	 */
366 370
 	protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
367 371
 	{
368 372
 		$template = <<<SQL
Please login to merge, or discard this patch.
Indentation   +696 added lines, -696 removed lines patch added patch discarded remove patch
@@ -18,706 +18,706 @@
 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
-	private $registeredCreateHooks;
32
-
33
-	/** @var array A map of column name to functions that hook the read function */
34
-	private $registeredReadHooks;
35
-
36
-	/** @var array A map of column name to functions that hook the update function */
37
-	private $registeredUpdateHooks;
38
-
39
-	/** @var array A map of column name to functions that hook the update function */
40
-	private $registeredDeleteHooks;	
41
-
42
-	/** @var array A map of column name to functions that hook the search function */
43
-	private $registeredSearchHooks;
44
-
45
-	/** @var array A list of table column definitions */
46
-	private $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
-	/**
83
-	 * Register a new hook for a specific column that gets called before execution of the create() method
84
-	 * Only one hook per column can be registered at a time
85
-	 * @param string $columnName The name of the column that is registered.
86
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
87
-	 */
88
-	public function registerCreateHook($columnName, $fn) 
89
-	{
90
-		// Check whether column exists
91
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
92
-		{
93
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
94
-		}
95
-
96
-		// Enforcing 1 hook per table column
97
-		if (array_key_exists($columnName, $this->registeredCreateHooks)) {
98
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
99
-			$message .= "do you have conflicting traits?";
100
-			throw new ActiveRecordException($message, 0);
101
-		}
102
-
103
-		if (is_string($fn) && is_callable([$this, $fn])) {
104
-			$this->registeredCreateHooks[$columnName] = [$this, $fn];
105
-		} else if (is_callable($fn)) {
106
-			$this->registeredCreateHooks[$columnName] = $fn;
107
-		} else {
108
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * Register a new hook for a specific column that gets called before execution of the read() method
114
-	 * Only one hook per column can be registered at a time
115
-	 * @param string $columnName The name of the column that is registered.
116
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
117
-	 */
118
-	public function registerReadHook($columnName, $fn)
119
-	{
120
-		// Check whether column exists
121
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
122
-		{
123
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
124
-		}
125
-
126
-		// Enforcing 1 hook per table column
127
-		if (array_key_exists($columnName, $this->registeredReadHooks)) {
128
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
129
-			$message .= "do you have conflicting traits?";
130
-			throw new ActiveRecordException($message, 0);
131
-		}
132
-
133
-		if (is_string($fn) && is_callable([$this, $fn])) {
134
-			$this->registeredReadHooks[$columnName] = [$this, $fn];
135
-		} else if (is_callable($fn)) {
136
-			$this->registeredReadHooks[$columnName] = $fn;
137
-		} else {
138
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
139
-		}
140
-	}
141
-
142
-	/**
143
-	 * Register a new hook for a specific column that gets called before execution of the update() method
144
-	 * Only one hook per column can be registered at a time
145
-	 * @param string $columnName The name of the column that is registered.
146
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
147
-	 */
148
-	public function registerUpdateHook($columnName, $fn)
149
-	{
150
-		// Check whether column exists
151
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
152
-		{
153
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
154
-		}
155
-
156
-		// Enforcing 1 hook per table column
157
-		if (array_key_exists($columnName, $this->registeredUpdateHooks)) {
158
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
159
-			$message .= "do you have conflicting traits?";
160
-			throw new ActiveRecordException($message, 0);
161
-		}
162
-
163
-		if (is_string($fn) && is_callable([$this, $fn])) {
164
-			$this->registeredUpdateHooks[$columnName] = [$this, $fn];
165
-		} else if (is_callable($fn)) {
166
-			$this->registeredUpdateHooks[$columnName] = $fn;
167
-		} else {
168
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
169
-		}
170
-	}
171
-
172
-	/**
173
-	 * Register a new hook for a specific column that gets called before execution of the delete() method
174
-	 * Only one hook per column can be registered at a time
175
-	 * @param string $columnName The name of the column that is registered.
176
-	 * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
177
-	 */
178
-	public function registerDeleteHook($columnName, $fn)
179
-	{
180
-		// Check whether column exists
181
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
182
-		{
183
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
184
-		}
185
-
186
-		// Enforcing 1 hook per table column
187
-		if (array_key_exists($columnName, $this->registeredDeleteHooks)) {
188
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
189
-			$message .= "do you have conflicting traits?";
190
-			throw new ActiveRecordException($message, 0);
191
-		}
192
-
193
-		if (is_string($fn) && is_callable([$this, $fn])) {
194
-			$this->registeredDeleteHooks[$columnName] = [$this, $fn];
195
-		} else if (is_callable($fn)) {
196
-			$this->registeredDeleteHooks[$columnName] = $fn;
197
-		} else {
198
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
199
-		}
200
-	}
201
-
202
-	/**
203
-	 * Register a new hook for a specific column that gets called before execution of the search() method
204
-	 * Only one hook per column can be registered at a time
205
-	 * @param string $columnName The name of the column that is registered.
206
-	 * @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; 
207
-	 */
208
-	public function registerSearchHook($columnName, $fn)
209
-	{
210
-		// Check whether column exists
211
-		if (!array_key_exists($columnName, $this->tableDefinition)) 
212
-		{
213
-			throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
214
-		}
215
-
216
-		// Enforcing 1 hook per table column
217
-		if (array_key_exists($columnName, $this->registeredSearchHooks)) {
218
-			$message = "Hook is trying to register on an already registered column \"$columnName\", ";
219
-			$message .= "do you have conflicting traits?";
220
-			throw new ActiveRecordException($message, 0);
221
-		}
222
-
223
-		if (is_string($fn) && is_callable([$this, $fn])) {
224
-			$this->registeredSearchHooks[$columnName] = [$this, $fn];
225
-		} else if (is_callable($fn)) {
226
-			$this->registeredSearchHooks[$columnName] = $fn;
227
-		} else {
228
-			throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
229
-		}
230
-	}
231
-
232
-	/**
233
-	 * Adds a new column definition to the table.
234
-	 * @param string $columnName The name of the column that is registered.
235
-	 * @param Array $definition The definition of that column.
236
-	 */
237
-	public function extendTableDefinition($columnName, $definition)
238
-	{
239
-		// Enforcing table can only be extended with new columns
240
-		if (array_key_exists($columnName, $this->tableDefinition)) {
241
-			$message = "Table is being extended with a column that already exists, ";
242
-			$message .= "\"$columnName\" conflicts with your table definition";
243
-			throw new ActiveRecordException($message, 0);
244
-		}
245
-
246
-		$this->tableDefinition[$columnName] = $definition;
247
-	}
248
-
249
-	private function getDatabaseTypeString($colName, $type, $length)
250
-	{
251
-		if ($type === null) 
252
-		{
253
-			throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
254
-		}
255
-
256
-		switch (strtoupper($type)) {
257
-			case 'DATETIME':
258
-			case 'DATE':
259
-			case 'TIME':
260
-			case 'TEXT':
261
-			case 'INT UNSIGNED':
262
-				return $type;
263
-
264
-			case 'VARCHAR':
265
-				return sprintf('%s(%d)', $type, $length);
266
-
267
-			case 'INT':
268
-			case 'TINYINT':
269
-			case 'BIGINT':
270
-			default: 	
271
-			// @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
272
-				if ($length === null) {
273
-					return $type;
274
-				} else {
275
-					return sprintf('%s(%d)', $type, $length);	
276
-				}
277
-		}
278
-	}
279
-
280
-	private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
281
-	{
282
-
283
-		$stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
284
-		if ($properties & ColumnProperty::NOT_NULL) {
285
-			$stmnt .= 'NOT NULL ';
286
-		} else {
287
-			$stmnt .= 'NULL ';
288
-		}
289
-
290
-		if ($default !== NULL) {
291
-			$stmnt .= ' DEFAULT ' . $default . ' ';
292
-		}
293
-
294
-		if ($properties & ColumnProperty::AUTO_INCREMENT) {
295
-			$stmnt .= 'AUTO_INCREMENT ';
296
-		}
297
-
298
-		if ($properties & ColumnProperty::UNIQUE) {
299
-			$stmnt .= 'UNIQUE ';
300
-		}
301
-
302
-		if ($properties & ColumnProperty::PRIMARY_KEY) {
303
-			$stmnt .= 'PRIMARY KEY ';
304
-		}
305
-
306
-		return $stmnt;
307
-	}
308
-
309
-
310
-	private function sortColumnStatements($colStatements)
311
-	{
312
-		// Find ID statement and put it first
313
-		$sortedStatements = [];
314
-
315
-		$sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
316
-		unset($colStatements[self::COLUMN_NAME_ID]);
317
-
318
-		// Sort remaining columns in alphabetical order
319
-		$columns = array_keys($colStatements);
320
-		sort($columns);
321
-		foreach ($columns as $colName) {
322
-			$sortedStatements[] = $colStatements[$colName];
323
-		}
324
-
325
-		return $sortedStatements;
326
-	}
327
-
328
-
329
-	public function buildCreateTableSQL()
330
-	{
331
-		$columnStatements = [];
332
-		foreach ($this->tableDefinition as $colName => $definition) {
333
-			// Destructure column definition
334
-			$type    = $definition['type'] ?? null;
335
-			$default = $definition['default'] ?? null;
336
-			$length  = $definition['length'] ?? null;
337
-			$properties = $definition['properties'] ?? null;
338
-
339
-			if (isset($definition['relation']) && $type !== null) {
340
-				$msg = "Column \"$colName\": ";
341
-				$msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
342
-				throw new ActiveRecordException($msg);
343
-			} else if (isset($definition['relation'])) {
344
-				$type = self::COLUMN_TYPE_ID;
345
-			}
346
-
347
-			$columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
348
-		}
349
-
350
-		// Sort table (first column is id, the remaining are alphabetically sorted)
351
-		$columnStatements = $this->sortColumnStatements($columnStatements);
352
-
353
-		$sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
354
-		$sql .= "(\n";
355
-		$sql .= join($columnStatements, ",\n");
356
-		$sql .= "\n);";
357
-
358
-		return $sql;
359
-	}
360
-
361
-	public function createTable()
362
-	{
363
-		$this->pdo->query($this->buildCreateTableSQL());
364
-	}
365
-
366
-	protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
367
-	{
368
-		$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
+    private $registeredCreateHooks;
32
+
33
+    /** @var array A map of column name to functions that hook the read function */
34
+    private $registeredReadHooks;
35
+
36
+    /** @var array A map of column name to functions that hook the update function */
37
+    private $registeredUpdateHooks;
38
+
39
+    /** @var array A map of column name to functions that hook the update function */
40
+    private $registeredDeleteHooks;	
41
+
42
+    /** @var array A map of column name to functions that hook the search function */
43
+    private $registeredSearchHooks;
44
+
45
+    /** @var array A list of table column definitions */
46
+    private $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
+    /**
83
+     * Register a new hook for a specific column that gets called before execution of the create() method
84
+     * Only one hook per column can be registered at a time
85
+     * @param string $columnName The name of the column that is registered.
86
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
87
+     */
88
+    public function registerCreateHook($columnName, $fn) 
89
+    {
90
+        // Check whether column exists
91
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
92
+        {
93
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
94
+        }
95
+
96
+        // Enforcing 1 hook per table column
97
+        if (array_key_exists($columnName, $this->registeredCreateHooks)) {
98
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
99
+            $message .= "do you have conflicting traits?";
100
+            throw new ActiveRecordException($message, 0);
101
+        }
102
+
103
+        if (is_string($fn) && is_callable([$this, $fn])) {
104
+            $this->registeredCreateHooks[$columnName] = [$this, $fn];
105
+        } else if (is_callable($fn)) {
106
+            $this->registeredCreateHooks[$columnName] = $fn;
107
+        } else {
108
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
109
+        }
110
+    }
111
+
112
+    /**
113
+     * Register a new hook for a specific column that gets called before execution of the read() method
114
+     * Only one hook per column can be registered at a time
115
+     * @param string $columnName The name of the column that is registered.
116
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
117
+     */
118
+    public function registerReadHook($columnName, $fn)
119
+    {
120
+        // Check whether column exists
121
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
122
+        {
123
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
124
+        }
125
+
126
+        // Enforcing 1 hook per table column
127
+        if (array_key_exists($columnName, $this->registeredReadHooks)) {
128
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
129
+            $message .= "do you have conflicting traits?";
130
+            throw new ActiveRecordException($message, 0);
131
+        }
132
+
133
+        if (is_string($fn) && is_callable([$this, $fn])) {
134
+            $this->registeredReadHooks[$columnName] = [$this, $fn];
135
+        } else if (is_callable($fn)) {
136
+            $this->registeredReadHooks[$columnName] = $fn;
137
+        } else {
138
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
139
+        }
140
+    }
141
+
142
+    /**
143
+     * Register a new hook for a specific column that gets called before execution of the update() method
144
+     * Only one hook per column can be registered at a time
145
+     * @param string $columnName The name of the column that is registered.
146
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
147
+     */
148
+    public function registerUpdateHook($columnName, $fn)
149
+    {
150
+        // Check whether column exists
151
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
152
+        {
153
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
154
+        }
155
+
156
+        // Enforcing 1 hook per table column
157
+        if (array_key_exists($columnName, $this->registeredUpdateHooks)) {
158
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
159
+            $message .= "do you have conflicting traits?";
160
+            throw new ActiveRecordException($message, 0);
161
+        }
162
+
163
+        if (is_string($fn) && is_callable([$this, $fn])) {
164
+            $this->registeredUpdateHooks[$columnName] = [$this, $fn];
165
+        } else if (is_callable($fn)) {
166
+            $this->registeredUpdateHooks[$columnName] = $fn;
167
+        } else {
168
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
169
+        }
170
+    }
171
+
172
+    /**
173
+     * Register a new hook for a specific column that gets called before execution of the delete() method
174
+     * Only one hook per column can be registered at a time
175
+     * @param string $columnName The name of the column that is registered.
176
+     * @param string|callable $fn Either a callable, or the name of a method on the inheriting object.
177
+     */
178
+    public function registerDeleteHook($columnName, $fn)
179
+    {
180
+        // Check whether column exists
181
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
182
+        {
183
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
184
+        }
185
+
186
+        // Enforcing 1 hook per table column
187
+        if (array_key_exists($columnName, $this->registeredDeleteHooks)) {
188
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
189
+            $message .= "do you have conflicting traits?";
190
+            throw new ActiveRecordException($message, 0);
191
+        }
192
+
193
+        if (is_string($fn) && is_callable([$this, $fn])) {
194
+            $this->registeredDeleteHooks[$columnName] = [$this, $fn];
195
+        } else if (is_callable($fn)) {
196
+            $this->registeredDeleteHooks[$columnName] = $fn;
197
+        } else {
198
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
199
+        }
200
+    }
201
+
202
+    /**
203
+     * Register a new hook for a specific column that gets called before execution of the search() method
204
+     * Only one hook per column can be registered at a time
205
+     * @param string $columnName The name of the column that is registered.
206
+     * @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; 
207
+     */
208
+    public function registerSearchHook($columnName, $fn)
209
+    {
210
+        // Check whether column exists
211
+        if (!array_key_exists($columnName, $this->tableDefinition)) 
212
+        {
213
+            throw new ActiveRecordException("Hook is trying to register on non-existing column \"$columnName\"", 0);
214
+        }
215
+
216
+        // Enforcing 1 hook per table column
217
+        if (array_key_exists($columnName, $this->registeredSearchHooks)) {
218
+            $message = "Hook is trying to register on an already registered column \"$columnName\", ";
219
+            $message .= "do you have conflicting traits?";
220
+            throw new ActiveRecordException($message, 0);
221
+        }
222
+
223
+        if (is_string($fn) && is_callable([$this, $fn])) {
224
+            $this->registeredSearchHooks[$columnName] = [$this, $fn];
225
+        } else if (is_callable($fn)) {
226
+            $this->registeredSearchHooks[$columnName] = $fn;
227
+        } else {
228
+            throw new ActiveRecordException("Provided hook on column \"$columnName\" is not callable", 0);
229
+        }
230
+    }
231
+
232
+    /**
233
+     * Adds a new column definition to the table.
234
+     * @param string $columnName The name of the column that is registered.
235
+     * @param Array $definition The definition of that column.
236
+     */
237
+    public function extendTableDefinition($columnName, $definition)
238
+    {
239
+        // Enforcing table can only be extended with new columns
240
+        if (array_key_exists($columnName, $this->tableDefinition)) {
241
+            $message = "Table is being extended with a column that already exists, ";
242
+            $message .= "\"$columnName\" conflicts with your table definition";
243
+            throw new ActiveRecordException($message, 0);
244
+        }
245
+
246
+        $this->tableDefinition[$columnName] = $definition;
247
+    }
248
+
249
+    private function getDatabaseTypeString($colName, $type, $length)
250
+    {
251
+        if ($type === null) 
252
+        {
253
+            throw new ActiveRecordException(sprintf("Column %s has invalid type \"NULL\"", $colName));
254
+        }
255
+
256
+        switch (strtoupper($type)) {
257
+            case 'DATETIME':
258
+            case 'DATE':
259
+            case 'TIME':
260
+            case 'TEXT':
261
+            case 'INT UNSIGNED':
262
+                return $type;
263
+
264
+            case 'VARCHAR':
265
+                return sprintf('%s(%d)', $type, $length);
266
+
267
+            case 'INT':
268
+            case 'TINYINT':
269
+            case 'BIGINT':
270
+            default: 	
271
+            // @TODO(Default): throw exception, or implicitly assume that type is correct? (For when using SQL databases with different types)
272
+                if ($length === null) {
273
+                    return $type;
274
+                } else {
275
+                    return sprintf('%s(%d)', $type, $length);	
276
+                }
277
+        }
278
+    }
279
+
280
+    private function buildCreateTableColumnEntry($colName, $type, $length, $properties, $default)
281
+    {
282
+
283
+        $stmnt = sprintf('`%s` %s ', $colName, $this->getDatabaseTypeString($colName, $type, $length));
284
+        if ($properties & ColumnProperty::NOT_NULL) {
285
+            $stmnt .= 'NOT NULL ';
286
+        } else {
287
+            $stmnt .= 'NULL ';
288
+        }
289
+
290
+        if ($default !== NULL) {
291
+            $stmnt .= ' DEFAULT ' . $default . ' ';
292
+        }
293
+
294
+        if ($properties & ColumnProperty::AUTO_INCREMENT) {
295
+            $stmnt .= 'AUTO_INCREMENT ';
296
+        }
297
+
298
+        if ($properties & ColumnProperty::UNIQUE) {
299
+            $stmnt .= 'UNIQUE ';
300
+        }
301
+
302
+        if ($properties & ColumnProperty::PRIMARY_KEY) {
303
+            $stmnt .= 'PRIMARY KEY ';
304
+        }
305
+
306
+        return $stmnt;
307
+    }
308
+
309
+
310
+    private function sortColumnStatements($colStatements)
311
+    {
312
+        // Find ID statement and put it first
313
+        $sortedStatements = [];
314
+
315
+        $sortedStatements[] = $colStatements[self::COLUMN_NAME_ID];
316
+        unset($colStatements[self::COLUMN_NAME_ID]);
317
+
318
+        // Sort remaining columns in alphabetical order
319
+        $columns = array_keys($colStatements);
320
+        sort($columns);
321
+        foreach ($columns as $colName) {
322
+            $sortedStatements[] = $colStatements[$colName];
323
+        }
324
+
325
+        return $sortedStatements;
326
+    }
327
+
328
+
329
+    public function buildCreateTableSQL()
330
+    {
331
+        $columnStatements = [];
332
+        foreach ($this->tableDefinition as $colName => $definition) {
333
+            // Destructure column definition
334
+            $type    = $definition['type'] ?? null;
335
+            $default = $definition['default'] ?? null;
336
+            $length  = $definition['length'] ?? null;
337
+            $properties = $definition['properties'] ?? null;
338
+
339
+            if (isset($definition['relation']) && $type !== null) {
340
+                $msg = "Column \"$colName\": ";
341
+                $msg .= "Relationship columns have an automatically inferred type, so type should be omitted";
342
+                throw new ActiveRecordException($msg);
343
+            } else if (isset($definition['relation'])) {
344
+                $type = self::COLUMN_TYPE_ID;
345
+            }
346
+
347
+            $columnStatements[$colName] = $this->buildCreateTableColumnEntry($colName, $type, $length, $properties, $default);
348
+        }
349
+
350
+        // Sort table (first column is id, the remaining are alphabetically sorted)
351
+        $columnStatements = $this->sortColumnStatements($columnStatements);
352
+
353
+        $sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
354
+        $sql .= "(\n";
355
+        $sql .= join($columnStatements, ",\n");
356
+        $sql .= "\n);";
357
+
358
+        return $sql;
359
+    }
360
+
361
+    public function createTable()
362
+    {
363
+        $this->pdo->query($this->buildCreateTableSQL());
364
+    }
365
+
366
+    protected function buildConstraint($parentTable, $parentColumn, $childTable, $childColumn)
367
+    {
368
+        $template = <<<SQL
369 369
 ALTER TABLE `%s`
370 370
 ADD CONSTRAINT
371 371
 FOREIGN KEY (`%s`)
372 372
 REFERENCES `%s`(`%s`)
373 373
 ON DELETE CASCADE;
374 374
 SQL;
375
-		return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
376
-	}
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 ($definition['relation'] ?? null 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
-	private function getActiveRecordColumns()
393
-	{
394
-		$bindings = [];
395
-		foreach ($this->tableDefinition as $colName => $definition) {
396
-
397
-			// Ignore the id column (key) when inserting or updating
398
-			if ($colName == self::COLUMN_NAME_ID) {
399
-				continue;
400
-			}
401
-
402
-			$bindings[$colName] = &$definition['value'];
403
-		}
404
-		return $bindings;
405
-	}
406
-
407
-	/**
408
-	 * {@inheritdoc}
409
-	 */
410
-	public function create()
411
-	{
412
-		foreach ($this->registeredCreateHooks as $colName => $fn) {
413
-			// @TODO: Would it be better to pass the Query to the function?
414
-			$fn();
415
-		}
416
-
417
-		try {
418
-			$q = (new Query($this->getPdo(), $this->getActiveRecordTable()))
419
-				->insert($this->getActiveRecordColumns())
420
-				->execute();
421
-
422
-			$this->setId(intval($this->getPdo()->lastInsertId()));
423
-		} catch (\PDOException $e) {
424
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
425
-		}
426
-
427
-		return $this;
428
-	}
429
-
430
-	/**
431
-	 * {@inheritdoc}
432
-	 */
433
-	public function read($id)
434
-	{
435
-		foreach ($this->registeredReadHooks as $colName => $fn) {
436
-			// @TODO: Would it be better to pass the Query to the function?
437
-			$fn();
438
-		}
439
-
440
-		try {
441
-			$row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
442
-				->select()
443
-				->where('id', '=', $id)
444
-				->execute()
445
-				->fetch();
446
-
447
-			if ($row === false) {
448
-				throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
449
-			}
450
-
451
-			$this->fill($row)->setId($id);
452
-		} catch (\PDOException $e) {
453
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
454
-		}
455
-
456
-		return $this;
457
-	}
458
-
459
-	/**
460
-	 * {@inheritdoc}
461
-	 */
462
-	public function update()
463
-	{
464
-		foreach ($this->registeredUpdateHooks as $colName => $fn) {
465
-			// @TODO: Would it be better to pass the Query to the function?
466
-			$fn();
467
-		}
468
-
469
-		try {
470
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
471
-				->update($this->getActiveRecordColumns())
472
-				->where('id', '=', $this->getId())
473
-				->execute();
474
-		} catch (\PDOException $e) {
475
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
476
-		}
477
-
478
-		return $this;
479
-	}
480
-
481
-	/**
482
-	 * {@inheritdoc}
483
-	 */
484
-	public function delete()
485
-	{
486
-		foreach ($this->registeredDeleteHooks as $colName => $fn) {
487
-			// @TODO: Would it be better to pass the Query to the function?
488
-			$fn();
489
-		}
490
-
491
-		try {
492
-			(new Query($this->getPdo(), $this->getActiveRecordTable()))
493
-				->delete()
494
-				->where('id', '=', $this->getId())
495
-				->execute();
496
-
497
-			$this->setId(null);
498
-		} catch (\PDOException $e) {
499
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
500
-		}
501
-
502
-		return $this;
503
-	}
504
-
505
-	/**
506
-	 * {@inheritdoc}
507
-	 */
508
-	public function sync()
509
-	{
510
-		if (!$this->exists()) {
511
-			return $this->create();
512
-		}
513
-
514
-		return $this->update();
515
-	}
516
-
517
-	/**
518
-	 * {@inheritdoc}
519
-	 */
520
-	public function exists()
521
-	{
522
-		return $this->getId() !== null;
523
-	}
524
-
525
-	/**
526
-	 * {@inheritdoc}
527
-	 */
528
-	public function fill(array $attributes)
529
-	{
530
-		$columns = $this->getActiveRecordColumns();
531
-		$columns['id'] = &$this->id;
532
-
533
-		foreach ($attributes as $key => $value) {
534
-			if (array_key_exists($key, $columns)) {
535
-				$columns[$key] = $value;
536
-			}
537
-		}
538
-
539
-		return $this;
540
-	}
541
-
542
-	/**
543
-	 * {@inheritdoc}
544
-	 */
545
-	public function searchOne(array $where = [], array $orderBy = [])
546
-	{
547
-		try {
548
-			$row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
549
-
550
-			if ($row === false) {
551
-				throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
552
-			}
553
-
554
-			return $this->fill($row)->setId($row['id']);
555
-		} catch (\PDOException $e) {
556
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
557
-		}
558
-	}
559
-
560
-	/**
561
-	 * {@inheritdoc}
562
-	 */
563
-	public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
564
-	{
565
-		try {
566
-			$queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
567
-			$result = [];
568
-
569
-			foreach ($queryResult as $row) {
570
-				$new = clone $this;
571
-
572
-				$result[] = $new->fill($row)->setId($row['id']);
573
-			}
574
-
575
-			return $result;
576
-		} catch (\PDOException $e) {
577
-			throw new ActiveRecordException($e->getMessage(), 0, $e);
578
-		}
579
-	}
580
-
581
-	/**
582
-	 * Returns the search query result with the given where, order by, limit and offset clauses.
583
-	 *
584
-	 * @param array $where = []
585
-	 * @param array $orderBy = []
586
-	 * @param int $limit = -1
587
-	 * @param int $offset = 0
588
-	 * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
589
-	 */
590
-	private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
591
-	{
592
-		$query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
593
-			->select();
594
-
595
-		$this->getSearchQueryWhere($query, $where);
596
-		$this->getSearchQueryOrderBy($query, $orderBy);
597
-		$this->getSearchQueryLimit($query, $limit, $offset);
598
-
599
-		// Ignore all trait modifiers for which a where clause was specified
600
-		$registeredSearchHooks = $this->registeredSearchHooks;
601
-		foreach ($where as $index => $clause) {
602
-			[$colName, , ] = $clause;
603
-			unset($registeredSearchHooks[$colName]);
604
-		}
605
-
606
-		// Allow traits to modify the query
607
-		foreach ($registeredSearchHooks as $column => $searchFunction) {
608
-			$searchFunction($query);
609
-		}
610
-
611
-		return $query->execute();
612
-	}
613
-
614
-	/**
615
-	 * Returns the given query after adding the given where conditions.
616
-	 *
617
-	 * @param \miBadger\Query\Query $query
618
-	 * @param array $where
619
-	 * @return \miBadger\Query\Query the given query after adding the given where conditions.
620
-	 */
621
-	private function getSearchQueryWhere($query, $where)
622
-	{
623
-		foreach ($where as $key => $value) {
624
-			$query->where($value[0], $value[1], $value[2]);
625
-		}
626
-
627
-		return $query;
628
-	}
629
-
630
-	/**
631
-	 * Returns the given query after adding the given order by conditions.
632
-	 *
633
-	 * @param \miBadger\Query\Query $query
634
-	 * @param array $orderBy
635
-	 * @return \miBadger\Query\Query the given query after adding the given order by conditions.
636
-	 */
637
-	private function getSearchQueryOrderBy($query, $orderBy)
638
-	{
639
-		foreach ($orderBy as $key => $value) {
640
-			$query->orderBy($key, $value);
641
-		}
642
-
643
-		return $query;
644
-	}
645
-
646
-	/**
647
-	 * Returns the given query after adding the given limit and offset conditions.
648
-	 *
649
-	 * @param \miBadger\Query\Query $query
650
-	 * @param int $limit
651
-	 * @param int $offset
652
-	 * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
653
-	 */
654
-	private function getSearchQueryLimit($query, $limit, $offset)
655
-	{
656
-		if ($limit > -1) {
657
-			$query->limit($limit);
658
-			$query->offset($offset);
659
-		}
660
-
661
-		return $query;
662
-	}
663
-
664
-	/**
665
-	 * Returns the PDO.
666
-	 *
667
-	 * @return \PDO the PDO.
668
-	 */
669
-	public function getPdo()
670
-	{
671
-		return $this->pdo;
672
-	}
673
-
674
-	/**
675
-	 * Set the PDO.
676
-	 *
677
-	 * @param \PDO $pdo
678
-	 * @return $this
679
-	 */
680
-	protected function setPdo($pdo)
681
-	{
682
-		$this->pdo = $pdo;
683
-
684
-		return $this;
685
-	}
686
-
687
-	/**
688
-	 * Returns the ID.
689
-	 *
690
-	 * @return null|int The ID.
691
-	 */
692
-	public function getId()
693
-	{
694
-		return $this->id;
695
-	}
696
-
697
-	/**
698
-	 * Set the ID.
699
-	 *
700
-	 * @param int $id
701
-	 * @return $this
702
-	 */
703
-	protected function setId($id)
704
-	{
705
-		$this->id = $id;
706
-
707
-		return $this;
708
-	}
709
-
710
-	/**
711
-	 * Returns the active record table.
712
-	 *
713
-	 * @return string the active record table.
714
-	 */
715
-	abstract protected function getActiveRecordTable();
716
-
717
-	/**
718
-	 * Returns the active record columns.
719
-	 *
720
-	 * @return array the active record columns.
721
-	 */
722
-	abstract protected function getActiveRecordTableDefinition();
375
+        return sprintf($template, $childTable, $childColumn, $parentTable, $parentColumn);
376
+    }
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 ($definition['relation'] ?? null 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
+    private function getActiveRecordColumns()
393
+    {
394
+        $bindings = [];
395
+        foreach ($this->tableDefinition as $colName => $definition) {
396
+
397
+            // Ignore the id column (key) when inserting or updating
398
+            if ($colName == self::COLUMN_NAME_ID) {
399
+                continue;
400
+            }
401
+
402
+            $bindings[$colName] = &$definition['value'];
403
+        }
404
+        return $bindings;
405
+    }
406
+
407
+    /**
408
+     * {@inheritdoc}
409
+     */
410
+    public function create()
411
+    {
412
+        foreach ($this->registeredCreateHooks as $colName => $fn) {
413
+            // @TODO: Would it be better to pass the Query to the function?
414
+            $fn();
415
+        }
416
+
417
+        try {
418
+            $q = (new Query($this->getPdo(), $this->getActiveRecordTable()))
419
+                ->insert($this->getActiveRecordColumns())
420
+                ->execute();
421
+
422
+            $this->setId(intval($this->getPdo()->lastInsertId()));
423
+        } catch (\PDOException $e) {
424
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
425
+        }
426
+
427
+        return $this;
428
+    }
429
+
430
+    /**
431
+     * {@inheritdoc}
432
+     */
433
+    public function read($id)
434
+    {
435
+        foreach ($this->registeredReadHooks as $colName => $fn) {
436
+            // @TODO: Would it be better to pass the Query to the function?
437
+            $fn();
438
+        }
439
+
440
+        try {
441
+            $row = (new Query($this->getPdo(), $this->getActiveRecordTable()))
442
+                ->select()
443
+                ->where('id', '=', $id)
444
+                ->execute()
445
+                ->fetch();
446
+
447
+            if ($row === false) {
448
+                throw new ActiveRecordException(sprintf('Can not read the non-existent active record entry %d from the `%s` table.', $id, $this->getActiveRecordTable()));
449
+            }
450
+
451
+            $this->fill($row)->setId($id);
452
+        } catch (\PDOException $e) {
453
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
454
+        }
455
+
456
+        return $this;
457
+    }
458
+
459
+    /**
460
+     * {@inheritdoc}
461
+     */
462
+    public function update()
463
+    {
464
+        foreach ($this->registeredUpdateHooks as $colName => $fn) {
465
+            // @TODO: Would it be better to pass the Query to the function?
466
+            $fn();
467
+        }
468
+
469
+        try {
470
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
471
+                ->update($this->getActiveRecordColumns())
472
+                ->where('id', '=', $this->getId())
473
+                ->execute();
474
+        } catch (\PDOException $e) {
475
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
476
+        }
477
+
478
+        return $this;
479
+    }
480
+
481
+    /**
482
+     * {@inheritdoc}
483
+     */
484
+    public function delete()
485
+    {
486
+        foreach ($this->registeredDeleteHooks as $colName => $fn) {
487
+            // @TODO: Would it be better to pass the Query to the function?
488
+            $fn();
489
+        }
490
+
491
+        try {
492
+            (new Query($this->getPdo(), $this->getActiveRecordTable()))
493
+                ->delete()
494
+                ->where('id', '=', $this->getId())
495
+                ->execute();
496
+
497
+            $this->setId(null);
498
+        } catch (\PDOException $e) {
499
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
500
+        }
501
+
502
+        return $this;
503
+    }
504
+
505
+    /**
506
+     * {@inheritdoc}
507
+     */
508
+    public function sync()
509
+    {
510
+        if (!$this->exists()) {
511
+            return $this->create();
512
+        }
513
+
514
+        return $this->update();
515
+    }
516
+
517
+    /**
518
+     * {@inheritdoc}
519
+     */
520
+    public function exists()
521
+    {
522
+        return $this->getId() !== null;
523
+    }
524
+
525
+    /**
526
+     * {@inheritdoc}
527
+     */
528
+    public function fill(array $attributes)
529
+    {
530
+        $columns = $this->getActiveRecordColumns();
531
+        $columns['id'] = &$this->id;
532
+
533
+        foreach ($attributes as $key => $value) {
534
+            if (array_key_exists($key, $columns)) {
535
+                $columns[$key] = $value;
536
+            }
537
+        }
538
+
539
+        return $this;
540
+    }
541
+
542
+    /**
543
+     * {@inheritdoc}
544
+     */
545
+    public function searchOne(array $where = [], array $orderBy = [])
546
+    {
547
+        try {
548
+            $row = $this->getSearchQueryResult($where, $orderBy, 1)->fetch();
549
+
550
+            if ($row === false) {
551
+                throw new ActiveRecordException(sprintf('Can not search one non-existent entry from the `%s` table.', $this->getActiveRecordTable()));
552
+            }
553
+
554
+            return $this->fill($row)->setId($row['id']);
555
+        } catch (\PDOException $e) {
556
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
557
+        }
558
+    }
559
+
560
+    /**
561
+     * {@inheritdoc}
562
+     */
563
+    public function search(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
564
+    {
565
+        try {
566
+            $queryResult = $this->getSearchQueryResult($where, $orderBy, $limit, $offset);
567
+            $result = [];
568
+
569
+            foreach ($queryResult as $row) {
570
+                $new = clone $this;
571
+
572
+                $result[] = $new->fill($row)->setId($row['id']);
573
+            }
574
+
575
+            return $result;
576
+        } catch (\PDOException $e) {
577
+            throw new ActiveRecordException($e->getMessage(), 0, $e);
578
+        }
579
+    }
580
+
581
+    /**
582
+     * Returns the search query result with the given where, order by, limit and offset clauses.
583
+     *
584
+     * @param array $where = []
585
+     * @param array $orderBy = []
586
+     * @param int $limit = -1
587
+     * @param int $offset = 0
588
+     * @return \miBadger\Query\QueryResult the search query result with the given where, order by, limit and offset clauses.
589
+     */
590
+    private function getSearchQueryResult(array $where = [], array $orderBy = [], $limit = -1, $offset = 0)
591
+    {
592
+        $query = (new Query($this->getPdo(), $this->getActiveRecordTable()))
593
+            ->select();
594
+
595
+        $this->getSearchQueryWhere($query, $where);
596
+        $this->getSearchQueryOrderBy($query, $orderBy);
597
+        $this->getSearchQueryLimit($query, $limit, $offset);
598
+
599
+        // Ignore all trait modifiers for which a where clause was specified
600
+        $registeredSearchHooks = $this->registeredSearchHooks;
601
+        foreach ($where as $index => $clause) {
602
+            [$colName, , ] = $clause;
603
+            unset($registeredSearchHooks[$colName]);
604
+        }
605
+
606
+        // Allow traits to modify the query
607
+        foreach ($registeredSearchHooks as $column => $searchFunction) {
608
+            $searchFunction($query);
609
+        }
610
+
611
+        return $query->execute();
612
+    }
613
+
614
+    /**
615
+     * Returns the given query after adding the given where conditions.
616
+     *
617
+     * @param \miBadger\Query\Query $query
618
+     * @param array $where
619
+     * @return \miBadger\Query\Query the given query after adding the given where conditions.
620
+     */
621
+    private function getSearchQueryWhere($query, $where)
622
+    {
623
+        foreach ($where as $key => $value) {
624
+            $query->where($value[0], $value[1], $value[2]);
625
+        }
626
+
627
+        return $query;
628
+    }
629
+
630
+    /**
631
+     * Returns the given query after adding the given order by conditions.
632
+     *
633
+     * @param \miBadger\Query\Query $query
634
+     * @param array $orderBy
635
+     * @return \miBadger\Query\Query the given query after adding the given order by conditions.
636
+     */
637
+    private function getSearchQueryOrderBy($query, $orderBy)
638
+    {
639
+        foreach ($orderBy as $key => $value) {
640
+            $query->orderBy($key, $value);
641
+        }
642
+
643
+        return $query;
644
+    }
645
+
646
+    /**
647
+     * Returns the given query after adding the given limit and offset conditions.
648
+     *
649
+     * @param \miBadger\Query\Query $query
650
+     * @param int $limit
651
+     * @param int $offset
652
+     * @return \miBadger\Query\Query the given query after adding the given limit and offset conditions.
653
+     */
654
+    private function getSearchQueryLimit($query, $limit, $offset)
655
+    {
656
+        if ($limit > -1) {
657
+            $query->limit($limit);
658
+            $query->offset($offset);
659
+        }
660
+
661
+        return $query;
662
+    }
663
+
664
+    /**
665
+     * Returns the PDO.
666
+     *
667
+     * @return \PDO the PDO.
668
+     */
669
+    public function getPdo()
670
+    {
671
+        return $this->pdo;
672
+    }
673
+
674
+    /**
675
+     * Set the PDO.
676
+     *
677
+     * @param \PDO $pdo
678
+     * @return $this
679
+     */
680
+    protected function setPdo($pdo)
681
+    {
682
+        $this->pdo = $pdo;
683
+
684
+        return $this;
685
+    }
686
+
687
+    /**
688
+     * Returns the ID.
689
+     *
690
+     * @return null|int The ID.
691
+     */
692
+    public function getId()
693
+    {
694
+        return $this->id;
695
+    }
696
+
697
+    /**
698
+     * Set the ID.
699
+     *
700
+     * @param int $id
701
+     * @return $this
702
+     */
703
+    protected function setId($id)
704
+    {
705
+        $this->id = $id;
706
+
707
+        return $this;
708
+    }
709
+
710
+    /**
711
+     * Returns the active record table.
712
+     *
713
+     * @return string the active record table.
714
+     */
715
+    abstract protected function getActiveRecordTable();
716
+
717
+    /**
718
+     * Returns the active record columns.
719
+     *
720
+     * @return array the active record columns.
721
+     */
722
+    abstract protected function getActiveRecordTableDefinition();
723 723
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -288,7 +288,7 @@  discard block
 block discarded – undo
288 288
 		}
289 289
 
290 290
 		if ($default !== NULL) {
291
-			$stmnt .= ' DEFAULT ' . $default . ' ';
291
+			$stmnt .= ' DEFAULT '.$default.' ';
292 292
 		}
293 293
 
294 294
 		if ($properties & ColumnProperty::AUTO_INCREMENT) {
@@ -350,7 +350,7 @@  discard block
 block discarded – undo
350 350
 		// Sort table (first column is id, the remaining are alphabetically sorted)
351 351
 		$columnStatements = $this->sortColumnStatements($columnStatements);
352 352
 
353
-		$sql = 'CREATE TABLE ' . $this->getActiveRecordTable() . ' ';
353
+		$sql = 'CREATE TABLE '.$this->getActiveRecordTable().' ';
354 354
 		$sql .= "(\n";
355 355
 		$sql .= join($columnStatements, ",\n");
356 356
 		$sql .= "\n);";
@@ -599,7 +599,7 @@  discard block
 block discarded – undo
599 599
 		// Ignore all trait modifiers for which a where clause was specified
600 600
 		$registeredSearchHooks = $this->registeredSearchHooks;
601 601
 		foreach ($where as $index => $clause) {
602
-			[$colName, , ] = $clause;
602
+			[$colName,,] = $clause;
603 603
 			unset($registeredSearchHooks[$colName]);
604 604
 		}
605 605
 
Please login to merge, or discard this patch.
src/Traits/Address.php 2 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -2,8 +2,6 @@
 block discarded – undo
2 2
 
3 3
 namespace miBadger\ActiveRecord\Traits;
4 4
 
5
-use miBadger\ActiveRecord\ColumnProperty;
6
-
7 5
 const TRAIT_ADDRESS_FIELD_ADDRESS = "address_address";
8 6
 const TRAIT_ADDRESS_FIELD_ZIPCODE = "address_zipcode";
9 7
 const TRAIT_ADDRESS_FIELD_CITY = "address_city";
Please login to merge, or discard this patch.
Indentation   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -11,91 +11,91 @@
 block discarded – undo
11 11
 
12 12
 trait Address
13 13
 {
14
-	protected $address;
15
-
16
-	protected $zipcode;
17
-
18
-	protected $city;
19
-
20
-	protected $country;
21
-
22
-	protected function initAddress() 
23
-	{
24
-		$this->extendTableDefinition(TRAIT_ADDRESS_FIELD_ADDRESS, [
25
-			'value' => &$this->address,
26
-			'validate' => null,
27
-			'type' => 'VARCHAR',
28
-			'length' => 1024,
29
-			'properties' => null
30
-		]);
31
-
32
-		$this->extendTableDefinition(TRAIT_ADDRESS_FIELD_ZIPCODE, [
33
-			'value' => &$this->zipcode,
34
-			'validate' => null,
35
-			'type' => 'VARCHAR',
36
-			'length' => 1024,
37
-			'properties' => null
38
-		]);
39
-
40
-		$this->extendTableDefinition(TRAIT_ADDRESS_FIELD_CITY, [
41
-			'value' => &$this->city,
42
-			'validate' => null,
43
-			'type' => 'VARCHAR',
44
-			'length' => 1024,
45
-			'properties' => null
46
-		]);
47
-
48
-		$this->extendTableDefinition(TRAIT_ADDRESS_FIELD_COUNTRY, [
49
-			'value' => &$this->country,
50
-			'validate' => null,
51
-			'type' => 'VARCHAR',
52
-			'length' => 1024,
53
-			'properties' => null
54
-		]);
55
-
56
-		$this->address = null;
57
-		$this->zipcode = null;
58
-		$this->city = null;
59
-		$this->country = null;
60
-	}
61
-
62
-	public function getAddress()
63
-	{
64
-		return $this->address;
65
-	}
14
+    protected $address;
15
+
16
+    protected $zipcode;
17
+
18
+    protected $city;
19
+
20
+    protected $country;
21
+
22
+    protected function initAddress() 
23
+    {
24
+        $this->extendTableDefinition(TRAIT_ADDRESS_FIELD_ADDRESS, [
25
+            'value' => &$this->address,
26
+            'validate' => null,
27
+            'type' => 'VARCHAR',
28
+            'length' => 1024,
29
+            'properties' => null
30
+        ]);
31
+
32
+        $this->extendTableDefinition(TRAIT_ADDRESS_FIELD_ZIPCODE, [
33
+            'value' => &$this->zipcode,
34
+            'validate' => null,
35
+            'type' => 'VARCHAR',
36
+            'length' => 1024,
37
+            'properties' => null
38
+        ]);
39
+
40
+        $this->extendTableDefinition(TRAIT_ADDRESS_FIELD_CITY, [
41
+            'value' => &$this->city,
42
+            'validate' => null,
43
+            'type' => 'VARCHAR',
44
+            'length' => 1024,
45
+            'properties' => null
46
+        ]);
47
+
48
+        $this->extendTableDefinition(TRAIT_ADDRESS_FIELD_COUNTRY, [
49
+            'value' => &$this->country,
50
+            'validate' => null,
51
+            'type' => 'VARCHAR',
52
+            'length' => 1024,
53
+            'properties' => null
54
+        ]);
55
+
56
+        $this->address = null;
57
+        $this->zipcode = null;
58
+        $this->city = null;
59
+        $this->country = null;
60
+    }
61
+
62
+    public function getAddress()
63
+    {
64
+        return $this->address;
65
+    }
66 66
 	
67
-	public function setAddress($address)
68
-	{
69
-		$this->address = $address;
70
-	}
71
-
72
-	public function getZipcode()
73
-	{
74
-		return $this->zipcode;
75
-	}
67
+    public function setAddress($address)
68
+    {
69
+        $this->address = $address;
70
+    }
71
+
72
+    public function getZipcode()
73
+    {
74
+        return $this->zipcode;
75
+    }
76 76
 	
77
-	public function setZipcode($zipcode)
78
-	{
79
-		$this->zipcode = $zipcode;
80
-	}
81
-
82
-	public function getCity()
83
-	{
84
-		return $this->city;
85
-	}
77
+    public function setZipcode($zipcode)
78
+    {
79
+        $this->zipcode = $zipcode;
80
+    }
81
+
82
+    public function getCity()
83
+    {
84
+        return $this->city;
85
+    }
86 86
 	
87
-	public function setCity($city)
88
-	{
89
-		$this->city = $city;
90
-	}
91
-
92
-	public function getCountry()
93
-	{
94
-		return $this->country;
95
-	}
87
+    public function setCity($city)
88
+    {
89
+        $this->city = $city;
90
+    }
91
+
92
+    public function getCountry()
93
+    {
94
+        return $this->country;
95
+    }
96 96
 	
97
-	public function setCountry($country)
98
-	{
99
-		$this->country = $country;
100
-	}
97
+    public function setCountry($country)
98
+    {
99
+        $this->country = $country;
100
+    }
101 101
 }
102 102
\ No newline at end of file
Please login to merge, or discard this patch.
src/Traits/Datefields.php 2 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -2,7 +2,6 @@
 block discarded – undo
2 2
 
3 3
 namespace miBadger\ActiveRecord\Traits;
4 4
 
5
-use miBadger\Query\Query;
6 5
 use miBadger\ActiveRecord\ColumnProperty;
7 6
 
8 7
 const TRAIT_DATEFIELDS_LAST_MODIFIED = "last_modified";
Please login to merge, or discard this patch.
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -10,59 +10,59 @@
 block discarded – undo
10 10
 
11 11
 trait Datefields
12 12
 {
13
-	/** @var string The timestamp representing the moment this record was created */
14
-	protected $created;
13
+    /** @var string The timestamp representing the moment this record was created */
14
+    protected $created;
15 15
 
16
-	/** @var string The timestamp representing the moment this record was last updated */
17
-	protected $lastModified;
16
+    /** @var string The timestamp representing the moment this record was last updated */
17
+    protected $lastModified;
18 18
 
19
-	protected function initDatefields()
20
-	{
21
-		$this->extendTableDefinition(TRAIT_DATEFIELDS_CREATED, [
22
-			'value' => &$this->created,
23
-			'validate' => null,
24
-			'type' => 'DATETIME',
25
-			'default' => 'CURRENT_TIMESTAMP',
26
-			'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE
27
-		]);
19
+    protected function initDatefields()
20
+    {
21
+        $this->extendTableDefinition(TRAIT_DATEFIELDS_CREATED, [
22
+            'value' => &$this->created,
23
+            'validate' => null,
24
+            'type' => 'DATETIME',
25
+            'default' => 'CURRENT_TIMESTAMP',
26
+            'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE
27
+        ]);
28 28
 
29
-		$this->extendTableDefinition(TRAIT_DATEFIELDS_LAST_MODIFIED, [
30
-			'value' => &$this->lastModified,
31
-			'validate' => null,
32
-			'type' => 'DATETIME',
33
-			'default' => 'CURRENT_TIMESTAMP',
34
-			// 'on_update' => 'CURRENT_TIMESTAMP',		// @TODO(Discuss): Should we support this? (would not sync with object)
35
-			'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE
36
-		]);
29
+        $this->extendTableDefinition(TRAIT_DATEFIELDS_LAST_MODIFIED, [
30
+            'value' => &$this->lastModified,
31
+            'validate' => null,
32
+            'type' => 'DATETIME',
33
+            'default' => 'CURRENT_TIMESTAMP',
34
+            // 'on_update' => 'CURRENT_TIMESTAMP',		// @TODO(Discuss): Should we support this? (would not sync with object)
35
+            'properties' => ColumnProperty::NOT_NULL | ColumnProperty::IMMUTABLE
36
+        ]);
37 37
 		
38
-		$this->registerUpdateHook(TRAIT_DATEFIELDS_LAST_MODIFIED, 'DatefieldsUpdateHook');
39
-		$this->registerCreateHook(TRAIT_DATEFIELDS_LAST_MODIFIED, 'DatefieldsCreateHook');
38
+        $this->registerUpdateHook(TRAIT_DATEFIELDS_LAST_MODIFIED, 'DatefieldsUpdateHook');
39
+        $this->registerCreateHook(TRAIT_DATEFIELDS_LAST_MODIFIED, 'DatefieldsCreateHook');
40 40
 
41
-		$this->created = null;
42
-		$this->lastModified = null;
43
-	}
41
+        $this->created = null;
42
+        $this->lastModified = null;
43
+    }
44 44
 
45
-	protected function DatefieldsCreateHook()
46
-	{
47
-		// Should this be split up to seperate hooks for "last_modified" and "created" for consistency?
48
-		$this->created = (new \DateTime('now'))->format('Y-m-d H:i:s');
49
-		$this->lastModified = (new \DateTime('now'))->format('Y-m-d H:i:s');
50
-	}
45
+    protected function DatefieldsCreateHook()
46
+    {
47
+        // Should this be split up to seperate hooks for "last_modified" and "created" for consistency?
48
+        $this->created = (new \DateTime('now'))->format('Y-m-d H:i:s');
49
+        $this->lastModified = (new \DateTime('now'))->format('Y-m-d H:i:s');
50
+    }
51 51
 
52
-	protected function DatefieldsUpdateHook()
53
-	{
54
-		$this->lastModified = (new \DateTime('now'))->format('Y-m-d H:i:s');
55
-	}
52
+    protected function DatefieldsUpdateHook()
53
+    {
54
+        $this->lastModified = (new \DateTime('now'))->format('Y-m-d H:i:s');
55
+    }
56 56
 
57
-	public function getLastModifiedDate()
58
-	{
59
-		return new \DateTime($this->lastModified);
60
-	}
57
+    public function getLastModifiedDate()
58
+    {
59
+        return new \DateTime($this->lastModified);
60
+    }
61 61
 
62
-	public function getCreationDate()
63
-	{
64
-		return new \DateTime($this->created);
65
-	}
62
+    public function getCreationDate()
63
+    {
64
+        return new \DateTime($this->created);
65
+    }
66 66
 }
67 67
 
68
-	
69 68
\ No newline at end of file
69
+    
70 70
\ No newline at end of file
Please login to merge, or discard this patch.
src/Traits/ManyToManyRelation.php 2 patches
Unused Use Statements   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -2,9 +2,8 @@
 block discarded – undo
2 2
 
3 3
 namespace miBadger\ActiveRecord\Traits;
4 4
 
5
-use miBadger\Query\Query;
6
-use miBadger\ActiveRecord\ColumnProperty;
7 5
 use miBadger\ActiveRecord\AbstractActiveRecord;
6
+use miBadger\ActiveRecord\ColumnProperty;
8 7
 
9 8
 Trait ManyToManyRelation
10 9
 {
Please login to merge, or discard this patch.
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -8,65 +8,65 @@
 block discarded – undo
8 8
 
9 9
 Trait ManyToManyRelation
10 10
 {
11
-	// These variables are relevant for internal bookkeeping (constraint generation etc)
12
-	private $_leftColumnName;
11
+    // These variables are relevant for internal bookkeeping (constraint generation etc)
12
+    private $_leftColumnName;
13 13
 
14
-	private $_rightColumnName;
14
+    private $_rightColumnName;
15 15
 
16
-	private $_leftEntityTable;
16
+    private $_leftEntityTable;
17 17
 
18
-	private $_rightEntityTable;
18
+    private $_rightEntityTable;
19 19
 
20
-	/**
21
-	 * Initializes the the ManyToManyRelation trait on the included object
22
-	 * 
23
-	 * @param AbstractActiveRecord $leftEntity The left entity of the relation
24
-	 * @param &variable $leftVariable The variable where the id for the left entity will be stored
25
-	 * @param AbstractActiveRecord $rightEntity The left entity of the relation
26
-	 * @param &variable $leftVariable The variable where the id for the right entity will be stored
27
-	 */
28
-	protected function initManyToManyRelation(AbstractActiveRecord $leftEntity, &$leftVariable, AbstractActiveRecord $rightEntity, &$rightVariable)
29
-	{
30
-		$this->_leftEntityTable = $leftEntity->getActiveRecordTable();
31
-		$this->_rightEntityTable = $rightEntity->getActiveRecordTable();
20
+    /**
21
+     * Initializes the the ManyToManyRelation trait on the included object
22
+     * 
23
+     * @param AbstractActiveRecord $leftEntity The left entity of the relation
24
+     * @param &variable $leftVariable The variable where the id for the left entity will be stored
25
+     * @param AbstractActiveRecord $rightEntity The left entity of the relation
26
+     * @param &variable $leftVariable The variable where the id for the right entity will be stored
27
+     */
28
+    protected function initManyToManyRelation(AbstractActiveRecord $leftEntity, &$leftVariable, AbstractActiveRecord $rightEntity, &$rightVariable)
29
+    {
30
+        $this->_leftEntityTable = $leftEntity->getActiveRecordTable();
31
+        $this->_rightEntityTable = $rightEntity->getActiveRecordTable();
32 32
 
33
-		if (get_class($leftEntity) === get_class($rightEntity)) {
34
-			$this->_leftColumnName = sprintf("id_%s_left", $leftEntity->getActiveRecordTable());
35
-			$this->_rightColumnName = sprintf("id_%s_right", $rightEntity->getActiveRecordTable());
36
-		} else {
37
-			$this->_leftColumnName = sprintf("id_%s", $leftEntity->getActiveRecordTable());
38
-			$this->_rightColumnName = sprintf("id_%s", $rightEntity->getActiveRecordTable());
39
-		}
33
+        if (get_class($leftEntity) === get_class($rightEntity)) {
34
+            $this->_leftColumnName = sprintf("id_%s_left", $leftEntity->getActiveRecordTable());
35
+            $this->_rightColumnName = sprintf("id_%s_right", $rightEntity->getActiveRecordTable());
36
+        } else {
37
+            $this->_leftColumnName = sprintf("id_%s", $leftEntity->getActiveRecordTable());
38
+            $this->_rightColumnName = sprintf("id_%s", $rightEntity->getActiveRecordTable());
39
+        }
40 40
 
41
-		$this->extendTableDefinition($this->_leftColumnName, [
42
-			'value' => &$leftVariable,
43
-			'validate' => null,
44
-			'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
45
-			'properties' => ColumnProperty::NOT_NULL
46
-		]);
41
+        $this->extendTableDefinition($this->_leftColumnName, [
42
+            'value' => &$leftVariable,
43
+            'validate' => null,
44
+            'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
45
+            'properties' => ColumnProperty::NOT_NULL
46
+        ]);
47 47
 
48
-		$this->extendTableDefinition($this->_rightColumnName, [
49
-			'value' => &$rightVariable,
50
-			'validate' => null,
51
-			'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
52
-			'properties' => ColumnProperty::NOT_NULL
53
-		]);
54
-	}
48
+        $this->extendTableDefinition($this->_rightColumnName, [
49
+            'value' => &$rightVariable,
50
+            'validate' => null,
51
+            'type' => AbstractActiveRecord::COLUMN_TYPE_ID,
52
+            'properties' => ColumnProperty::NOT_NULL
53
+        ]);
54
+    }
55 55
 
56
-	/**
57
-	 * Build the constraints for the many-to-many relation table
58
-	 */
59
-	public function createTableConstraints()
60
-	{
61
-		$childTable = $this->getActiveRecordTable();
56
+    /**
57
+     * Build the constraints for the many-to-many relation table
58
+     */
59
+    public function createTableConstraints()
60
+    {
61
+        $childTable = $this->getActiveRecordTable();
62 62
 
63
-		$leftParentTable = $this->_leftEntityTable;
64
-		$rightParentTable = $this->_rightEntityTable;
63
+        $leftParentTable = $this->_leftEntityTable;
64
+        $rightParentTable = $this->_rightEntityTable;
65 65
 
66
-		$leftConstraint = $this->buildConstraint($leftParentTable, 'id', $childTable, $this->_leftColumnName);
67
-		$rightConstraint = $this->buildConstraint($rightParentTable, 'id', $childTable, $this->_rightColumnName);
66
+        $leftConstraint = $this->buildConstraint($leftParentTable, 'id', $childTable, $this->_leftColumnName);
67
+        $rightConstraint = $this->buildConstraint($rightParentTable, 'id', $childTable, $this->_rightColumnName);
68 68
 
69
-		$this->pdo->query($leftConstraint);
70
-		$this->pdo->query($rightConstraint);
71
-	}
69
+        $this->pdo->query($leftConstraint);
70
+        $this->pdo->query($rightConstraint);
71
+    }
72 72
 }
Please login to merge, or discard this patch.
src/Traits/SoftDelete.php 2 patches
Unused Use Statements   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,8 +2,8 @@
 block discarded – undo
2 2
 
3 3
 namespace miBadger\ActiveRecord\Traits;
4 4
 
5
-use miBadger\Query\Query;
6 5
 use miBadger\ActiveRecord\ColumnProperty;
6
+use miBadger\Query\Query;
7 7
 
8 8
 const TRAIT_SOFT_DELETE_FIELD_KEY = "soft_delete";
9 9
 
Please login to merge, or discard this patch.
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -9,48 +9,48 @@
 block discarded – undo
9 9
 
10 10
 trait SoftDelete
11 11
 {
12
-	protected $softDelete;
13
-
14
-	protected function initSoftDelete()
15
-	{
16
-		$this->softDelete = false;
17
-
18
-		$this->extendTableDefinition(TRAIT_SOFT_DELETE_FIELD_KEY, [
19
-			'value' => &$this->softDelete,
20
-			'validate' => null,
21
-			'default' => 0,
22
-			'type' => 'INT',
23
-			'length' => 1,
24
-			'properties' => ColumnProperty::NOT_NULL
25
-		]);
26
-
27
-		$this->registerSearchHook(TRAIT_SOFT_DELETE_FIELD_KEY, 'softDeleteSearchHook');
28
-	}
29
-
30
-	protected function softDeleteSearchHook(Query $query)
31
-	{
32
-		$query->where(TRAIT_SOFT_DELETE_FIELD_KEY, '=', 0);
33
-	}
34
-
35
-	public function getSoftDeleteFieldName()
36
-	{
37
-		return TRAIT_SOFT_DELETE_FIELD_KEY;
38
-	}
12
+    protected $softDelete;
13
+
14
+    protected function initSoftDelete()
15
+    {
16
+        $this->softDelete = false;
17
+
18
+        $this->extendTableDefinition(TRAIT_SOFT_DELETE_FIELD_KEY, [
19
+            'value' => &$this->softDelete,
20
+            'validate' => null,
21
+            'default' => 0,
22
+            'type' => 'INT',
23
+            'length' => 1,
24
+            'properties' => ColumnProperty::NOT_NULL
25
+        ]);
26
+
27
+        $this->registerSearchHook(TRAIT_SOFT_DELETE_FIELD_KEY, 'softDeleteSearchHook');
28
+    }
29
+
30
+    protected function softDeleteSearchHook(Query $query)
31
+    {
32
+        $query->where(TRAIT_SOFT_DELETE_FIELD_KEY, '=', 0);
33
+    }
34
+
35
+    public function getSoftDeleteFieldName()
36
+    {
37
+        return TRAIT_SOFT_DELETE_FIELD_KEY;
38
+    }
39 39
 	
40
-	public function softDelete()
41
-	{
42
-		$this->softDelete = true;
43
-		return $this;
44
-	}
45
-
46
-	public function softRestore()
47
-	{
48
-		$this->softDelete = false;
49
-		return $this;
50
-	}
51
-
52
-	public function getDeletionStatus() 
53
-	{
54
-		return $this->softDelete;
55
-	}
40
+    public function softDelete()
41
+    {
42
+        $this->softDelete = true;
43
+        return $this;
44
+    }
45
+
46
+    public function softRestore()
47
+    {
48
+        $this->softDelete = false;
49
+        return $this;
50
+    }
51
+
52
+    public function getDeletionStatus() 
53
+    {
54
+        return $this->softDelete;
55
+    }
56 56
 }
57 57
\ No newline at end of file
Please login to merge, or discard this patch.
src/Traits/Password.php 1 patch
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -12,104 +12,104 @@
 block discarded – undo
12 12
 
13 13
 trait Password
14 14
 {
15
-	/** @var string The password hash. */
16
-	protected $password;
17
-
18
-	/** @var string|null The password reset token. */
19
-	protected $passwordResetToken;
20
-
21
-	protected function initPassword()
22
-	{
23
-		$this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD, [
24
-			'value' => &$this->password,
25
-			'validate' => null,
26
-			'type' => 'VARCHAR',
27
-			'length' => 1024,
28
-			'properties' => ColumnProperty::NOT_NULL
29
-		]);
30
-
31
-		$this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD_RESET_TOKEN, [
32
-			'value' => &$this->passwordResetToken,
33
-			'validate' => null,
34
-			'default' => 0,
35
-			'type' => 'VARCHAR',
36
-			'length' => 1024
37
-		]);
38
-	}
39
-
40
-	/**
41
-	 * Returns true if the credentials are correct.
42
-	 *
43
-	 * @param string $password
44
-	 * @return boolean true if the credentials are correct
45
-	 */
46
-	public function isPassword($password)
47
-	{
48
-		if (!password_verify($password, $this->password)) {
49
-			return false;
50
-		}
51
-
52
-		if (password_needs_rehash($this->password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH])) {
53
-			$this->setPassword($password)->sync();
54
-		}
55
-
56
-		return true;
57
-	}
58
-
59
-	/**
60
-	 * Set the password.
61
-	 *
62
-	 * @param string $password
63
-	 * @return $this
64
-	 * @throws \Exception
65
-	 */
66
-	public function setPassword($password)
67
-	{
68
-		if (strlen($password) < TRAIT_PASSWORD_MIN_LENGTH) {
69
-			throw new \Exception(sprintf('\'Password\' must be atleast %s characters long. %s characters provied.', self::PASSWORD_MIN_LENGTH, strlen($password)));
70
-		}
71
-
72
-		$passwordHash = \password_hash($password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH]);
73
-
74
-		if ($passwordHash === false) {
75
-			throw new \Exception('\'Password\' hash failed.');
76
-		}
77
-
78
-		$this->password = $passwordHash;
79
-
80
-		return $this;
81
-	}
82
-
83
-	/**
84
-	 * @return string The Hash of the password
85
-	 */
86
-	public function getPasswordHash()
87
-	{
88
-		return $this->password;
89
-	}
90
-
91
-	/**
92
-	 * Returns the currently set password token for the entity, or null if not set
93
-	 * @return string|null The password reset token
94
-	 */
95
-	public function getPasswordResetToken()
96
-	{
97
-		return $this->passwordResetToken;
98
-	}
99
-
100
-	/**
101
-	 * Generates a new password reset token for the user
102
-	 */
103
-	public function generatePasswordResetToken()
104
-	{
105
-		$this->passwordResetToken = md5(uniqid(mt_rand(), true));
106
-	}
107
-
108
-	/**
109
-	 * Clears the current password reset token
110
-	 */
111
-	public function clearPasswordResetToken()
112
-	{
113
-		$this->passwordResetToken = null;
114
-	}
15
+    /** @var string The password hash. */
16
+    protected $password;
17
+
18
+    /** @var string|null The password reset token. */
19
+    protected $passwordResetToken;
20
+
21
+    protected function initPassword()
22
+    {
23
+        $this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD, [
24
+            'value' => &$this->password,
25
+            'validate' => null,
26
+            'type' => 'VARCHAR',
27
+            'length' => 1024,
28
+            'properties' => ColumnProperty::NOT_NULL
29
+        ]);
30
+
31
+        $this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD_RESET_TOKEN, [
32
+            'value' => &$this->passwordResetToken,
33
+            'validate' => null,
34
+            'default' => 0,
35
+            'type' => 'VARCHAR',
36
+            'length' => 1024
37
+        ]);
38
+    }
39
+
40
+    /**
41
+     * Returns true if the credentials are correct.
42
+     *
43
+     * @param string $password
44
+     * @return boolean true if the credentials are correct
45
+     */
46
+    public function isPassword($password)
47
+    {
48
+        if (!password_verify($password, $this->password)) {
49
+            return false;
50
+        }
51
+
52
+        if (password_needs_rehash($this->password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH])) {
53
+            $this->setPassword($password)->sync();
54
+        }
55
+
56
+        return true;
57
+    }
58
+
59
+    /**
60
+     * Set the password.
61
+     *
62
+     * @param string $password
63
+     * @return $this
64
+     * @throws \Exception
65
+     */
66
+    public function setPassword($password)
67
+    {
68
+        if (strlen($password) < TRAIT_PASSWORD_MIN_LENGTH) {
69
+            throw new \Exception(sprintf('\'Password\' must be atleast %s characters long. %s characters provied.', self::PASSWORD_MIN_LENGTH, strlen($password)));
70
+        }
71
+
72
+        $passwordHash = \password_hash($password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH]);
73
+
74
+        if ($passwordHash === false) {
75
+            throw new \Exception('\'Password\' hash failed.');
76
+        }
77
+
78
+        $this->password = $passwordHash;
79
+
80
+        return $this;
81
+    }
82
+
83
+    /**
84
+     * @return string The Hash of the password
85
+     */
86
+    public function getPasswordHash()
87
+    {
88
+        return $this->password;
89
+    }
90
+
91
+    /**
92
+     * Returns the currently set password token for the entity, or null if not set
93
+     * @return string|null The password reset token
94
+     */
95
+    public function getPasswordResetToken()
96
+    {
97
+        return $this->passwordResetToken;
98
+    }
99
+
100
+    /**
101
+     * Generates a new password reset token for the user
102
+     */
103
+    public function generatePasswordResetToken()
104
+    {
105
+        $this->passwordResetToken = md5(uniqid(mt_rand(), true));
106
+    }
107
+
108
+    /**
109
+     * Clears the current password reset token
110
+     */
111
+    public function clearPasswordResetToken()
112
+    {
113
+        $this->passwordResetToken = null;
114
+    }
115 115
 }
116 116
\ No newline at end of file
Please login to merge, or discard this patch.
src/ColumnProperty.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -5,10 +5,10 @@
 block discarded – undo
5 5
 
6 6
 class ColumnProperty
7 7
 {
8
-	const NONE = 0;
9
-	const UNIQUE = 1;
10
-	const NOT_NULL = 2;
11
-	const IMMUTABLE = 4;
12
-	const AUTO_INCREMENT = 8;
13
-	const PRIMARY_KEY = 16;
8
+    const NONE = 0;
9
+    const UNIQUE = 1;
10
+    const NOT_NULL = 2;
11
+    const IMMUTABLE = 4;
12
+    const AUTO_INCREMENT = 8;
13
+    const PRIMARY_KEY = 16;
14 14
 }
15 15
\ No newline at end of file
Please login to merge, or discard this patch.
test-bootstrap.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -9,7 +9,7 @@  discard block
 block discarded – undo
9 9
 // Cleanup SQL
10 10
 $user_delete = "DROP USER IF EXISTS $dbuser@'localhost'; ";
11 11
 $database_delete = "DROP DATABASE IF EXISTS $dbname; ";
12
-$sql_cleanup = $user_delete . $database_delete;
12
+$sql_cleanup = $user_delete.$database_delete;
13 13
 
14 14
 // Setup SQL
15 15
 $db_create = "CREATE DATABASE $dbname; ";
@@ -17,5 +17,5 @@  discard block
 block discarded – undo
17 17
 $user_alter = "ALTER USER 'phpunit'@'localhost' IDENTIFIED with mysql_native_password BY 'phpunit'; ";
18 18
 $user_grant = "GRANT ALL PRIVILEGES ON *.* TO '$dbuser'@'localhost';";
19 19
 
20
-$sql_setup = $sql_cleanup . $db_create . $user_create . $user_alter . $user_grant;
20
+$sql_setup = $sql_cleanup.$db_create.$user_create.$user_alter.$user_grant;
21 21
 exec("echo \"$sql_setup\" | mysql -u root -p");
Please login to merge, or discard this patch.