DB
[ class tree: DB ] [ index: DB ] [ all elements ]

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

Documentation generated on Tue, 20 Mar 2007 05:31:03 -0500 by phpDocumentor 1.3.0. PEAR Logo Copyright © PHP Group 2004.