|
1
|
|
|
<?php |
|
2
|
|
|
namespace Suricate; |
|
3
|
|
|
|
|
4
|
|
|
class DBCollection extends Collection |
|
5
|
|
|
{ |
|
6
|
|
|
const TABLE_NAME = ''; // Name of SQL table containing items |
|
7
|
|
|
const ITEM_TYPE = ''; // Class of items in collection |
|
8
|
|
|
const DB_CONFIG = ''; // Database configuration identifier |
|
9
|
|
|
const PARENT_ID_NAME = 'parent_id'; // Name of the field referencing to parent_id |
|
10
|
|
|
const PARENT_OBJECT_TYPE = ''; // Parent object type |
|
11
|
|
|
|
|
12
|
|
|
|
|
13
|
|
|
protected $lazyLoad = false; |
|
14
|
|
|
protected $parentId; // Id of the parent |
|
15
|
|
|
protected $parentFilterName; // Name of field used for filtering |
|
16
|
|
|
protected $parentFilterType; // Value of filter |
|
17
|
|
|
|
|
18
|
|
|
|
|
19
|
|
|
|
|
20
|
|
|
protected $itemOffset = 0; |
|
21
|
|
|
|
|
22
|
|
|
public function setLazyLoad($lazyLoad) |
|
23
|
|
|
{ |
|
24
|
|
|
$this->lazyLoad = $lazyLoad; |
|
25
|
|
|
|
|
26
|
|
|
return $this; |
|
27
|
|
|
} |
|
28
|
|
|
|
|
29
|
|
|
|
|
30
|
|
|
public function purgeItems() |
|
31
|
|
|
{ |
|
32
|
|
|
$this->items = array(); |
|
33
|
|
|
$this->mapping = array(); |
|
34
|
|
|
$this->itemOffset = 0; |
|
35
|
|
|
} |
|
36
|
|
|
|
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* Load entire table into collection |
|
40
|
|
|
* @return Collection Loaded collection |
|
41
|
|
|
*/ |
|
42
|
|
|
public static function loadAll() |
|
43
|
|
|
{ |
|
44
|
|
|
$calledClass = get_called_class(); |
|
45
|
|
|
$collection = new $calledClass; |
|
46
|
|
|
|
|
47
|
|
|
$sqlParams = array(); |
|
48
|
|
|
|
|
49
|
|
|
$sql = "SELECT *"; |
|
50
|
|
|
$sql .= " FROM `" . $collection::TABLE_NAME . "`"; |
|
51
|
|
|
|
|
52
|
|
|
if ($collection->parentFilterType !== '' && $collection->parentFilterType != null) { |
|
53
|
|
|
$sql .= "WHERE " . $collection->parentFilterName . "=:type"; |
|
54
|
|
|
$sqlParams['type'] = $collection->parentFilterType; |
|
55
|
|
|
} |
|
56
|
|
|
$dbLink = Suricate::Database(); |
|
57
|
|
|
if (static::DB_CONFIG != '') { |
|
58
|
|
|
$dbLink->setConfig(static::DB_CONFIG); |
|
59
|
|
|
} |
|
60
|
|
|
$results = $dbLink->query($sql, $sqlParams)->fetchAll(); |
|
61
|
|
|
|
|
62
|
|
|
if ($results !== false) { |
|
63
|
|
|
foreach ($results as $currentResult) { |
|
64
|
|
|
$itemName = $collection::ITEM_TYPE; |
|
65
|
|
|
$collection->addItem($itemName::instanciate($currentResult)); |
|
66
|
|
|
} |
|
67
|
|
|
} |
|
68
|
|
|
|
|
69
|
|
|
return $collection; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* Static wrapper for loadFromSql |
|
74
|
|
|
* @param string $sql SQL Statement |
|
75
|
|
|
* @param array $sqlParams SQL Parameters |
|
76
|
|
|
* @return Suricate\Collection Loaded collection |
|
77
|
|
|
*/ |
|
78
|
|
|
public static function buildFromSql($sql, $sqlParams = array()) |
|
79
|
|
|
{ |
|
80
|
|
|
$calledClass = get_called_class(); |
|
81
|
|
|
$collection = new $calledClass; |
|
82
|
|
|
|
|
83
|
|
|
$collection->loadFromSql($sql, $sqlParams); |
|
84
|
|
|
|
|
85
|
|
|
return $collection; |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
View Code Duplication |
public function loadFromSql($sql, $sqlParams = array()) |
|
|
|
|
|
|
89
|
|
|
{ |
|
90
|
|
|
$dbLink = Suricate::Database(); |
|
91
|
|
|
if (static::DB_CONFIG != '') { |
|
92
|
|
|
$dbLink->setConfig(static::DB_CONFIG); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
$results = Suricate::Database()->query($sql, $sqlParams)->fetchAll(); |
|
96
|
|
|
|
|
97
|
|
|
if ($results !== false) { |
|
98
|
|
|
foreach ($results as $currentResult) { |
|
99
|
|
|
$itemName = $this::ITEM_TYPE; |
|
100
|
|
|
$this->addItem($itemName::instanciate($currentResult)); |
|
101
|
|
|
} |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
return $this; |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
View Code Duplication |
public function lazyLoadFromSql($sql, $sqlParams = array()) |
|
|
|
|
|
|
108
|
|
|
{ |
|
109
|
|
|
$dbLink = Suricate::Database(); |
|
110
|
|
|
if (static::DB_CONFIG != '') { |
|
111
|
|
|
$dbLink->setConfig(static::DB_CONFIG); |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
$results = $dbLink->query($sql, $sqlParams) |
|
115
|
|
|
->fetchAll(); |
|
116
|
|
|
|
|
117
|
|
|
if ($results !== false) { |
|
118
|
|
|
foreach ($results as $currentResult) { |
|
119
|
|
|
$this->addItemLink(current($currentResult)); |
|
|
|
|
|
|
120
|
|
|
} |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
return $this; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
/** |
|
127
|
|
|
* Load items linked to a parentId |
|
128
|
|
|
* @param mixed $parentId Parent id description |
|
129
|
|
|
* @param string $parentIdField Name of parent id referencing field |
|
130
|
|
|
* @param closure $validate Callback use to validate add to items collection |
|
131
|
|
|
*/ |
|
132
|
|
|
public static function loadForParentId($parentId, $parentIdField = null, $validate = null) |
|
133
|
|
|
{ |
|
134
|
|
|
$calledClass = get_called_class(); |
|
135
|
|
|
$collection = new $calledClass; |
|
136
|
|
|
|
|
137
|
|
|
if ($parentId != '') { |
|
138
|
|
|
$sqlParams = array(); |
|
139
|
|
|
$dbHandler = Suricate::Database(true); |
|
140
|
|
|
|
|
141
|
|
|
if (static::DB_CONFIG != '') { |
|
142
|
|
|
$dbHandler->setConfig(static::DB_CONFIG); |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
$sql = "SELECT *"; |
|
146
|
|
|
$sql .= " FROM `" . $collection::TABLE_NAME . "`"; |
|
147
|
|
|
$sql .= " WHERE"; |
|
148
|
|
|
if ($parentIdField !== null) { |
|
149
|
|
|
$sql .= " " . $parentIdField . "=:parent_id"; |
|
150
|
|
|
} else { |
|
151
|
|
|
$sql .= " " . $collection::PARENT_ID_NAME . "=:parent_id"; |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
if ($collection->parentFilterType !== null) { |
|
155
|
|
|
$sql .= " AND " . $collection->parentFilterName . "=:parent_type"; |
|
156
|
|
|
$sqlParams['parent_type'] = $collection->parentFilterType; |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
$sqlParams['parent_id'] = $parentId; |
|
160
|
|
|
$results = $dbHandler->query($sql, $sqlParams)->fetchAll(); |
|
161
|
|
|
|
|
162
|
|
|
if ($results !== false) { |
|
163
|
|
|
foreach ($results as $currentResult) { |
|
164
|
|
|
$itemName = $collection::ITEM_TYPE; |
|
165
|
|
|
$item = $itemName::instanciate($currentResult); |
|
166
|
|
|
if ($validate === null || $validate($item)) { |
|
167
|
|
|
$collection->addItem($item); |
|
168
|
|
|
} |
|
169
|
|
|
} |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
$collection->parentId = $parentId; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
return $collection; |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
public function setParentIdForAll($parentId) |
|
179
|
|
|
{ |
|
180
|
|
|
$this->parentId = $parentId; |
|
181
|
|
|
foreach ($this->items as $key => $currentItem) { |
|
182
|
|
|
$this->items[$key]->{static::PARENT_ID_NAME} = $parentId; |
|
183
|
|
|
} |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Load Parent Item, if item type is defined |
|
188
|
|
|
* @return item type Parent Object |
|
189
|
|
|
*/ |
|
190
|
|
|
public function loadParent() |
|
191
|
|
|
{ |
|
192
|
|
|
if (static::PARENT_OBJECT_TYPE != '' && $this->parentId != '') { |
|
193
|
|
|
$parentObjectType = static::PARENT_OBJECT_TYPE; |
|
194
|
|
|
$parent = new $parentObjectType(); |
|
195
|
|
|
if (method_exists($parent, 'load')) { |
|
196
|
|
|
$parent->load($this->parentId); |
|
197
|
|
|
|
|
198
|
|
|
return $parent; |
|
199
|
|
|
} else { |
|
200
|
|
|
throw new \BadMethodCallException("Parent object does not have a load(\$id) method"); |
|
201
|
|
|
} |
|
202
|
|
|
} else { |
|
203
|
|
|
throw new \BadMethodCallException("PARENT_OBJECT_TYPE is not defined"); |
|
204
|
|
|
} |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
public function craftItem($itemData) |
|
208
|
|
|
{ |
|
209
|
|
|
$itemName = static::ITEM_TYPE; |
|
210
|
|
|
|
|
211
|
|
|
foreach ($itemData as $data) { |
|
212
|
|
|
$newItem = new $itemName(); |
|
213
|
|
|
$newItem->{static::PARENT_ID_NAME} = $this->parentId; |
|
214
|
|
|
$hasData = false; |
|
215
|
|
|
foreach ($data as $field => $value) { |
|
216
|
|
|
$newItem->$field = $value; |
|
217
|
|
|
if ($value != '') { |
|
218
|
|
|
$hasData = true; |
|
219
|
|
|
} |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
// Only add item if there's data inside |
|
223
|
|
|
if ($hasData) { |
|
224
|
|
|
$this->addItem($newItem); |
|
225
|
|
|
} |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
public function save() |
|
230
|
|
|
{ |
|
231
|
|
|
// 1st step : delete all records for current parentId |
|
232
|
|
|
$sql = "DELETE FROM `" . static::TABLE_NAME . "`"; |
|
233
|
|
|
if (static::PARENT_ID_NAME != '') { |
|
234
|
|
|
$sql .= " WHERE"; |
|
235
|
|
|
$sql .= " " . static::PARENT_ID_NAME . "=:parent_id"; |
|
236
|
|
|
|
|
237
|
|
|
$sqlParams = array('parent_id' => $this->parentId); |
|
238
|
|
|
} else { |
|
239
|
|
|
$sqlParams = array(); |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
$dbLink = Suricate::Database(); |
|
243
|
|
|
if (static::DB_CONFIG != '') { |
|
244
|
|
|
$dbLink->setConfig(static::DB_CONFIG); |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
$dbLink->query($sql, $sqlParams); |
|
248
|
|
|
|
|
249
|
|
|
// 2nd step : save all current items |
|
250
|
|
|
foreach ($this->items as $currentItem) { |
|
251
|
|
|
$currentItem->save(true); // Force insert |
|
252
|
|
|
} |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
public function addItem(Interfaces\IDBObject $item) |
|
256
|
|
|
{ |
|
257
|
|
|
$key = $item::TABLE_INDEX; |
|
258
|
|
|
// Add item to items pool |
|
259
|
|
|
$this->items[$this->itemOffset] = $item; |
|
260
|
|
|
|
|
261
|
|
|
// add mapping between item->index and $position in items pool |
|
262
|
|
|
$this->mapping[$this->itemOffset] = $item->$key; |
|
263
|
|
|
|
|
264
|
|
|
$this->itemOffset++; |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
public function getItemsType() |
|
268
|
|
|
{ |
|
269
|
|
|
return static::ITEM_TYPE; |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
public function getParentIdName() |
|
273
|
|
|
{ |
|
274
|
|
|
return static::PARENT_ID_NAME; |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
public function getParentId() |
|
278
|
|
|
{ |
|
279
|
|
|
return $this->parentId; |
|
280
|
|
|
} |
|
281
|
|
|
} |
|
282
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.