PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / admin / helpers / src / mvc / model.php

model.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/helpers/src/mvc/model.php

507 lines 13.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * VikBooking MVC base model declaration.
16 *
17 * @since 1.15.10 (J) - 1.5.10 (WP)
18 */
19 abstract class VBOMvcModel extends JObject
20 {
21 /**
22 * Cached used to store the supported columns of the requested database tables.
23 *
24 * @var string
25 */
26 protected static $fields = [];
27
28 /**
29 * The database table name.
30 *
31 * @var string
32 */
33 protected $tableName = null;
34
35 /**
36 * The database table primary key name.
37 *
38 * @var string
39 */
40 protected $tableKeyName = 'id';
41
42 /**
43 * Returns a new instance of the requested model.
44 *
45 * @param string $name The model name.
46 * @param array $options The model configuration.
47 *
48 * @return VBOMvcModel
49 */
50 public static function getInstance($name, array $options = [])
51 {
52 /**
53 * Trigger hook to allow third party plugins to extend the default models in VikBooking without
54 * altering a single line of code from the core of the plugin.
55 *
56 * It is either possible to swap the name or to return a new instance of VBOMvcModel.
57 *
58 * @param string &$name A reference to the requested model.
59 * @param array &$options A reference to the model configuration.
60 *
61 * @return mixed
62 */
63 $results = VBOFactory::getPlatform()->getDispatcher()->filter('onBeforeCreateModelVikBooking', [&$name, &$options]);
64
65 // filter the returned values to take only the first valid instance
66 $results = array_filter($results, function($data)
67 {
68 return $data instanceof VBOMvcModel;
69 });
70
71 if ($results)
72 {
73 // class returned by a plugin, directly use it
74 return reset($results);
75 }
76
77 // fallback to the default classes in VikBooking
78 $suffix = str_replace('_', ' ', $name);
79 $suffix = str_replace(' ', '', ucwords($suffix));
80
81 $modelClass = 'VBOModel' . $suffix;
82
83 if (!class_exists($modelClass))
84 {
85 throw new Exception(sprintf('Model [%s] not found', $name), 404);
86 }
87
88 return new $modelClass($options);
89 }
90
91 /**
92 * Returns the model name.
93 *
94 * @return string
95 */
96 public function getName()
97 {
98 if (preg_match("/^VBOModel([a-z0-9_]+)$/i", get_class($this), $match))
99 {
100 return strtolower($match[1]);
101 }
102
103 // unable to extract model name from class, use the file name
104 return basename(__FILE__, '.php');
105 }
106
107 /**
108 * Basic item loading implementation.
109 *
110 * @param mixed $pk An optional primary key value to load the row by, or an array of fields to match.
111 * If not set the instance property value is used.
112 *
113 * @return ?object The record object on success, null otherwise.
114 */
115 public function getItem($pk)
116 {
117 $db = JFactory::getDbo();
118
119 $query = $db->getQuery(true)
120 ->select('*')
121 ->from($db->qn($this->tableName));
122
123 if (is_array($pk))
124 {
125 foreach ($pk as $column => $value)
126 {
127 $query->where($db->qn($column) . ' = ' . $db->q($value));
128 }
129 }
130 else
131 {
132 $query->where($db->qn($this->tableKeyName) . ' = ' . (int) $pk);
133 }
134
135 $db->setQuery($query, 0, 1);
136
137 return $db->loadObject();
138 }
139
140 /**
141 * Items loading implementation.
142 *
143 * @param array $clauses List of associative columns to fetch
144 * (column => [operator, value] or column => value)
145 * @param int $start Query limit start.
146 * @param int $lim Query limit value.
147 * @param array $cols Optional list of columns to fetch.
148 * @param array $ordering Optional associative list of ordering columns.
149 *
150 * @return array List of record objects.
151 *
152 * @since 1.18.8 (J) - 1.8.8 (WP)
153 */
154 public function getItems(array $clauses = [], int $start = 0, int $lim = 0, array $cols = [], array $ordering = [])
155 {
156 $db = JFactory::getDbo();
157
158 $q = $db->getQuery(true);
159
160 if (!$cols)
161 {
162 $q->select('*');
163 }
164 else
165 {
166 $q->select(array_map([$db, 'qn'], $cols));
167 }
168
169 $q->from($db->qn($this->tableName));
170
171 foreach ($clauses as $column => $data)
172 {
173 if (!is_array($data))
174 {
175 // convert structure
176 $data = ['value' => $data];
177 }
178
179 if (is_null($data['value']))
180 {
181 $q->where($db->qn($column) . ' IS NULL');
182 }
183 else
184 {
185 $q->where($db->qn($column) . ' ' . ($data['operator'] ?? '=') . ' ' . $db->q($data['value']));
186 }
187 }
188
189 if ($ordering)
190 {
191 // sort by given columns
192 foreach ($ordering as $orderColumn => $orderSort)
193 {
194 if (!is_string($orderSort))
195 {
196 continue;
197 }
198
199 // set ordering column
200 $q->order($db->qn($orderColumn) . ' ' . (!strcasecmp($orderSort, 'ASC') ? 'ASC' : 'DESC'));
201 }
202 }
203 else
204 {
205 // default ordering column
206 $q->order($db->qn($this->tableKeyName) . ' ASC');
207 }
208
209 $db->setQuery($q, $start, $lim);
210
211 return $db->loadObjectList();
212 }
213
214 /**
215 * Method to save the form data.
216 *
217 * @param mixed $data The form data.
218 *
219 * @return mixed The primary key of the saved item, false otherwise.
220 */
221 public function save($data)
222 {
223 $data = (array) $data;
224
225 // let the children bind the data array before save
226 if (!$this->preflight($data))
227 {
228 return false;
229 }
230
231 // check if we have an empty record
232 $isNew = empty($data[$this->tableKeyName]);
233
234 // store the object within the database
235 $pk = $this->store((array) $data);
236
237 if (!$pk)
238 {
239 return false;
240 }
241
242 // let the children perform extra actions after saving
243 $this->postflight((array) $data, $isNew);
244
245 return $pk;
246 }
247
248 /**
249 * Method to delete one or more records.
250 *
251 * @param mixed $pks An array of record primary keys.
252 *
253 * @return bool True if successful, false if an error occurs.
254 */
255 public function delete($pks)
256 {
257 if (!$pks)
258 {
259 // nothing to delete
260 return false;
261 }
262
263 if (!is_array($pks))
264 {
265 // wrap in an array
266 $pks = [$pks];
267 }
268
269 $app = JFactory::getApplication();
270
271 $affected = true;
272
273 foreach ($pks as $pk)
274 {
275 // fetch item details
276 $item = $this->getItem($pk);
277
278 if (!$item)
279 {
280 continue;
281 }
282
283 /**
284 * Runs before deleting the given data.
285 * It is possible to validate here whether the item should be deleted or not.
286 *
287 * @param object $data The record to delete.
288 * @param self $model The current model.
289 *
290 * @return bool False to abort the deleting process.
291 *
292 * @since 1.5.10
293 */
294 $results = $app->triggerEvent('onBeforeDeleteVikBooking' . ucfirst($this->getName()), [$item, $this]);
295
296 // check whether a plugin aborted the deleting process
297 if (in_array(false, $results, true))
298 {
299 continue;
300 }
301
302 // remove item
303 $result = $this->remove($item);
304
305 /**
306 * Runs after deleting the given data.
307 * It is possible to perform here some extra actions.
308 *
309 * @param object $data The deleted item.
310 * @param bool $success True in case of success, false otherwise.
311 * @param self $model The current model.
312 *
313 * @return void
314 *
315 * @since 1.5.10
316 */
317 $app->triggerEvent('onAfterDeleteVikBooking' . ucfirst($this->getName()), [$item, $result, $this]);
318
319 $affected = $affected || $result;
320 }
321
322 return $affected;
323 }
324
325 /**
326 * Runs before saving the given data.
327 * It is possible to inject here additional properties to save.
328 *
329 * @param array &$data A reference to the data to save.
330 *
331 * @return bool True on success, false otherwise.
332 */
333 protected function preflight(array &$data)
334 {
335 $app = JFactory::getApplication();
336
337 /**
338 * Runs before saving the given data.
339 * It is possible to inject here additional properties to save.
340 *
341 * @param array &$data A reference to the data to save.
342 * @param self $model The current model.
343 *
344 * @return bool False to abort the saving process.
345 *
346 * @since 1.5.10
347 */
348 $results = $app->triggerEvent('onBeforeSaveVikBooking' . ucfirst($this->getName()), [&$data, $this]);
349
350 // check whether a plugin aborted the saving process
351 if (in_array(false, $results, true))
352 {
353 return false;
354 }
355
356 return true;
357 }
358
359 /**
360 * Converts the array data into an object compatible with the database
361 * structure of the specified table.
362 *
363 * @param array $data The requested data.
364 *
365 * @return object The object ready to be saved.
366 */
367 protected function prepareSaveData(array $data)
368 {
369 $table = new stdClass;
370
371 // bind only the columns supported by the database table
372 foreach ($this->getTableColumns() as $field => $type)
373 {
374 if (isset($data[$field]))
375 {
376 // always encode in JSON format non-scalar values
377 if (!is_scalar($data[$field]))
378 {
379 $data[$field] = json_encode($data[$field]);
380 }
381
382 $table->{$field} = $data[$field];
383 }
384 }
385
386 return $table;
387 }
388
389 /**
390 * Saves the specified data into the database.
391 *
392 * @param array $data The requested data.
393 *
394 * @return mixed The primary key value of the saved record (true if missing).
395 * Returns false in case of failure.
396 */
397 final protected function store(array $data)
398 {
399 // construct the object that will be saved
400 $table = $this->prepareSaveData($data);
401
402 if (!$table)
403 {
404 return false;
405 }
406
407 $db = JFactory::getDbo();
408
409 if (!empty($table->{$this->tableKeyName}))
410 {
411 // update needed
412 $res = $db->updateObject($this->tableName, $table, $this->tableKeyName);
413 }
414 else
415 {
416 // insert needed
417 $res = $db->insertObject($this->tableName, $table, $this->tableKeyName);
418 }
419
420 if (!$res)
421 {
422 // something went wrong while saving the record
423 return false;
424 }
425
426 // check again whether the PK has been filled
427 if (empty($table->{$this->tableKeyName}))
428 {
429 // no PK, just return true
430 return true;
431 }
432
433 return $table->{$this->tableKeyName};
434 }
435
436 /**
437 * Runs after saving the given data.
438 * It is possible to perform here some extra actions.
439 *
440 * @param array $data The saved data.
441 * @param bool True in case of insert, false in case of update.
442 *
443 * @return void
444 */
445 protected function postflight(array $data, $isNew)
446 {
447 $app = JFactory::getApplication();
448
449 /**
450 * Runs after saving the given data.
451 * It is possible to perform here some extra actions.
452 *
453 * @param array $data The saved data.
454 * @param bool $isNew True in case of insert, false in case of update.
455 * @param self $model The current model.
456 *
457 * @return void
458 *
459 * @since 1.5.10
460 */
461 $app->triggerEvent('onAfterSaveVikBooking' . ucfirst($this->getName()), [$data, $isNew, $this]);
462 }
463
464 /**
465 * Removes the specified item from the database.
466 *
467 * @param object $item The record to delete.
468 *
469 * @return bool True if deleted, false otherwise.
470 */
471 protected function remove($item)
472 {
473 $db = JFactory::getDbo();
474
475 $query = $db->getQuery(true)
476 ->delete($db->qn($this->tableName))
477 ->where($db->qn($this->tableKeyName) . ' = ' . $db->q($item->{$this->tableKeyName}));
478
479 $db->setQuery($query);
480 $db->execute();
481
482 return (bool) $db->getAffectedRows();
483 }
484
485 /**
486 * Returns all the columns supported by the database table of this model.
487 *
488 * @return array
489 */
490 public function getTableColumns()
491 {
492 if (!isset(static::$fields[$this->tableName]))
493 {
494 try
495 {
496 static::$fields[$this->tableName] = JFactory::getDbo()->getTableColumns($this->tableName);
497 }
498 catch (Exception $e)
499 {
500 static::$fields[$this->tableName] = [];
501 }
502 }
503
504 return static::$fields[$this->tableName];
505 }
506 }
507