]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/DB/storage.php
no notice form on invites
[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 versions 4 and 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: storage.php,v 1.24 2007/08/12 05:27:25 aharvey Exp $
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.7.14RC1
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     var $_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     var $_keycolumn = null;
56
57     /** DB connection handle used for all transactions */
58     var $_dbh = null;
59
60     /** an assoc with the names of database fields stored as properties
61         in this object */
62     var $_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     var $_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     var $_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     var $_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     function DB_storage($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      * Utility method to build a "WHERE" clause to locate ourselves in
112      * the table.
113      *
114      * XXX future improvement: use rowids?
115      *
116      * @access private
117      */
118     function _makeWhere($keyval = null)
119     {
120         if (is_array($this->_keycolumn)) {
121             if ($keyval === null) {
122                 for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
123                     $keyval[] = $this->{$this->_keycolumn[$i]};
124                 }
125             }
126             $whereclause = '';
127             for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
128                 if ($i > 0) {
129                     $whereclause .= ' AND ';
130                 }
131                 $whereclause .= $this->_keycolumn[$i];
132                 if (is_null($keyval[$i])) {
133                     // there's not much point in having a NULL key,
134                     // but we support it anyway
135                     $whereclause .= ' IS NULL';
136                 } else {
137                     $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
138                 }
139             }
140         } else {
141             if ($keyval === null) {
142                 $keyval = @$this->{$this->_keycolumn};
143             }
144             $whereclause = $this->_keycolumn;
145             if (is_null($keyval)) {
146                 // there's not much point in having a NULL key,
147                 // but we support it anyway
148                 $whereclause .= ' IS NULL';
149             } else {
150                 $whereclause .= ' = ' . $this->_dbh->quote($keyval);
151             }
152         }
153         return $whereclause;
154     }
155
156     // }}}
157     // {{{ setup()
158
159     /**
160      * Method used to initialize a DB_storage object from the
161      * configured table.
162      *
163      * @param $keyval mixed the key[s] of the row to fetch (string or array)
164      *
165      * @return int DB_OK on success, a DB error if not
166      */
167     function setup($keyval)
168     {
169         $whereclause = $this->_makeWhere($keyval);
170         $query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
171         $sth = $this->_dbh->query($query);
172         if (DB::isError($sth)) {
173             return $sth;
174         }
175         $row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
176         if (DB::isError($row)) {
177             return $row;
178         }
179         if (!$row) {
180             return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null,
181                                      $query, null, true);
182         }
183         foreach ($row as $key => $value) {
184             $this->_properties[$key] = true;
185             $this->$key = $value;
186         }
187         return DB_OK;
188     }
189
190     // }}}
191     // {{{ insert()
192
193     /**
194      * Create a new (empty) row in the configured table for this
195      * object.
196      */
197     function insert($newpk)
198     {
199         if (is_array($this->_keycolumn)) {
200             $primarykey = $this->_keycolumn;
201         } else {
202             $primarykey = array($this->_keycolumn);
203         }
204         settype($newpk, "array");
205         for ($i = 0; $i < sizeof($primarykey); $i++) {
206             $pkvals[] = $this->_dbh->quote($newpk[$i]);
207         }
208
209         $sth = $this->_dbh->query("INSERT INTO $this->_table (" .
210                                   implode(",", $primarykey) . ") VALUES(" .
211                                   implode(",", $pkvals) . ")");
212         if (DB::isError($sth)) {
213             return $sth;
214         }
215         if (sizeof($newpk) == 1) {
216             $newpk = $newpk[0];
217         }
218         $this->setup($newpk);
219     }
220
221     // }}}
222     // {{{ toString()
223
224     /**
225      * Output a simple description of this DB_storage object.
226      * @return string object description
227      */
228     function toString()
229     {
230         $info = strtolower(get_class($this));
231         $info .= " (table=";
232         $info .= $this->_table;
233         $info .= ", keycolumn=";
234         if (is_array($this->_keycolumn)) {
235             $info .= "(" . implode(",", $this->_keycolumn) . ")";
236         } else {
237             $info .= $this->_keycolumn;
238         }
239         $info .= ", dbh=";
240         if (is_object($this->_dbh)) {
241             $info .= $this->_dbh->toString();
242         } else {
243             $info .= "null";
244         }
245         $info .= ")";
246         if (sizeof($this->_properties)) {
247             $info .= " [loaded, key=";
248             $keyname = $this->_keycolumn;
249             if (is_array($keyname)) {
250                 $info .= "(";
251                 for ($i = 0; $i < sizeof($keyname); $i++) {
252                     if ($i > 0) {
253                         $info .= ",";
254                     }
255                     $info .= $this->$keyname[$i];
256                 }
257                 $info .= ")";
258             } else {
259                 $info .= $this->$keyname;
260             }
261             $info .= "]";
262         }
263         if (sizeof($this->_changes)) {
264             $info .= " [modified]";
265         }
266         return $info;
267     }
268
269     // }}}
270     // {{{ dump()
271
272     /**
273      * Dump the contents of this object to "standard output".
274      */
275     function dump()
276     {
277         foreach ($this->_properties as $prop => $foo) {
278             print "$prop = ";
279             print htmlentities($this->$prop);
280             print "<br />\n";
281         }
282     }
283
284     // }}}
285     // {{{ &create()
286
287     /**
288      * Static method used to create new DB storage objects.
289      * @param $data assoc. array where the keys are the names
290      *              of properties/columns
291      * @return object a new instance of DB_storage or a subclass of it
292      */
293     function &create($table, &$data)
294     {
295         $classname = strtolower(get_class($this));
296         $obj = new $classname($table);
297         foreach ($data as $name => $value) {
298             $obj->_properties[$name] = true;
299             $obj->$name = &$value;
300         }
301         return $obj;
302     }
303
304     // }}}
305     // {{{ loadFromQuery()
306
307     /**
308      * Loads data into this object from the given query.  If this
309      * object already contains table data, changes will be saved and
310      * the object re-initialized first.
311      *
312      * @param $query SQL query
313      *
314      * @param $params parameter list in case you want to use
315      * prepare/execute mode
316      *
317      * @return int DB_OK on success, DB_WARNING_READ_ONLY if the
318      * returned object is read-only (because the object's specified
319      * key column was not found among the columns returned by $query),
320      * or another DB error code in case of errors.
321      */
322 // XXX commented out for now
323 /*
324     function loadFromQuery($query, $params = null)
325     {
326         if (sizeof($this->_properties)) {
327             if (sizeof($this->_changes)) {
328                 $this->store();
329                 $this->_changes = array();
330             }
331             $this->_properties = array();
332         }
333         $rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
334         if (DB::isError($rowdata)) {
335             return $rowdata;
336         }
337         reset($rowdata);
338         $found_keycolumn = false;
339         while (list($key, $value) = each($rowdata)) {
340             if ($key == $this->_keycolumn) {
341                 $found_keycolumn = true;
342             }
343             $this->_properties[$key] = true;
344             $this->$key = &$value;
345             unset($value); // have to unset, or all properties will
346                            // refer to the same value
347         }
348         if (!$found_keycolumn) {
349             $this->_readonly = true;
350             return DB_WARNING_READ_ONLY;
351         }
352         return DB_OK;
353     }
354  */
355
356     // }}}
357     // {{{ set()
358
359     /**
360      * Modify an attriute value.
361      */
362     function set($property, $newvalue)
363     {
364         // only change if $property is known and object is not
365         // read-only
366         if ($this->_readonly) {
367             return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
368                                      null, null, null, true);
369         }
370         if (@isset($this->_properties[$property])) {
371             if (empty($this->_validator)) {
372                 $valid = true;
373             } else {
374                 $valid = @call_user_func($this->_validator,
375                                          $this->_table,
376                                          $property,
377                                          $newvalue,
378                                          $this->$property,
379                                          $this);
380             }
381             if ($valid) {
382                 $this->$property = $newvalue;
383                 if (empty($this->_changes[$property])) {
384                     $this->_changes[$property] = 0;
385                 } else {
386                     $this->_changes[$property]++;
387                 }
388             } else {
389                 return $this->raiseError(null, DB_ERROR_INVALID, null,
390                                          null, "invalid field: $property",
391                                          null, true);
392             }
393             return true;
394         }
395         return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null,
396                                  null, "unknown field: $property",
397                                  null, true);
398     }
399
400     // }}}
401     // {{{ &get()
402
403     /**
404      * Fetch an attribute value.
405      *
406      * @param string attribute name
407      *
408      * @return attribute contents, or null if the attribute name is
409      * unknown
410      */
411     function &get($property)
412     {
413         // only return if $property is known
414         if (isset($this->_properties[$property])) {
415             return $this->$property;
416         }
417         $tmp = null;
418         return $tmp;
419     }
420
421     // }}}
422     // {{{ _DB_storage()
423
424     /**
425      * Destructor, calls DB_storage::store() if there are changes
426      * that are to be kept.
427      */
428     function _DB_storage()
429     {
430         if (sizeof($this->_changes)) {
431             $this->store();
432         }
433         $this->_properties = array();
434         $this->_changes = array();
435         $this->_table = null;
436     }
437
438     // }}}
439     // {{{ store()
440
441     /**
442      * Stores changes to this object in the database.
443      *
444      * @return DB_OK or a DB error
445      */
446     function store()
447     {
448         $params = array();
449         $vars = array();
450         foreach ($this->_changes as $name => $foo) {
451             $params[] = &$this->$name;
452             $vars[] = $name . ' = ?';
453         }
454         if ($vars) {
455             $query = 'UPDATE ' . $this->_table . ' SET ' .
456                 implode(', ', $vars) . ' WHERE ' .
457                 $this->_makeWhere();
458             $stmt = $this->_dbh->prepare($query);
459             $res = $this->_dbh->execute($stmt, $params);
460             if (DB::isError($res)) {
461                 return $res;
462             }
463             $this->_changes = array();
464         }
465         return DB_OK;
466     }
467
468     // }}}
469     // {{{ remove()
470
471     /**
472      * Remove the row represented by this object from the database.
473      *
474      * @return mixed DB_OK or a DB error
475      */
476     function remove()
477     {
478         if ($this->_readonly) {
479             return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
480                                      null, null, null, true);
481         }
482         $query = 'DELETE FROM ' . $this->_table .' WHERE '.
483             $this->_makeWhere();
484         $res = $this->_dbh->query($query);
485         if (DB::isError($res)) {
486             return $res;
487         }
488         foreach ($this->_properties as $prop => $foo) {
489             unset($this->$prop);
490         }
491         $this->_properties = array();
492         $this->_changes = array();
493         return DB_OK;
494     }
495
496     // }}}
497 }
498
499 /*
500  * Local variables:
501  * tab-width: 4
502  * c-basic-offset: 4
503  * End:
504  */
505
506 ?>