1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @package Laztopaz\potato-ORM |
5
|
|
|
* @author Temitope Olotin <[email protected]> |
6
|
|
|
* @license <https://opensource.org/license/MIT> MIT |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Laztopaz\PotatoORM; |
10
|
|
|
|
11
|
|
|
use Laztopaz\PotatoORM\DatabaseHandler; |
12
|
|
|
use Laztopaz\PotatoORM\BaseModelInterface; |
13
|
|
|
use Laztopaz\PotatoORM\NoRecordDeletionException; |
14
|
|
|
use Laztopaz\PotatoORM\NoRecordFoundException; |
15
|
|
|
use Laztopaz\PotatoORM\NoRecordInsertionException; |
16
|
|
|
use Laztopaz\PotatoORM\NullArgumentPassedToFunction; |
17
|
|
|
use Laztopaz\PotatoORM\WrongArgumentException; |
18
|
|
|
use Laztopaz\PotatoORM\NoArgumentPassedToFunctionException; |
19
|
|
|
use Laztopaz\PotatoORM\EmptyArrayException; |
20
|
|
|
|
21
|
|
|
class BaseModel implements BaseModelInterface |
22
|
|
|
{ |
23
|
|
|
// Inject the inflector trait |
24
|
|
|
use Inflector; |
25
|
|
|
|
26
|
|
|
// Private variable that contains instance of database |
27
|
|
|
protected $databaseModel; |
28
|
|
|
|
29
|
|
|
// Class variable holding class name pluralized |
30
|
|
|
protected $tableName; |
31
|
|
|
|
32
|
|
|
// Properties will later contain key, value pairs from the magic setter, getter methods |
33
|
|
|
protected $properties = []; |
34
|
|
|
|
35
|
|
|
public function __construct() |
36
|
|
|
{ |
37
|
|
|
$this->tableName = $this->getClassName(); |
38
|
|
|
|
39
|
|
|
$this->databaseModel = new DatabaseHandler($this->tableName); |
40
|
|
|
|
41
|
|
|
$this->properties['id'] = 0; |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* The magic getter method |
46
|
|
|
* @params key |
47
|
|
|
* @return array key |
48
|
|
|
*/ |
49
|
|
|
public function __get($key) |
50
|
|
|
{ |
51
|
|
|
$this->properties[$key]; |
52
|
|
|
|
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* The magic setter method |
57
|
|
|
* @params property, key |
58
|
|
|
* @return array associative array properties |
59
|
|
|
*/ |
60
|
|
|
public function __set($property, $value) |
61
|
|
|
{ |
62
|
|
|
$this->properties[$property] = $value; |
63
|
|
|
|
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* This method gets all the record from a particular table |
68
|
|
|
* @params void |
69
|
|
|
* @return associative array |
70
|
|
|
* @throws NoRecordFoundException |
71
|
|
|
*/ |
72
|
|
|
public static function getAll() |
73
|
|
|
{ |
74
|
|
|
$allData = DatabaseHandler::read($id = false, self::getClassName()); |
75
|
|
|
|
76
|
|
|
if (count($allData) > 0) { |
77
|
|
|
return $allData; |
|
|
|
|
78
|
|
|
|
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
throw NoRecordFoundException::create("There is no record to display"); |
82
|
|
|
|
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* This method create or update record in a database table |
87
|
|
|
* @params void |
88
|
|
|
* @return bool true or false; |
89
|
|
|
* @throws EmptyArrayException |
90
|
|
|
* @throws NoRecordInsertionException |
91
|
|
|
* @throws NoRecordUpdateException |
92
|
|
|
*/ |
93
|
|
|
public function save() |
94
|
|
|
{ |
95
|
|
|
$boolCommit = false; |
|
|
|
|
96
|
|
|
|
97
|
|
|
if ($this->properties['id']) { |
98
|
|
|
$allData = DatabaseHandler::read($id = $this->properties['id'], self::getClassName()); |
99
|
|
|
|
100
|
|
|
if ($this->checkIfRecordIsEmpty($allData)) { |
101
|
|
|
$boolCommit = $this->databaseModel->update(['id' => $this->properties['id']], $this->tableName, $this->properties); |
102
|
|
|
|
103
|
|
|
if ($boolCommit) { |
104
|
|
|
return true; |
105
|
|
|
|
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
throw NoRecordUpdateException::create("Record not updated successfully"); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
throw EmptyArrayException::create("Value passed didn't match any record"); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$boolCommit = $this->databaseModel->create($this->properties, $this->tableName); |
115
|
|
|
|
116
|
|
|
if ($boolCommit) { |
117
|
|
|
return true; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
throw NoRecordInsertionException::create("Record not created successfully"); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* This method find a record by id |
125
|
|
|
* @params int id |
126
|
|
|
* @return Object |
127
|
|
|
* @throws NoArgumentPassedToFunctionException |
128
|
|
|
*/ |
129
|
|
|
public static function find($id) |
130
|
|
|
{ |
131
|
|
|
$num_args = (int) func_num_args(); // get number of arguments passed to this function |
132
|
|
|
if ($num_args == 0 || $num_args > 1) { |
133
|
|
|
throw NoArgumentPassedToFunctionException::create("Argument missing: only one argument is allowed"); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
if ($id == "") { |
137
|
|
|
throw NullArgumentPassedToFunction::create("This function expect a value"); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
$staticFindInstance = new static(); |
141
|
|
|
$staticFindInstance->id = $id == "" ? false : $id; |
|
|
|
|
142
|
|
|
|
143
|
|
|
return $staticFindInstance; |
144
|
|
|
|
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* This method delete a row from the table by the row id |
149
|
|
|
* @params int id |
150
|
|
|
* @return boolean true or false |
151
|
|
|
* @throws NoRecordDeletionException; |
152
|
|
|
*/ |
153
|
|
|
public static function destroy($id) |
154
|
|
|
{ |
155
|
|
|
$boolDeleted = false; |
|
|
|
|
156
|
|
|
|
157
|
|
|
$num_args = (int) func_num_args(); // get number of arguments passed to this function |
158
|
|
|
|
159
|
|
|
if ($num_args == 0 || $num_args > 1) { |
160
|
|
|
throw NoArgumentPassedToFunctionException::create("Argument missing: only one argument is allowed"); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
$boolDeleted = DatabaseHandler::delete($id, self::getClassName()); |
164
|
|
|
|
165
|
|
|
if ($boolDeleted) { |
166
|
|
|
return true; |
167
|
|
|
|
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
throw NoRecordDeletionException::create("Record deletion unsuccessful because id does not match any record"); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* This method return the current class name |
175
|
|
|
* $params void |
176
|
|
|
* @return classname |
177
|
|
|
*/ |
178
|
|
|
public static function getClassName() |
179
|
|
|
{ |
180
|
|
|
$tableName = preg_split('/(?=[A-Z])/', get_called_class()); |
181
|
|
|
|
182
|
|
|
$className = end($tableName); |
183
|
|
|
|
184
|
|
|
return self::pluralize(strtolower($className)); |
185
|
|
|
|
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* This method check if the argument passed to this function is an array |
190
|
|
|
* @param $arrayOfRecord |
191
|
|
|
* @return bool |
192
|
|
|
*/ |
193
|
|
|
public function checkIfRecordIsEmpty($arrayOfRecord) |
194
|
|
|
{ |
195
|
|
|
if (count($arrayOfRecord) > 0) { |
196
|
|
|
return true; |
197
|
|
|
|
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
return false; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
} |
204
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.