PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.7
VikBooking Hotel Booking Engine & PMS v1.6.7
1.8.16 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 All 37 releases
vikbooking / libraries / adapter / database / table.php

table.php in VikBooking Hotel Booking Engine & PMS 1.6.7, at libraries/adapter/database/table.php

947 lines 22.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.database
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2023 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 * Generic table class for database objects.
16 *
17 * @since 10.1.19
18 */
19 class JTable extends JObject
20 {
21 /**
22 * Include paths for searching for Table classes.
23 *
24 * @var array
25 */
26 private static $_includePaths = array();
27
28 /**
29 * Table fields cache to prevent the static changed applied by PHP 8.1.
30 * @link https://bugs.php.net/bug.php?id=81686
31 *
32 * @var array
33 * @since 10.1.41
34 */
35 protected static $_tableFields = [];
36
37 /**
38 * Name of the database table to model.
39 *
40 * @var string
41 */
42 protected $_table = '';
43
44 /**
45 * Name of the primary key fields in the table.
46 *
47 * @var array
48 */
49 protected $_tableKeys = array();
50
51 /**
52 * Indicates that the primary keys autoincrement.
53 *
54 * @var boolean
55 */
56 protected $_autoincrement = true;
57
58 /**
59 * Array with alias for "special" columns such as ordering, hits etc etc
60 *
61 * @var array
62 * @since 10.1.30
63 */
64 protected $_columnAlias = array();
65
66 /**
67 * Static method to get an instance of a Table class if it
68 * can be found in the table include paths.
69 *
70 * @param string $type The type (name) of the Table class to get an instance of.
71 * @param string $prefix An optional prefix for the table class name.
72 * @param array $config An optional array of configuration values for the Table object.
73 *
74 * @return mixed A Table object if found, false otherwise.
75 *
76 * @see JTable::addIncludePath() to add include paths for searching for Table classes.
77 */
78 public static function getInstance($type, $prefix = 'JTable', $config = array())
79 {
80 // sanitize and prepare the table class name
81 $type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type);
82 $tableClass = $prefix . ucfirst($type);
83
84 // only try to load the class if it doesn't already exist
85 if (!class_exists($tableClass))
86 {
87 // search for the class file in the JTable include paths.
88 $paths = static::addIncludePath();
89 $pathIndex = 0;
90
91 // iterate until the class is loaded
92 while (!class_exists($tableClass) && $pathIndex < count($paths))
93 {
94 if ($tryThis = JPath::find($paths[$pathIndex++], strtolower($type) . '.php'))
95 {
96 // import the class file
97 include_once $tryThis;
98 }
99 }
100
101 if (!class_exists($tableClass))
102 {
103 throw new Exception(sprintf('Table [%s] not found', $tableClass), 404);
104 }
105 }
106
107 // instantiate a new table class and return it
108 return new $tableClass($type);
109 }
110
111 /**
112 * Adds a filesystem path where Table should search for table class files.
113 *
114 * @param mixed $path A filesystem path or array of filesystem paths to add.
115 *
116 * @return array An array of filesystem paths to find Table classes in.
117 */
118 public static function addIncludePath($path = null)
119 {
120 // if the internal paths have not been initialised, do so with the base table path
121 if (empty(self::$_includePaths))
122 {
123 self::$_includePaths[] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tables';
124 }
125
126 if ($path)
127 {
128 // convert the passed path(s) to add to an array.
129 $path = (array) $path;
130
131 // add each individual new path
132 foreach ($path as $dir)
133 {
134 // sanitize path
135 $dir = trim($dir);
136
137 // add to the front of the list so that custom paths are searched first
138 if (!in_array($dir, self::$_includePaths))
139 {
140 array_unshift(self::$_includePaths, $dir);
141 }
142 }
143 }
144
145 return self::$_includePaths;
146 }
147
148 /**
149 * Object constructor to set table and key fields.
150 * In most cases this will be overridden by child classes to explicitly
151 * set the table and key fields for a particular database table.
152 *
153 * @param string $table Name of the table to model.
154 * @param mixed $key Name of the primary key field in the table
155 * or array of field names that compose the primary key.
156 */
157 public function __construct($table, $key = 'id')
158 {
159 // set internal variables
160 $this->_table = $table;
161
162 // set the key to be an array.
163 if (is_string($key))
164 {
165 $key = array($key);
166 }
167 else if (is_object($key))
168 {
169 $key = (array) $key;
170 }
171
172 $this->_tableKeys = $key;
173
174 if (count($key) == 1)
175 {
176 $this->_autoincrement = true;
177 }
178 else
179 {
180 $this->_autoincrement = false;
181 }
182
183 // initialise the table properties
184 $fields = $this->getFields();
185
186 if ($fields)
187 {
188 foreach ($fields as $name => $v)
189 {
190 if (is_int($name))
191 {
192 // use the value in case we have a linear array
193 $name = $v;
194 }
195
196 // add the field if it is not already present
197 if (!property_exists($this, $name))
198 {
199 $this->{$name} = null;
200 }
201 }
202 }
203 }
204
205 /**
206 * Gets the columns from database table.
207 *
208 * @param boolean $reload Flag to reload cache.
209 *
210 * @return mixed An array of the field names, or false if an error occurs.
211 *
212 * @throws Exception
213 */
214 public function getFields($reload = false)
215 {
216 $key = $this->getTableName();
217
218 if (!isset(static::$_tableFields[$key]) || $reload)
219 {
220 $dbo = JFactory::getDbo();
221
222 // lookup the fields for this table only once
223 $fields = $dbo->getTableColumns($this->_table, false);
224
225 if (empty($fields))
226 {
227 throw new Exception(sprintf('No columns found for [%s] table', $this->_table));
228 }
229
230 static::$_tableFields[$key] = $fields;
231 }
232
233 return static::$_tableFields[$key];
234 }
235
236 /**
237 * Method to get the database table name for the class.
238 *
239 * @return string The name of the database table being modeled.
240 *
241 * @since 10.1.30
242 */
243 public function getTableName()
244 {
245 return $this->_table;
246 }
247
248 /**
249 * Method to get the primary key field name for the table.
250 *
251 * @param boolean $multiple True to return all primary keys (as an array) or false to return
252 * just the first one (as a string).
253 *
254 * @return mixed Array of primary key field names or string containing the first primary key field.
255 *
256 * @since 10.1.35
257 */
258 public function getKeyName($multiple = false)
259 {
260 // Count the number of keys
261 if (count($this->_tableKeys))
262 {
263 if ($multiple)
264 {
265 // If we want multiple keys, return the raw array.
266 return $this->_tableKeys;
267 }
268 else
269 {
270 // If we want the standard method, just return the first key.
271 return $this->_tableKeys[0];
272 }
273 }
274
275 return '';
276 }
277
278 /**
279 * Validate that the primary key has been set.
280 *
281 * @return boolean True if the primary key(s) have been set.
282 *
283 * @since 10.1.30
284 */
285 public function hasPrimaryKey()
286 {
287 if ($this->_autoincrement)
288 {
289 $empty = true;
290
291 foreach ($this->_tableKeys as $key)
292 {
293 $empty = $empty && empty($this->$key);
294 }
295 }
296 else
297 {
298 $dbo = JFactory::getDbo();
299
300 $q = $dbo->getQuery(true)
301 ->select('COUNT(*)')
302 ->from($this->_table);
303
304 $this->appendPrimaryKeys($q);
305
306 $dbo->setQuery($q);
307
308 $count = $dbo->loadResult();
309
310 if ($count == 1)
311 {
312 $empty = false;
313 }
314 else
315 {
316 $empty = true;
317 }
318 }
319
320 return !$empty;
321 }
322
323 /**
324 * Method to append the primary keys for this table to a query.
325 *
326 * @param mixed $query A query object to append.
327 * @param mixed $pk Optional primary key parameter.
328 *
329 * @return void
330 *
331 * @since 10.1.30
332 */
333 public function appendPrimaryKeys($query, $pk = null)
334 {
335 $dbo = JFactory::getDbo();
336
337 if (is_null($pk))
338 {
339 foreach ($this->_tableKeys as $k)
340 {
341 $query->where($dbo->qn($k) . ' = ' . $dbo->q($this->{$k}));
342 }
343 }
344 else
345 {
346 if (is_string($pk))
347 {
348 $pk = array($this->_tableKeys[0] => $pk);
349 }
350
351 $pk = (object) $pk;
352
353 foreach ($this->_tableKeys as $k)
354 {
355 $query->where($dbo->qn($k) . ' = ' . $dbo->q($pk->{$k}));
356 }
357 }
358 }
359
360 /**
361 * Method to reset class properties to the defaults set in the class
362 * definition. It will ignore the primary key as well as any private class
363 * properties (except $_errors).
364 *
365 * @return void
366 *
367 * @since 10.1.30
368 */
369 public function reset()
370 {
371 // get the default values for the class from the table
372 foreach ($this->getFields() as $k => $v)
373 {
374 // if the property is not the primary key or private, reset it
375 if (!in_array($k, $this->_tableKeys) && (strpos($k, '_') !== 0))
376 {
377 $this->{$k} = $v->Default;
378 }
379 }
380
381 // reset table errors
382 $this->_errors = array();
383 }
384
385 /**
386 * Method to bind an associative array or object to the Table instance.This
387 * method only binds properties that are publicly accessible and optionally
388 * takes an array of properties to ignore when binding.
389 *
390 * @param mixed $src An associative array or object to bind to the Table instance.
391 * @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
392 *
393 * @return boolean True on success.
394 *
395 * @since 10.1.30
396 *
397 * @throws InvalidArgumentException
398 */
399 public function bind($src, $ignore = array())
400 {
401 // check if the source value is an array or object
402 if (!is_object($src) && !is_array($src))
403 {
404 throw new InvalidArgumentException(
405 sprintf(
406 'Could not bind the data source in %s::bind(), the source must be an array or object but a "%s" was given.',
407 get_class($this),
408 gettype($src)
409 )
410 );
411 }
412
413 // if the source value is an object, get its accessible properties
414 if (is_object($src))
415 {
416 $src = get_object_vars($src);
417 }
418
419 $ignore = (array) $ignore;
420
421 // bind the source value, excluding the ignored fields
422 foreach ($this->getProperties() as $k => $v)
423 {
424 // only process fields not in the ignore array
425 if (!in_array($k, $ignore))
426 {
427 if (isset($src[$k]))
428 {
429 $this->{$k} = $src[$k];
430 }
431 }
432 }
433
434 return true;
435 }
436
437 /**
438 * Method to perform sanity checks on the Table instance properties to ensure they are safe to store in the database.
439 *
440 * Child classes should override this method to make sure the data they are storing in the database is safe and as expected before storage.
441 *
442 * @return boolean True if the instance is sane and able to be stored in the database.
443 *
444 * @since 10.1.30
445 */
446 public function check()
447 {
448 // inherit in children classes
449 return true;
450 }
451
452 /**
453 * Method to store a row in the database from the Table instance properties.
454 *
455 * If a primary key value is set the row with that primary key value will be updated with the instance property values.
456 * If no primary key value is set a new row will be inserted into the database with the properties from the Table instance.
457 *
458 * @param boolean $updateNulls True to update fields even if they are null.
459 *
460 * @return boolean True on success.
461 *
462 * @since 10.1.30
463 */
464 public function store($updateNulls = false)
465 {
466 $dbo = JFactory::getDbo();
467 $event = JEventDispatcher::getInstance();
468
469 $k = $this->_tableKeys;
470
471 // pre-processing by observers
472 $event->trigger('onBeforeStore', array($updateNulls, $k));
473
474 // If a primary key exists update the object, otherwise insert it.
475 if ($this->hasPrimaryKey())
476 {
477 $result = $dbo->updateObject($this->_table, $this, $this->_tableKeys, $updateNulls);
478 }
479 else
480 {
481 $result = $dbo->insertObject($this->_table, $this, $this->_tableKeys[0]);
482 }
483
484 // post-processing by observers
485 $event->trigger('onAfterStore', array(&$result));
486
487 return $result;
488 }
489
490 /**
491 * Method to provide a shortcut to binding, checking and storing a Table instance to the database table.
492 *
493 * The method will check a row in once the data has been stored and if an ordering filter is present will attempt to reorder
494 * the table rows based on the filter. The ordering filter is an instance property name. The rows that will be reordered
495 * are those whose value matches the Table instance for the property specified.
496 *
497 * @param mixed $src An associative array or object to bind to the Table instance.
498 * @param string $orderingFilter Filter for the order updating
499 * @param mixed $ignore An optional array or space separated list of properties to ignore while binding.
500 *
501 * @return boolean True on success.
502 *
503 * @since 10.1.30
504 */
505 public function save($src, $orderingFilter = '', $ignore = '')
506 {
507 // attempt to bind the source to the instance
508 if (!$this->bind($src, $ignore))
509 {
510 return false;
511 }
512
513 // run any sanity checks on the instance and verify that it is ready for storage
514 if (!$this->check())
515 {
516 return false;
517 }
518
519 // attempt to store the properties to the database table
520 if (!$this->store())
521 {
522 return false;
523 }
524
525 // ff an ordering filter is set, attempt reorder the rows in the table based on the filter and value.
526 if ($orderingFilter)
527 {
528 $dbo = JFactory::getDbo();
529
530 $filterValue = $this->{$orderingFilter};
531 $this->reorder($orderingFilter ? $dbo->qn($orderingFilter) . ' = ' . $dbo->q($filterValue) : '');
532 }
533
534 return true;
535 }
536
537 /**
538 * Method to delete a row from the database table by primary key value.
539 *
540 * @param mixed $pk An optional primary key value to delete. If not set the instance property value is used.
541 *
542 * @return boolean True on success.
543 *
544 * @since 10.1.30
545 *
546 * @throws UnexpectedValueException
547 */
548 public function delete($pk = null)
549 {
550 if (is_null($pk))
551 {
552 $pk = array();
553
554 foreach ($this->_tableKeys as $key)
555 {
556 $pk[$key] = $this->{$key};
557 }
558 }
559 else if (!is_array($pk))
560 {
561 $pk = array($this->_tableKeys[0] => $pk);
562 }
563
564 foreach ($this->_tableKeys as $key)
565 {
566 $pk[$key] = is_null($pk[$key]) ? $this->{$key} : $pk[$key];
567
568 if ($pk[$key] === null)
569 {
570 throw new UnexpectedValueException('Null primary key not allowed.');
571 }
572
573 $this->{$key} = $pk[$key];
574 }
575
576 $dbo = JFactory::getDbo();
577 $event = JEventDispatcher::getInstance();
578
579 // pre-processing by observers
580 $event->trigger('onBeforeDelete', array($pk));
581
582 // delete the row by primary key
583 $q = $dbo->getQuery(true)
584 ->delete($this->_table);
585
586 $this->appendPrimaryKeys($q, $pk);
587
588 $dbo->setQuery($q);
589
590 // check for a database error
591 $dbo->execute();
592
593 // post-processing by observers
594 $event->trigger('onAfterDelete', array($pk));
595
596 return true;
597 }
598
599 /**
600 * Method to get the next ordering value for a group of rows defined by an SQL WHERE clause.
601 *
602 * This is useful for placing a new item last in a group of items in the table.
603 *
604 * @param string $where WHERE clause to use for selecting the MAX(ordering) for the table.
605 *
606 * @return integer The next ordering value.
607 *
608 * @since 10.1.30
609 *
610 * @throws UnexpectedValueException
611 */
612 public function getNextOrder($where = '')
613 {
614 // check if there is an ordering field set
615 $orderingField = $this->getColumnAlias('ordering');
616
617 if (!property_exists($this, $orderingField))
618 {
619 throw new UnexpectedValueException(sprintf('%s does not support ordering.', get_class($this)));
620 }
621
622 $dbo = JFactory::getDbo();
623
624 // get the largest ordering value for a given where clause
625 $q = $dbo->getQuery(true)
626 ->select('MAX(' . $dbo->qn($orderingField) . ')')
627 ->from($this->_table);
628
629 if ($where)
630 {
631 $q->where($where);
632 }
633
634 $dbo->setQuery($q);
635 $max = (int) $dbo->loadResult();
636
637 // return the largest ordering value + 1
638 return $max + 1;
639 }
640
641 /**
642 * Method to compact the ordering values of rows in a group of rows defined by an SQL WHERE clause.
643 *
644 * @param string $where WHERE clause to use for limiting the selection of rows to compact the ordering values.
645 *
646 * @return mixed Boolean True on success.
647 *
648 * @since 10.1.30
649 *
650 * @throws UnexpectedValueException
651 */
652 public function reorder($where = '')
653 {
654 // check if there is an ordering field set
655 $orderingField = $this->getColumnAlias('ordering');
656
657 if (!property_exists($this, $orderingField))
658 {
659 throw new UnexpectedValueException(sprintf('%s does not support ordering.', get_class($this)));
660 }
661
662 $dbo = JFactory::getDbo();
663
664 $quotedOrderingField = $dbo->qn($orderingField);
665
666 $subquery = $dbo->getQuery(true)
667 ->from($this->_table)
668 ->selectRowNumber($quotedOrderingField, 'new_ordering');
669
670 $query = $dbo->getQuery(true)
671 ->update($this->_table)
672 ->set($quotedOrderingField . ' = sq.new_ordering');
673
674 $innerOn = array();
675
676 // get the primary keys for the selection
677 foreach ($this->_tableKeys as $i => $k)
678 {
679 $subquery->select($dbo->qn($k, 'pk__' . $i));
680 $innerOn[] = $dbo->qn($k) . ' = sq.' . $dbo->qn('pk__' . $i);
681 }
682
683 // setup the extra where and ordering clause data
684 if ($where)
685 {
686 $subquery->where($where);
687 $query->where($where);
688 }
689
690 $subquery->where($quotedOrderingField . ' >= 0');
691 $query->where($quotedOrderingField . ' >= 0');
692
693 $query->innerJoin('(' . (string) $subquery . ') AS sq ON ' . implode(' AND ', $innerOn));
694
695 $dbo->setQuery($query);
696 $dbo->execute();
697 }
698
699 /**
700 * Method to set the publishing state for a row or list of rows in the database table.
701 *
702 * The method respects checked out rows by other users and will attempt to checkin rows that it can after adjustments are made.
703 *
704 * @param mixed $pks An optional array of primary key values to update. If not set the instance property value is used.
705 * @param integer $state The publishing state. eg. [0 = unpublished, 1 = published]
706 * @param integer $userId The user ID of the user performing the operation.
707 *
708 * @return boolean True on success; false if $pks is empty.
709 *
710 * @since 10.1.30
711 */
712 public function publish($pks = null, $state = 1, $userId = 0)
713 {
714 // sanitize input
715 $userId = (int) $userId;
716 $state = (int) $state;
717
718 if (!is_null($pks))
719 {
720 if (!is_array($pks))
721 {
722 $pks = array($pks);
723 }
724
725 foreach ($pks as $key => $pk)
726 {
727 if (!is_array($pk))
728 {
729 $pks[$key] = array($this->_tableKeys[0] => $pk);
730 }
731 }
732 }
733
734 // if there are no primary keys set check to see if the instance key is set
735 if (empty($pks))
736 {
737 $pk = array();
738
739 foreach ($this->_tableKeys as $key)
740 {
741 if ($this->{$key})
742 {
743 $pk[$key] = $this->{$key};
744 }
745 // we don't have a full primary key - return false
746 else
747 {
748 $this->setError('JLIB_DATABASE_ERROR_NO_ROWS_SELECTED');
749
750 return false;
751 }
752 }
753
754 $pks = array($pk);
755 }
756
757 $dbo = JFactory::getDbo();
758
759 $publishedField = $this->getColumnAlias('published');
760
761 foreach ($pks as $pk)
762 {
763 // update the publishing state for rows with the given primary keys
764 $query = $dbo->getQuery(true)
765 ->update($this->_table)
766 ->set($dbo->qn($publishedField) . ' = ' . (int) $state);
767
768 // build the WHERE clause for the primary keys
769 $this->appendPrimaryKeys($query, $pk);
770
771 $dbo->setQuery($query);
772
773 try
774 {
775 $dbo->execute();
776 }
777 catch (RuntimeException $e)
778 {
779 $this->setError($e->getMessage());
780
781 return false;
782 }
783
784 // if the Table instance value is in the list of primary keys that were set, set the instance
785 $ours = true;
786
787 foreach ($this->_tableKeys as $key)
788 {
789 if ($this->{$key} != $pk[$key])
790 {
791 $ours = false;
792 }
793 }
794
795 if ($ours)
796 {
797 $this->{$publishedField} = $state;
798 }
799 }
800
801 return true;
802 }
803
804 /**
805 * Method to return the real name of a "special" column such as ordering, hits, published
806 * etc etc. In this way you are free to follow your db naming convention and use the
807 * built in \Joomla functions.
808 *
809 * @param string $column Name of the "special" column (ie ordering, hits).
810 *
811 * @return string The string that identify the special.
812 *
813 * @since 10.1.30
814 */
815 public function getColumnAlias($column)
816 {
817 // get the column data if set
818 if (isset($this->_columnAlias[$column]))
819 {
820 $return = $this->_columnAlias[$column];
821 }
822 else
823 {
824 $return = $column;
825 }
826
827 // sanitize the name
828 $return = preg_replace('#[^A-Z0-9_]#i', '', $return);
829
830 return $return;
831 }
832
833 /**
834 * Method to register a column alias for a "special" column.
835 *
836 * @param string $column The "special" column (i.e. ordering).
837 * @param string $columnAlias The real column name (i.e. foo_ordering).
838 *
839 * @return void
840 *
841 * @since 10.1.30
842 */
843 public function setColumnAlias($column, $columnAlias)
844 {
845 // santize the column name alias
846 $column = strtolower($column);
847 $column = preg_replace('#[^A-Z0-9_]#i', '', $column);
848
849 // set the column alias internally
850 $this->_columnAlias[$column] = $columnAlias;
851 }
852
853 /**
854 * Method to load a row from the database by primary key and bind the fields to the Table instance properties.
855 *
856 * @param mixed $keys An optional primary key value to load the row by, or an array of fields to match.
857 * If not set the instance property value is used.
858 * @param boolean $reset True to reset the default values before loading the new row.
859 *
860 * @return boolean True if successful. False if row not found.
861 *
862 * @since 10.1.35
863 */
864 public function load($keys = null, $reset = true)
865 {
866 if (empty($keys))
867 {
868 $empty = true;
869 $keys = array();
870
871 // If empty, use the value of the current key
872 foreach ($this->_tableKeys as $key)
873 {
874 $empty = $empty && empty($this->$key);
875 $keys[$key] = $this->$key;
876 }
877
878 // If empty primary key there's is no need to load anything
879 if ($empty)
880 {
881 return true;
882 }
883 }
884 else if (!is_array($keys))
885 {
886 // Load by primary key.
887 $keyCount = count($this->_tableKeys);
888
889 if ($keyCount)
890 {
891 if ($keyCount > 1)
892 {
893 throw new InvalidArgumentException('Table has multiple primary keys specified, only one primary key value provided.');
894 }
895
896 $keys = array($this->getKeyName() => $keys);
897 }
898 else
899 {
900 throw new RuntimeException('No table keys defined.');
901 }
902 }
903
904 if ($reset)
905 {
906 $this->reset();
907 }
908
909 $dbo = JFactory::getDbo();
910
911 // Initialise the query.
912 $query = $dbo->getQuery(true)
913 ->select('*')
914 ->from($this->_table);
915 $fields = array_keys($this->getProperties());
916
917 foreach ($keys as $field => $value)
918 {
919 // Check that $field is in the table.
920 if (!in_array($field, $fields))
921 {
922 throw new UnexpectedValueException(sprintf('Missing field in database: %s &#160; %s.', get_class($this), $field));
923 }
924
925 // Add the search tuple to the query.
926 $query->where($dbo->quoteName($field) . ' = ' . $dbo->quote($value));
927 }
928
929 $dbo->setQuery($query);
930
931 $row = $dbo->loadAssoc();
932
933 // check that we have a result
934 if (empty($row))
935 {
936 $result = false;
937 }
938 else
939 {
940 // Bind the object with the row and return.
941 $result = $this->bind($row);
942 }
943
944 return $result;
945 }
946 }
947