source: branches/dev/data/module/MDB2/Extended.php @ 15986

Revision 15986, 25.5 KB checked in by kakinaka, 19 years ago (diff)
Line 
1<?php
2// +----------------------------------------------------------------------+
3// | PHP versions 4 and 5                                                 |
4// +----------------------------------------------------------------------+
5// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox,                 |
6// | Stig. S. Bakken, Lukas Smith                                         |
7// | All rights reserved.                                                 |
8// +----------------------------------------------------------------------+
9// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
10// | API as well as database abstraction for PHP applications.            |
11// | This LICENSE is in the BSD license style.                            |
12// |                                                                      |
13// | Redistribution and use in source and binary forms, with or without   |
14// | modification, are permitted provided that the following conditions   |
15// | are met:                                                             |
16// |                                                                      |
17// | Redistributions of source code must retain the above copyright       |
18// | notice, this list of conditions and the following disclaimer.        |
19// |                                                                      |
20// | Redistributions in binary form must reproduce the above copyright    |
21// | notice, this list of conditions and the following disclaimer in the  |
22// | documentation and/or other materials provided with the distribution. |
23// |                                                                      |
24// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
25// | Lukas Smith nor the names of his contributors may be used to endorse |
26// | or promote products derived from this software without specific prior|
27// | written permission.                                                  |
28// |                                                                      |
29// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
30// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
31// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
32// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
33// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
34// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
37// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
38// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
40// | POSSIBILITY OF SUCH DAMAGE.                                          |
41// +----------------------------------------------------------------------+
42// | Author: Lukas Smith <[email protected]>                           |
43// +----------------------------------------------------------------------+
44//
45// $Id: Extended.php,v 1.58 2007/01/06 21:40:52 quipo Exp $
46
47/**
48 * @package  MDB2
49 * @category Database
50 * @author   Lukas Smith <[email protected]>
51 */
52
53/**
54 * Used by autoPrepare()
55 */
56define('MDB2_AUTOQUERY_INSERT', 1);
57define('MDB2_AUTOQUERY_UPDATE', 2);
58define('MDB2_AUTOQUERY_DELETE', 3);
59define('MDB2_AUTOQUERY_SELECT', 4);
60
61/**
62 * MDB2_Extended: class which adds several high level methods to MDB2
63 *
64 * @package MDB2
65 * @category Database
66 * @author Lukas Smith <[email protected]>
67 */
68class MDB2_Extended extends MDB2_Module_Common
69{
70    // {{{ autoPrepare()
71
72    /**
73     * Generate an insert, update or delete query and call prepare() on it
74     *
75     * @param string table
76     * @param array the fields names
77     * @param int type of query to build
78     *                          MDB2_AUTOQUERY_INSERT
79     *                          MDB2_AUTOQUERY_UPDATE
80     *                          MDB2_AUTOQUERY_DELETE
81     *                          MDB2_AUTOQUERY_SELECT
82     * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
83     * @param array that contains the types of the placeholders
84     * @param mixed array that contains the types of the columns in
85     *                        the result set or MDB2_PREPARE_RESULT, if set to
86     *                        MDB2_PREPARE_MANIP the query is handled as a manipulation query
87     *
88     * @return resource handle for the query
89     * @see buildManipSQL
90     * @access public
91     */
92    function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT,
93        $where = false, $types = null, $result_types = MDB2_PREPARE_MANIP)
94    {
95        $query = $this->buildManipSQL($table, $table_fields, $mode, $where);
96        if (PEAR::isError($query)) {
97            return $query;
98        }
99        $db =& $this->getDBInstance();
100        if (PEAR::isError($db)) {
101            return $db;
102        }
103        return $db->prepare($query, $types, $result_types);
104    }
105    // }}}
106
107    // {{{ autoExecute()
108
109    /**
110     * Generate an insert, update or delete query and call prepare() and execute() on it
111     *
112     * @param string name of the table
113     * @param array assoc ($key=>$value) where $key is a field name and $value its value
114     * @param int type of query to build
115     *                          MDB2_AUTOQUERY_INSERT
116     *                          MDB2_AUTOQUERY_UPDATE
117     *                          MDB2_AUTOQUERY_DELETE
118     *                          MDB2_AUTOQUERY_SELECT
119     * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
120     * @param array that contains the types of the placeholders
121     * @param string which specifies which result class to use
122     * @param mixed  array that contains the types of the columns in
123     *                        the result set or MDB2_PREPARE_RESULT, if set to
124     *                        MDB2_PREPARE_MANIP the query is handled as a manipulation query
125     *
126     * @return bool|MDB2_Error true on success, a MDB2 error on failure
127     * @see buildManipSQL
128     * @see autoPrepare
129     * @access public
130    */
131    function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT,
132        $where = false, $types = null, $result_class = true, $result_types = MDB2_PREPARE_MANIP)
133    {
134        $fields_values = (array)$fields_values;
135        if ($mode == MDB2_AUTOQUERY_SELECT) {
136            if (is_array($result_types)) {
137                $keys = array_keys($result_types);
138            } elseif (!empty($fields_values)) {
139                $keys = $fields_values;
140            } else {
141                $keys = array();
142            }
143        } else {
144            $keys = array_keys($fields_values);
145        }
146        $params = array_values($fields_values);
147        if (empty($params)) {
148            $query = $this->buildManipSQL($table, $keys, $mode, $where);
149
150            $db =& $this->getDBInstance();
151            if (PEAR::isError($db)) {
152                return $db;
153            }
154            if ($mode == MDB2_AUTOQUERY_SELECT) {
155                $result =& $db->query($query, $result_types, $result_class);
156            } else {
157                $result = $db->exec($query);
158            }
159        } else {
160            $stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types);
161            if (PEAR::isError($stmt)) {
162                return $stmt;
163            }
164            $result =& $stmt->execute($params, $result_class);
165            $stmt->free();
166        }
167        return $result;
168    }
169    // }}}
170
171    // {{{ buildManipSQL()
172
173    /**
174     * Make automaticaly an sql query for prepare()
175     *
176     * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), MDB2_AUTOQUERY_INSERT)
177     *           will return the string : INSERT INTO table_sql (field1,field2,field3) VALUES (?,?,?)
178     * NB : - This belongs more to a SQL Builder class, but this is a simple facility
179     *      - Be carefull ! If you don't give a $where param with an UPDATE/DELETE query, all
180     *        the records of the table will be updated/deleted !
181     *
182     * @param string name of the table
183     * @param ordered array containing the fields names
184     * @param int type of query to build
185     *                          MDB2_AUTOQUERY_INSERT
186     *                          MDB2_AUTOQUERY_UPDATE
187     *                          MDB2_AUTOQUERY_DELETE
188     *                          MDB2_AUTOQUERY_SELECT
189     * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement)
190     *
191     * @return string sql query for prepare()
192     * @access public
193     */
194    function buildManipSQL($table, $table_fields, $mode, $where = false)
195    {
196        $db =& $this->getDBInstance();
197        if (PEAR::isError($db)) {
198            return $db;
199        }
200
201        if ($db->options['quote_identifier']) {
202            $table = $db->quoteIdentifier($table);
203        }
204
205        if (!empty($table_fields) && $db->options['quote_identifier']) {
206            foreach ($table_fields as $key => $field) {
207                $table_fields[$key] = $db->quoteIdentifier($field);
208            }
209        }
210
211        if ($where !== false && !is_null($where)) {
212            if (is_array($where)) {
213                $where = implode(' AND ', $where);
214            }
215            $where = ' WHERE '.$where;
216        }
217
218        switch ($mode) {
219        case MDB2_AUTOQUERY_INSERT:
220            if (empty($table_fields)) {
221                return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
222                'Insert requires table fields', __FUNCTION__);
223            }
224            $cols = implode(', ', $table_fields);
225            $values = '?'.str_repeat(', ?', (count($table_fields) - 1));
226            return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')';
227            break;
228        case MDB2_AUTOQUERY_UPDATE:
229            if (empty($table_fields)) {
230                return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
231                'Update requires table fields', __FUNCTION__);
232            }
233            $set = implode(' = ?, ', $table_fields).' = ?';
234            $sql = 'UPDATE '.$table.' SET '.$set.$where;
235            return $sql;
236            break;
237        case MDB2_AUTOQUERY_DELETE:
238            $sql = 'DELETE FROM '.$table.$where;
239            return $sql;
240            break;
241        case MDB2_AUTOQUERY_SELECT:
242            $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*';
243            $sql = 'SELECT '.$cols.' FROM '.$table.$where;
244            return $sql;
245            break;
246        }
247        return $db->raiseError(MDB2_ERROR_SYNTAX, null, null,
248                'Non existant mode', __FUNCTION__);
249    }
250    // }}}
251
252    // {{{ limitQuery()
253
254    /**
255     * Generates a limited query
256     *
257     * @param string query
258     * @param array that contains the types of the columns in the result set
259     * @param integer the numbers of rows to fetch
260     * @param integer the row to start to fetching
261     * @param string which specifies which result class to use
262     * @param mixed   string which specifies which class to wrap results in
263     *
264     * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure
265     * @access public
266     */
267    function &limitQuery($query, $types, $limit, $offset = 0, $result_class = true,
268        $result_wrap_class = false)
269    {
270        $db =& $this->getDBInstance();
271        if (PEAR::isError($db)) {
272            return $db;
273        }
274
275        $result = $db->setLimit($limit, $offset);
276        if (PEAR::isError($result)) {
277            return $result;
278        }
279        $result =& $db->query($query, $types, $result_class, $result_wrap_class);
280        return $result;
281    }
282    // }}}
283
284    // {{{ execParam()
285
286    /**
287     * Execute a parameterized DML statement.
288     *
289     * @param string the SQL query
290     * @param array if supplied, prepare/execute will be used
291     *       with this array as execute parameters
292     * @param array that contains the types of the values defined in $params
293     *
294     * @return int|MDB2_Error affected rows on success, a MDB2 error on failure
295     * @access public
296     */
297    function execParam($query, $params = array(), $param_types = null)
298    {
299        $db =& $this->getDBInstance();
300        if (PEAR::isError($db)) {
301            return $db;
302        }
303
304        settype($params, 'array');
305        if (empty($params)) {
306            return $db->exec($query);
307        }
308
309        $stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP);
310        if (PEAR::isError($stmt)) {
311            return $stmt;
312        }
313
314        $result = $stmt->execute($params);
315        if (PEAR::isError($result)) {
316            return $result;
317        }
318
319        $stmt->free();
320        return $result;
321    }
322    // }}}
323
324    // {{{ getOne()
325
326    /**
327     * Fetch the first column of the first row of data returned from a query.
328     * Takes care of doing the query and freeing the results when finished.
329     *
330     * @param string the SQL query
331     * @param string that contains the type of the column in the result set
332     * @param array if supplied, prepare/execute will be used
333     *       with this array as execute parameters
334     * @param array that contains the types of the values defined in $params
335     * @param int|string which column to return
336     *
337     * @return scalar|MDB2_Error data on success, a MDB2 error on failure
338     * @access public
339     */
340    function getOne($query, $type = null, $params = array(),
341        $param_types = null, $colnum = 0)
342    {
343        $db =& $this->getDBInstance();
344        if (PEAR::isError($db)) {
345            return $db;
346        }
347
348        settype($params, 'array');
349        settype($type, 'array');
350        if (empty($params)) {
351            return $db->queryOne($query, $type, $colnum);
352        }
353
354        $stmt = $db->prepare($query, $param_types, $type);
355        if (PEAR::isError($stmt)) {
356            return $stmt;
357        }
358
359        $result = $stmt->execute($params);
360        if (!MDB2::isResultCommon($result)) {
361            return $result;
362        }
363
364        $one = $result->fetchOne($colnum);
365        $stmt->free();
366        $result->free();
367        return $one;
368    }
369    // }}}
370
371    // {{{ getRow()
372
373    /**
374     * Fetch the first row of data returned from a query.  Takes care
375     * of doing the query and freeing the results when finished.
376     *
377     * @param string the SQL query
378     * @param array that contains the types of the columns in the result set
379     * @param array if supplied, prepare/execute will be used
380     *       with this array as execute parameters
381     * @param array that contains the types of the values defined in $params
382     * @param int the fetch mode to use
383     *
384     * @return array|MDB2_Error data on success, a MDB2 error on failure
385     * @access public
386     */
387    function getRow($query, $types = null, $params = array(),
388        $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT)
389    {
390        $db =& $this->getDBInstance();
391        if (PEAR::isError($db)) {
392            return $db;
393        }
394
395        settype($params, 'array');
396        if (empty($params)) {
397            return $db->queryRow($query, $types, $fetchmode);
398        }
399
400        $stmt = $db->prepare($query, $param_types, $types);
401        if (PEAR::isError($stmt)) {
402            return $stmt;
403        }
404
405        $result = $stmt->execute($params);
406        if (!MDB2::isResultCommon($result)) {
407            return $result;
408        }
409
410        $row = $result->fetchRow($fetchmode);
411        $stmt->free();
412        $result->free();
413        return $row;
414    }
415    // }}}
416
417    // {{{ getCol()
418
419    /**
420     * Fetch a single column from a result set and return it as an
421     * indexed array.
422     *
423     * @param string the SQL query
424     * @param string that contains the type of the column in the result set
425     * @param array if supplied, prepare/execute will be used
426     *       with this array as execute parameters
427     * @param array that contains the types of the values defined in $params
428     * @param int|string which column to return
429     *
430     * @return array|MDB2_Error data on success, a MDB2 error on failure
431     * @access public
432     */
433    function getCol($query, $type = null, $params = array(),
434        $param_types = null, $colnum = 0)
435    {
436        $db =& $this->getDBInstance();
437        if (PEAR::isError($db)) {
438            return $db;
439        }
440
441        settype($params, 'array');
442        settype($type, 'array');
443        if (empty($params)) {
444            return $db->queryCol($query, $type, $colnum);
445        }
446
447        $stmt = $db->prepare($query, $param_types, $type);
448        if (PEAR::isError($stmt)) {
449            return $stmt;
450        }
451
452        $result = $stmt->execute($params);
453        if (!MDB2::isResultCommon($result)) {
454            return $result;
455        }
456
457        $col = $result->fetchCol($colnum);
458        $stmt->free();
459        $result->free();
460        return $col;
461    }
462    // }}}
463
464    // {{{ getAll()
465
466    /**
467     * Fetch all the rows returned from a query.
468     *
469     * @param string the SQL query
470     * @param array that contains the types of the columns in the result set
471     * @param array if supplied, prepare/execute will be used
472     *       with this array as execute parameters
473     * @param array that contains the types of the values defined in $params
474     * @param int the fetch mode to use
475     * @param bool if set to true, the $all will have the first
476     *       column as its first dimension
477     * @param bool $force_array used only when the query returns exactly
478     *       two columns. If true, the values of the returned array will be
479     *       one-element arrays instead of scalars.
480     * @param bool $group if true, the values of the returned array is
481     *       wrapped in another array.  If the same key value (in the first
482     *       column) repeats itself, the values will be appended to this array
483     *       instead of overwriting the existing values.
484     *
485     * @return array|MDB2_Error data on success, a MDB2 error on failure
486     * @access public
487     */
488    function getAll($query, $types = null, $params = array(),
489        $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT,
490        $rekey = false, $force_array = false, $group = false)
491    {
492        $db =& $this->getDBInstance();
493        if (PEAR::isError($db)) {
494            return $db;
495        }
496
497        settype($params, 'array');
498        if (empty($params)) {
499            return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group);
500        }
501       
502        $stmt = $db->prepare($query, $param_types, $types);
503        if (PEAR::isError($stmt)) {
504            return $stmt;
505        }
506
507        $result = $stmt->execute($params);
508        if (!MDB2::isResultCommon($result)) {
509            return $result;
510        }
511       
512        $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group);
513        $stmt->free();
514        $result->free();
515        return $all;
516    }
517    // }}}
518
519    // {{{ getAssoc()
520
521    /**
522     * Fetch the entire result set of a query and return it as an
523     * associative array using the first column as the key.
524     *
525     * If the result set contains more than two columns, the value
526     * will be an array of the values from column 2-n.  If the result
527     * set contains only two columns, the returned value will be a
528     * scalar with the value of the second column (unless forced to an
529     * array with the $force_array parameter).  A MDB2 error code is
530     * returned on errors.  If the result set contains fewer than two
531     * columns, a MDB2_ERROR_TRUNCATED error is returned.
532     *
533     * For example, if the table 'mytable' contains:
534     * <pre>
535     *   ID      TEXT       DATE
536     * --------------------------------
537     *   1       'one'      944679408
538     *   2       'two'      944679408
539     *   3       'three'    944679408
540     * </pre>
541     * Then the call getAssoc('SELECT id,text FROM mytable') returns:
542     * <pre>
543     *    array(
544     *      '1' => 'one',
545     *      '2' => 'two',
546     *      '3' => 'three',
547     *    )
548     * </pre>
549     * ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
550     * <pre>
551     *    array(
552     *      '1' => array('one', '944679408'),
553     *      '2' => array('two', '944679408'),
554     *      '3' => array('three', '944679408')
555     *    )
556     * </pre>
557     *
558     * If the more than one row occurs with the same value in the
559     * first column, the last row overwrites all previous ones by
560     * default.  Use the $group parameter if you don't want to
561     * overwrite like this.  Example:
562     * <pre>
563     * getAssoc('SELECT category,id,name FROM mytable', null, null
564     *           MDB2_FETCHMODE_ASSOC, false, true) returns:
565     *    array(
566     *      '1' => array(array('id' => '4', 'name' => 'number four'),
567     *                   array('id' => '6', 'name' => 'number six')
568     *             ),
569     *      '9' => array(array('id' => '4', 'name' => 'number four'),
570     *                   array('id' => '6', 'name' => 'number six')
571     *             )
572     *    )
573     * </pre>
574     *
575     * Keep in mind that database functions in PHP usually return string
576     * values for results regardless of the database's internal type.
577     *
578     * @param string the SQL query
579     * @param array that contains the types of the columns in the result set
580     * @param array if supplied, prepare/execute will be used
581     *       with this array as execute parameters
582     * @param array that contains the types of the values defined in $params
583     * @param bool $force_array used only when the query returns
584     * exactly two columns.  If TRUE, the values of the returned array
585     * will be one-element arrays instead of scalars.
586     * @param bool $group if TRUE, the values of the returned array
587     *       is wrapped in another array.  If the same key value (in the first
588     *       column) repeats itself, the values will be appended to this array
589     *       instead of overwriting the existing values.
590     *
591     * @return array|MDB2_Error data on success, a MDB2 error on failure
592     * @access public
593     */
594    function getAssoc($query, $types = null, $params = array(), $param_types = null,
595        $fetchmode = MDB2_FETCHMODE_DEFAULT, $force_array = false, $group = false)
596    {
597        $db =& $this->getDBInstance();
598        if (PEAR::isError($db)) {
599            return $db;
600        }
601
602        settype($params, 'array');
603        if (empty($params)) {
604            return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group);
605        }
606
607        $stmt = $db->prepare($query, $param_types, $types);
608        if (PEAR::isError($stmt)) {
609            return $stmt;
610        }
611
612        $result = $stmt->execute($params);
613        if (!MDB2::isResultCommon($result)) {
614            return $result;
615        }
616
617        $all = $result->fetchAll($fetchmode, true, $force_array, $group);
618        $stmt->free();
619        $result->free();
620        return $all;
621    }
622    // }}}
623
624    // {{{ executeMultiple()
625
626    /**
627     * This function does several execute() calls on the same statement handle.
628     * $params must be an array indexed numerically from 0, one execute call is
629     * done for every 'row' in the array.
630     *
631     * If an error occurs during execute(), executeMultiple() does not execute
632     * the unfinished rows, but rather returns that error.
633     *
634     * @param resource query handle from prepare()
635     * @param array numeric array containing the data to insert into the query
636     *
637     * @return bool|MDB2_Error true on success, a MDB2 error on failure
638     * @access public
639     * @see prepare(), execute()
640     */
641    function executeMultiple(&$stmt, $params = null)
642    {
643        for ($i = 0, $j = count($params); $i < $j; $i++) {
644            $result = $stmt->execute($params[$i]);
645            if (PEAR::isError($result)) {
646                return $result;
647            }
648        }
649        return MDB2_OK;
650    }
651    // }}}
652
653    // {{{ getBeforeID()
654
655    /**
656     * Returns the next free id of a sequence if the RDBMS
657     * does not support auto increment
658     *
659     * @param string name of the table into which a new row was inserted
660     * @param string name of the field into which a new row was inserted
661     * @param bool when true the sequence is automatic created, if it not exists
662     * @param bool if the returned value should be quoted
663     *
664     * @return int|MDB2_Error id on success, a MDB2 error on failure
665     * @access public
666     */
667    function getBeforeID($table, $field = null, $ondemand = true, $quote = true)
668    {
669        $db =& $this->getDBInstance();
670        if (PEAR::isError($db)) {
671            return $db;
672        }
673
674        if ($db->supports('auto_increment') !== true) {
675            $seq = $table.(empty($field) ? '' : '_'.$field);
676            $id = $db->nextID($seq, $ondemand);
677            if (!$quote || PEAR::isError($id)) {
678                return $id;
679            }
680            return $db->quote($id, 'integer');
681        } elseif (!$quote) {
682            return null;
683        }
684        return 'NULL';
685    }
686    // }}}
687
688    // {{{ getAfterID()
689
690    /**
691     * Returns the autoincrement ID if supported or $id
692     *
693     * @param mixed value as returned by getBeforeId()
694     * @param string name of the table into which a new row was inserted
695     * @param string name of the field into which a new row was inserted
696     *
697     * @return int|MDB2_Error id on success, a MDB2 error on failure
698     * @access public
699     */
700    function getAfterID($id, $table, $field = null)
701    {
702        $db =& $this->getDBInstance();
703        if (PEAR::isError($db)) {
704            return $db;
705        }
706
707        if ($db->supports('auto_increment') !== true) {
708            return $id;
709        }
710        return $db->lastInsertID($table, $field);
711    }
712    // }}}
713}
714?>
Note: See TracBrowser for help on using the repository browser.