]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/DB/storage.php
[ROUTES] Allow accept-header specification during router creation
[quix0rs-gnu-social.git] / extlib / DB / storage.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6  * Provides an object interface to a table row
7  *
8  * PHP version 5
9  *
10  * LICENSE: This source file is subject to version 3.0 of the PHP license
11  * that is available through the world-wide-web at the following URI:
12  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
13  * the PHP License and are unable to obtain it through the web, please
14  * send a note to license@php.net so we can mail you a copy immediately.
15  *
16  * @category   Database
17  * @package    DB
18  * @author     Stig Bakken <stig@php.net>
19  * @copyright  1997-2007 The PHP Group
20  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
21  * @version    CVS: $Id$
22  * @link       http://pear.php.net/package/DB
23  */
24
25 /**
26  * Obtain the DB class so it can be extended from
27  */
28 require_once 'DB.php';
29
30 /**
31  * Provides an object interface to a table row
32  *
33  * It lets you add, delete and change rows using objects rather than SQL
34  * statements.
35  *
36  * @category   Database
37  * @package    DB
38  * @author     Stig Bakken <stig@php.net>
39  * @copyright  1997-2007 The PHP Group
40  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
41  * @version    Release: 1.9.2
42  * @link       http://pear.php.net/package/DB
43  */
44 class DB_storage extends PEAR
45 {
46     // {{{ properties
47
48     /** the name of the table (or view, if the backend database supports
49      * updates in views) we hold data from */
50     public $_table = null;
51
52     /** which column(s) in the table contains primary keys, can be a
53      * string for single-column primary keys, or an array of strings
54      * for multiple-column primary keys */
55     public $_keycolumn = null;
56
57     /** DB connection handle used for all transactions */
58     public $_dbh = null;
59
60     /** an assoc with the names of database fields stored as properties
61      * in this object */
62     public $_properties = array();
63
64     /** an assoc with the names of the properties in this object that
65      * have been changed since they were fetched from the database */
66     public $_changes = array();
67
68     /** flag that decides if data in this object can be changed.
69      * objects that don't have their table's key column in their
70      * property lists will be flagged as read-only. */
71     public $_readonly = false;
72
73     /** function or method that implements a validator for fields that
74      * are set, this validator function returns true if the field is
75      * valid, false if not */
76     public $_validator = null;
77
78     // }}}
79     // {{{ constructor
80
81     /**
82      * Constructor
83      *
84      * @param $table string the name of the database table
85      *
86      * @param $keycolumn mixed string with name of key column, or array of
87      * strings if the table has a primary key of more than one column
88      *
89      * @param $dbh object database connection object
90      *
91      * @param $validator mixed function or method used to validate
92      * each new value, called with three parameters: the name of the
93      * field/column that is changing, a reference to the new value and
94      * a reference to this object
95      *
96      */
97     public function __construct($table, $keycolumn, &$dbh, $validator = null)
98     {
99         $this->PEAR('DB_Error');
100         $this->_table = $table;
101         $this->_keycolumn = $keycolumn;
102         $this->_dbh = $dbh;
103         $this->_readonly = false;
104         $this->_validator = $validator;
105     }
106
107     // }}}
108     // {{{ _makeWhere()
109
110     /**
111      * Create a new (empty) row in the configured table for this
112      * object.
113      * @param $newpk
114      * @return |null
115      */
116     public function insert($newpk)
117     {
118         if (is_array($this->_keycolumn)) {
119             $primarykey = $this->_keycolumn;
120         } else {
121             $primarykey = array($this->_keycolumn);
122         }
123         settype($newpk, "array");
124         for ($i = 0; $i < sizeof($primarykey); $i++) {
125             $pkvals[] = $this->_dbh->quote($newpk[$i]);
126         }
127
128         $sth = $this->_dbh->query("INSERT INTO $this->_table (" .
129             implode(",", $primarykey) . ") VALUES(" .
130             implode(",", $pkvals) . ")");
131         if (DB::isError($sth)) {
132             return $sth;
133         }
134         if (sizeof($newpk) == 1) {
135             $newpk = $newpk[0];
136         }
137         $this->setup($newpk);
138         return null;
139     }
140
141     // }}}
142     // {{{ setup()
143
144     /**
145      * Method used to initialize a DB_storage object from the
146      * configured table.
147      *
148      * @param $keyval mixed the key[s] of the row to fetch (string or array)
149      *
150      * @return int|object
151      */
152     public function setup($keyval)
153     {
154         $whereclause = $this->_makeWhere($keyval);
155         $query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
156         $sth = $this->_dbh->query($query);
157         if (DB::isError($sth)) {
158             return $sth;
159         }
160         $row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
161         if (DB::isError($row)) {
162             return $row;
163         }
164         if (!$row) {
165             return $this->raiseError(
166                 null,
167                 DB_ERROR_NOT_FOUND,
168                 null,
169                 null,
170                 $query,
171                 null,
172                 true
173             );
174         }
175         foreach ($row as $key => $value) {
176             $this->_properties[$key] = true;
177             $this->$key = $value;
178         }
179         return DB_OK;
180     }
181
182     // }}}
183     // {{{ insert()
184
185     /**
186      * Utility method to build a "WHERE" clause to locate ourselves in
187      * the table.
188      *
189      * XXX future improvement: use rowids?
190      *
191      * @access private
192      * @param null $keyval
193      * @return mixed|string|null
194      */
195     public function _makeWhere($keyval = null)
196     {
197         if (is_array($this->_keycolumn)) {
198             if ($keyval === null) {
199                 for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
200                     $keyval[] = $this->{$this->_keycolumn[$i]};
201                 }
202             }
203             $whereclause = '';
204             for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
205                 if ($i > 0) {
206                     $whereclause .= ' AND ';
207                 }
208                 $whereclause .= $this->_keycolumn[$i];
209                 if (is_null($keyval[$i])) {
210                     // there's not much point in having a NULL key,
211                     // but we support it anyway
212                     $whereclause .= ' IS NULL';
213                 } else {
214                     $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
215                 }
216             }
217         } else {
218             if ($keyval === null) {
219                 $keyval = @$this->{$this->_keycolumn};
220             }
221             $whereclause = $this->_keycolumn;
222             if (is_null($keyval)) {
223                 // there's not much point in having a NULL key,
224                 // but we support it anyway
225                 $whereclause .= ' IS NULL';
226             } else {
227                 $whereclause .= ' = ' . $this->_dbh->quote($keyval);
228             }
229         }
230         return $whereclause;
231     }
232
233     // }}}
234     // {{{ toString()
235
236     /**
237      * Output a simple description of this DB_storage object.
238      * @return string object description
239      */
240     public function toString()
241     {
242         $info = strtolower(get_class($this));
243         $info .= " (table=";
244         $info .= $this->_table;
245         $info .= ", keycolumn=";
246         if (is_array($this->_keycolumn)) {
247             $info .= "(" . implode(",", $this->_keycolumn) . ")";
248         } else {
249             $info .= $this->_keycolumn;
250         }
251         $info .= ", dbh=";
252         if (is_object($this->_dbh)) {
253             $info .= $this->_dbh->toString();
254         } else {
255             $info .= "null";
256         }
257         $info .= ")";
258         if (sizeof($this->_properties)) {
259             $info .= " [loaded, key=";
260             $keyname = $this->_keycolumn;
261             if (is_array($keyname)) {
262                 $info .= "(";
263                 for ($i = 0; $i < sizeof($keyname); $i++) {
264                     if ($i > 0) {
265                         $info .= ",";
266                     }
267                     $info .= $this->$keyname[$i];
268                 }
269                 $info .= ")";
270             } else {
271                 $info .= $this->$keyname;
272             }
273             $info .= "]";
274         }
275         if (sizeof($this->_changes)) {
276             $info .= " [modified]";
277         }
278         return $info;
279     }
280
281     // }}}
282     // {{{ dump()
283
284     /**
285      * Dump the contents of this object to "standard output".
286      */
287     public function dump()
288     {
289         foreach ($this->_properties as $prop => $foo) {
290             print "$prop = ";
291             print htmlentities($this->$prop);
292             print "<br />\n";
293         }
294     }
295
296     // }}}
297     // {{{ &create()
298
299     /**
300      * Static method used to create new DB storage objects.
301      * @param $table
302      * @param $data assoc. array where the keys are the names
303      *              of properties/columns
304      * @return object a new instance of DB_storage or a subclass of it
305      */
306     public function &create($table, &$data)
307     {
308         $classname = strtolower(get_class($this));
309         $obj = new $classname($table);
310         foreach ($data as $name => $value) {
311             $obj->_properties[$name] = true;
312             $obj->$name = &$value;
313         }
314         return $obj;
315     }
316
317     // }}}
318     // {{{ loadFromQuery()
319
320     /**
321      * Loads data into this object from the given query.  If this
322      * object already contains table data, changes will be saved and
323      * the object re-initialized first.
324      *
325      * @param $query SQL query
326      *
327      * @param $params parameter list in case you want to use
328      * prepare/execute mode
329      *
330      * @return int DB_OK on success, DB_WARNING_READ_ONLY if the
331      * returned object is read-only (because the object's specified
332      * key column was not found among the columns returned by $query),
333      * or another DB error code in case of errors.
334      */
335     // XXX commented out for now
336     /*
337         function loadFromQuery($query, $params = null)
338         {
339             if (sizeof($this->_properties)) {
340                 if (sizeof($this->_changes)) {
341                     $this->store();
342                     $this->_changes = array();
343                 }
344                 $this->_properties = array();
345             }
346             $rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
347             if (DB::isError($rowdata)) {
348                 return $rowdata;
349             }
350             reset($rowdata);
351             $found_keycolumn = false;
352             while (list($key, $value) = each($rowdata)) {
353                 if ($key == $this->_keycolumn) {
354                     $found_keycolumn = true;
355                 }
356                 $this->_properties[$key] = true;
357                 $this->$key = &$value;
358                 unset($value); // have to unset, or all properties will
359                                // refer to the same value
360             }
361             if (!$found_keycolumn) {
362                 $this->_readonly = true;
363                 return DB_WARNING_READ_ONLY;
364             }
365             return DB_OK;
366         }
367      */
368
369     // }}}
370     // {{{ set()
371
372     /**
373      * Modify an attriute value.
374      * @param $property
375      * @param $newvalue
376      * @return bool|object
377      */
378     public function set($property, $newvalue)
379     {
380         // only change if $property is known and object is not
381         // read-only
382         if ($this->_readonly) {
383             return $this->raiseError(
384                 null,
385                 DB_WARNING_READ_ONLY,
386                 null,
387                 null,
388                 null,
389                 null,
390                 true
391             );
392         }
393         if (@isset($this->_properties[$property])) {
394             if (empty($this->_validator)) {
395                 $valid = true;
396             } else {
397                 $valid = @call_user_func(
398                     $this->_validator,
399                     $this->_table,
400                     $property,
401                     $newvalue,
402                     $this->$property,
403                     $this
404                 );
405             }
406             if ($valid) {
407                 $this->$property = $newvalue;
408                 if (empty($this->_changes[$property])) {
409                     $this->_changes[$property] = 0;
410                 } else {
411                     $this->_changes[$property]++;
412                 }
413             } else {
414                 return $this->raiseError(
415                     null,
416                     DB_ERROR_INVALID,
417                     null,
418                     null,
419                     "invalid field: $property",
420                     null,
421                     true
422                 );
423             }
424             return true;
425         }
426         return $this->raiseError(
427             null,
428             DB_ERROR_NOSUCHFIELD,
429             null,
430             null,
431             "unknown field: $property",
432             null,
433             true
434         );
435     }
436
437     // }}}
438     // {{{ &get()
439
440     /**
441      * Fetch an attribute value.
442      *
443      * @param string attribute name
444      *
445      * @return attribute contents, or null if the attribute name is
446      * unknown
447      */
448     public function &get($property)
449     {
450         // only return if $property is known
451         if (isset($this->_properties[$property])) {
452             return $this->$property;
453         }
454         $tmp = null;
455         return $tmp;
456     }
457
458     // }}}
459     // {{{ _DB_storage()
460
461     /**
462      * Destructor, calls DB_storage::store() if there are changes
463      * that are to be kept.
464      */
465     public function _DB_storage()
466     {
467         if (sizeof($this->_changes)) {
468             $this->store();
469         }
470         $this->_properties = array();
471         $this->_changes = array();
472         $this->_table = null;
473     }
474
475     // }}}
476     // {{{ store()
477
478     /**
479      * Stores changes to this object in the database.
480      *
481      * @return DB_OK|int
482      */
483     public function store()
484     {
485         $params = array();
486         $vars = array();
487         foreach ($this->_changes as $name => $foo) {
488             $params[] = &$this->$name;
489             $vars[] = $name . ' = ?';
490         }
491         if ($vars) {
492             $query = 'UPDATE ' . $this->_table . ' SET ' .
493                 implode(', ', $vars) . ' WHERE ' .
494                 $this->_makeWhere();
495             $stmt = $this->_dbh->prepare($query);
496             $res = $this->_dbh->execute($stmt, $params);
497             if (DB::isError($res)) {
498                 return $res;
499             }
500             $this->_changes = array();
501         }
502         return DB_OK;
503     }
504
505     // }}}
506     // {{{ remove()
507
508     /**
509      * Remove the row represented by this object from the database.
510      *
511      * @return mixed DB_OK or a DB error
512      */
513     public function remove()
514     {
515         if ($this->_readonly) {
516             return $this->raiseError(
517                 null,
518                 DB_WARNING_READ_ONLY,
519                 null,
520                 null,
521                 null,
522                 null,
523                 true
524             );
525         }
526         $query = 'DELETE FROM ' . $this->_table . ' WHERE ' .
527             $this->_makeWhere();
528         $res = $this->_dbh->query($query);
529         if (DB::isError($res)) {
530             return $res;
531         }
532         foreach ($this->_properties as $prop => $foo) {
533             unset($this->$prop);
534         }
535         $this->_properties = array();
536         $this->_changes = array();
537         return DB_OK;
538     }
539
540     // }}}
541 }
542
543 /*
544  * Local variables:
545  * tab-width: 4
546  * c-basic-offset: 4
547  * End:
548  */