Source for file storage.php

Documentation is available at 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_PEAR_PATH.'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.13
  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(nullDB_ERROR_NOT_FOUNDnullnull,
  181.                                      $querynulltrue);
  182.         }
  183.         foreach ($row as $key => $value{
  184.             $this->_properties[$keytrue;
  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 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[$nametrue;
  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(nullDB_WARNING_READ_ONLYnull,
  368.                                      nullnullnulltrue);
  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[$property0;
  385.                 else {
  386.                     $this->_changes[$property]++;
  387.                 }
  388.             else {
  389.                 return $this->raiseError(nullDB_ERROR_INVALIDnull,
  390.                                          null"invalid field: $property",
  391.                                          nulltrue);
  392.             }
  393.             return true;
  394.         }
  395.         return $this->raiseError(nullDB_ERROR_NOSUCHFIELDnull,
  396.                                  null"unknown field: $property",
  397.                                  nulltrue);
  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(nullDB_WARNING_READ_ONLYnull,
  480.                                      nullnullnulltrue);
  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. ?>

Documentation generated on Wed, 09 Feb 2011 09:04:47 +0700 by phpDocumentor 1.4.2