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

Source for file Table.php

Documentation is available at Table.php

  1. <?php
  2.  
  3. /**
  4. * Error code at instantiation time when the first parameter to the
  5. * constructor is not a PEAR DB object.
  6. */
  7. define('DB_TABLE_ERR_NOT_DB_OBJECT',    -1);
  8.  
  9. /**
  10. * Error code at instantiation time when the PEAR DB $phptype is not
  11. * supported by DB_Table.
  12. */
  13. define('DB_TABLE_ERR_PHPTYPE',          -2);
  14.  
  15. /**
  16. * Error code when you call select() or selectResult() and the first
  17. * parameter does not match any of the $this->sql keys.
  18. */
  19. define('DB_TABLE_ERR_SQL_UNDEF',        -3);
  20.  
  21. /**
  22. * Error code when you try to insert data to a column that is not in the
  23. * $this->col array.
  24. */
  25. define('DB_TABLE_ERR_INS_COL_NOMAP',    -4);
  26.  
  27. /**
  28. * Error code when you try to insert data, and that data does not have a
  29. * column marked as 'require' in the $this->col array.
  30. */
  31. define('DB_TABLE_ERR_INS_COL_REQUIRED'-5);
  32.  
  33. /**
  34. * Error code when auto-validation fails on data to be inserted.
  35. */
  36. define('DB_TABLE_ERR_INS_DATA_INVALID'-6);
  37.  
  38. /**
  39. * Error code when you try to update data to a column that is not in the
  40. * $this->col array.
  41. */
  42. define('DB_TABLE_ERR_UPD_COL_NOMAP',    -7);
  43.  
  44. /**
  45. * Error code when you try to update data, and that data does not have a
  46. * column marked as 'require' in the $this->col array.
  47. */
  48. define('DB_TABLE_ERR_UPD_COL_REQUIRED'-8);
  49.  
  50. /**
  51. * Error code when auto-validation fails on update data.
  52. */
  53. define('DB_TABLE_ERR_UPD_DATA_INVALID'-9);
  54.  
  55. /**
  56. * Error code when you use a create() flag that is not recognized (must
  57. * be 'safe', 'drop', or boolean false.
  58. */
  59. define('DB_TABLE_ERR_CREATE_FLAG',      -10);
  60.  
  61. /**
  62. * Error code at create() time when you define an index in $this->idx
  63. * that has no columns.
  64. */
  65. define('DB_TABLE_ERR_IDX_NO_COLS',      -11);
  66.  
  67. /**
  68. * Error code at create() time when you define an index in $this->idx
  69. * that refers to a column that does not exist in the $this->col array.
  70. */
  71. define('DB_TABLE_ERR_IDX_COL_UNDEF',    -12);
  72.  
  73. /**
  74. * Error code at create() time when you define a $this->idx index type
  75. * that is not recognized (must be 'normal' or 'unique').
  76. */
  77. define('DB_TABLE_ERR_IDX_TYPE',         -13);
  78.  
  79. /**
  80. * Error code at create() time when you have an error in a 'char' or
  81. * 'varchar' definition in $this->col (usually because 'size' is wrong).
  82. */
  83. define('DB_TABLE_ERR_DECLARE_STRING',   -14);
  84.  
  85. /**
  86. * Error code at create() time when you have an error in a 'decimal'
  87. * definition (usually becuase the 'size' or 'scope' are wrong).
  88. */
  89. define('DB_TABLE_ERR_DECLARE_DECIMAL',  -15);
  90.  
  91. /**
  92. * Error code at create() time when you define a column in $this->col
  93. * with an unrecognized 'type'.
  94. */
  95. define('DB_TABLE_ERR_DECLARE_TYPE',     -16);
  96.  
  97. /**
  98. * Error code at validation time when a column in $this->col has an
  99. * unrecognized 'type'.
  100. */
  101. define('DB_TABLE_ERR_VALIDATE_TYPE',    -17);
  102.  
  103. /**
  104. * Error code at create() time when you define a column in $this->col
  105. * with an invalid column name (usually because it's a reserved keyword).
  106. */
  107. define('DB_TABLE_ERR_DECLARE_COLNAME',  -18);
  108.  
  109. /**
  110. * Error code at create() time when you define an index in $this->idx
  111. * with an invalid index name (usually because it's a reserved keyword).
  112. */
  113. define('DB_TABLE_ERR_DECLARE_IDXNAME',  -19);
  114.  
  115. /**
  116. * Error code at create() time when you define an index in $this->idx
  117. * that refers to a CLOB column.
  118. */
  119. define('DB_TABLE_ERR_IDX_COL_CLOB',     -20);
  120.  
  121. /**
  122. * Error code at create() time when you define a column name that is
  123. * more than 30 chars long (an Oracle restriction).
  124. */
  125. define('DB_TABLE_ERR_DECLARE_STRLEN',   -21);
  126.  
  127. /**
  128. * Error code at create() time when the index name ends up being more
  129. * than 30 chars long (an Oracle restriction).
  130. */
  131. define('DB_TABLE_ERR_IDX_STRLEN',       -22);
  132.  
  133. /**
  134. * Error code at create() time when the table name is more than 30 chars
  135. * long (an Oracle restriction).
  136. */
  137. define('DB_TABLE_ERR_TABLE_STRLEN',     -23);
  138.  
  139. /**
  140. * Error code at nextID() time when the sequence name is more than 30
  141. * chars long (an Oracle restriction).
  142. */
  143. define('DB_TABLE_ERR_SEQ_STRLEN',       -24);
  144.  
  145.  
  146. /**
  147. * The PEAR class for errors
  148. */
  149. require_once 'PEAR.php';
  150.  
  151. /**
  152. * The Date class for recasting date and time values
  153. */
  154. require_once 'Date.php';
  155.  
  156.  
  157. /**
  158. * DB_Table supports these RDBMS engines and their various native data
  159. * types; we need these here instead of in Manager.php becuase the
  160. * initial array key tells us what databases are supported.
  161. */
  162. $GLOBALS['_DB_TABLE']['type'= array(
  163.     'fbsql' => array(
  164.         'boolean'   => 'DECIMAL(1,0)',
  165.         'char'      => 'CHAR',
  166.         'varchar'   => 'VARCHAR',
  167.         'smallint'  => 'SMALLINT',
  168.         'integer'   => 'INTEGER',
  169.         'bigint'    => 'LONGINT',
  170.         'decimal'   => 'DECIMAL',
  171.         'single'    => 'REAL',
  172.         'double'    => 'DOUBLE PRECISION',
  173.         'clob'      => 'CLOB',
  174.         'date'      => 'CHAR(10)',
  175.         'time'      => 'CHAR(8)',
  176.         'timestamp' => 'CHAR(19)'
  177.     ),
  178.     'mssql' => array(
  179.         'boolean'   => 'DECIMAL(1,0)',
  180.         'char'      => 'CHAR',
  181.         'varchar'   => 'VARCHAR',
  182.         'smallint'  => 'SMALLINT',
  183.         'integer'   => 'INTEGER',
  184.         'bigint'    => 'BIGINT',
  185.         'decimal'   => 'DECIMAL',
  186.         'single'    => 'REAL',
  187.         'double'    => 'FLOAT',
  188.         'clob'      => 'TEXT',
  189.         'date'      => 'CHAR(10)',
  190.         'time'      => 'CHAR(8)',
  191.         'timestamp' => 'CHAR(19)'
  192.     ),
  193.     'mysql' => array(
  194.         'boolean'   => 'DECIMAL(1,0)',
  195.         'char'      => 'CHAR',
  196.         'varchar'   => 'VARCHAR',
  197.         'smallint'  => 'SMALLINT',
  198.         'integer'   => 'INTEGER',
  199.         'bigint'    => 'BIGINT',
  200.         'decimal'   => 'DECIMAL',
  201.         'single'    => 'FLOAT',
  202.         'double'    => 'DOUBLE',
  203.         'clob'      => 'LONGTEXT',
  204.         'date'      => 'CHAR(10)',
  205.         'time'      => 'CHAR(8)',
  206.         'timestamp' => 'CHAR(19)'
  207.     ),
  208.     'oci8' => array(
  209.         'boolean'   => 'NUMBER(1)',
  210.         'char'      => 'CHAR',
  211.         'varchar'   => 'VARCHAR2',
  212.         'smallint'  => 'NUMBER(6)',
  213.         'integer'   => 'NUMBER(11)',
  214.         'bigint'    => 'NUMBER(19)',
  215.         'decimal'   => 'NUMBER',
  216.         'single'    => 'REAL',
  217.         'double'    => 'DOUBLE PRECISION',
  218.         'clob'      => 'CLOB',
  219.         'date'      => 'CHAR(10)',
  220.         'time'      => 'CHAR(8)',
  221.         'timestamp' => 'CHAR(19)'
  222.     ),
  223.     'pgsql' => array(
  224.         'boolean'   => 'DECIMAL(1,0)',
  225.         'char'      => 'CHAR',
  226.         'varchar'   => 'VARCHAR',
  227.         'smallint'  => 'SMALLINT',
  228.         'integer'   => 'INTEGER',
  229.         'bigint'    => 'BIGINT',
  230.         'decimal'   => 'DECIMAL',
  231.         'single'    => 'REAL',
  232.         'double'    => 'DOUBLE PRECISION',
  233.         'clob'      => 'TEXT',
  234.         'date'      => 'CHAR(10)',
  235.         'time'      => 'CHAR(8)',
  236.         'timestamp' => 'CHAR(19)'
  237.     ),
  238.     'sqlite' => array(
  239.         'boolean'   => 'BOOLEAN',
  240.         'char'      => 'CHAR',
  241.         'varchar'   => 'VARCHAR',
  242.         'smallint'  => 'SMALLINT',
  243.         'integer'   => 'INTEGER',
  244.         'bigint'    => 'BIGINT',
  245.         'decimal'   => 'NUMERIC',
  246.         'single'    => 'FLOAT',
  247.         'double'    => 'DOUBLE',
  248.         'clob'      => 'CLOB',
  249.         'date'      => 'DATE',
  250.         'time'      => 'TIME',
  251.         'timestamp' => 'TIMESTAMP'
  252.     )
  253. );
  254.  
  255.  
  256. /**
  257. * US-English error messages.  DB_Table has no other embedded strings, so
  258. * if you want to internationalize, you can modify these for your
  259. * language; just set them before or after including DB_Table.
  260. */
  261. if (isset($GLOBALS['_DB_TABLE']['error'])) {
  262.     $GLOBALS['_DB_TABLE']['error'= array(
  263.         DB_TABLE_ERR_NOT_DB_OBJECT       => 'First parameter must be a DB object',
  264.         DB_TABLE_ERR_PHPTYPE             => 'DB phptype not supported',
  265.         DB_TABLE_ERR_SQL_UNDEF           => 'Select key not in map',
  266.         DB_TABLE_ERR_INS_COL_NOMAP       => 'Insert column not in map',
  267.         DB_TABLE_ERR_INS_COL_REQUIRED    => 'Insert data must be set and non-null for column',
  268.         DB_TABLE_ERR_INS_DATA_INVALID    => 'Insert data not valid for column',
  269.         DB_TABLE_ERR_UPD_COL_NOMAP       => 'Update column not in map',
  270.         DB_TABLE_ERR_UPD_COL_REQUIRED    => 'Update column must be set and non-null',
  271.         DB_TABLE_ERR_UPD_DATA_INVALID    => 'Update data not valid for column',
  272.         DB_TABLE_ERR_CREATE_FLAG         => 'Create flag not valid',
  273.         DB_TABLE_ERR_IDX_NO_COLS         => 'No columns for index',
  274.         DB_TABLE_ERR_IDX_COL_UNDEF       => 'Column not in map for index',
  275.         DB_TABLE_ERR_IDX_TYPE            => 'Type not valid for index',
  276.         DB_TABLE_ERR_DECLARE_STRING      => 'String column declaration not valid',
  277.         DB_TABLE_ERR_DECLARE_DECIMAL     => 'Decimal column declaration not valid',
  278.         DB_TABLE_ERR_DECLARE_TYPE        => 'Column type not valid',
  279.         DB_TABLE_ERR_VALIDATE_TYPE       => 'Cannot validate for unknown type on column',
  280.         DB_TABLE_ERR_DECLARE_COLNAME     => 'Column name not valid',
  281.         DB_TABLE_ERR_DECLARE_IDXNAME     => 'Index name not valid',
  282.         DB_TABLE_ERR_DECLARE_TYPE        => 'Column type not valid',
  283.         DB_TABLE_ERR_IDX_COL_CLOB        => 'CLOB column not allowed for index',
  284.         DB_TABLE_ERR_DECLARE_STRLEN      => 'Column name too long, 30 char max',
  285.         DB_TABLE_ERR_IDX_STRLEN          => 'Index name too long, 30 char max',
  286.         DB_TABLE_ERR_TABLE_STRLEN        => 'Table name too long, 30 char max',
  287.         DB_TABLE_ERR_SEQ_STRLEN          => 'Sequence name too long, 30 char max'
  288.     );
  289. }
  290.  
  291.  
  292. /**
  293. * DB_Table is a database API and data type SQL abstraction class.
  294. * DB_Table provides database API abstraction, data type abstraction,
  295. * automated SELECT, INSERT, and UPDATE queries, automated table
  296. * creation, automated validation of inserted/updated column values,
  297. * and automated creation of QuickForm elemnts based on the column
  298. * definitions.
  299. * $Id: Table.php,v 1.24 2004/12/23 17:59:13 pmjones Exp $
  300. *
  301. @author Paul M. Jones <pmjones@ciaweb.net>
  302. @version 0.22 beta
  303. *
  304. @package DB_Table
  305. */
  306.  
  307. class DB_Table {
  308.     
  309.     
  310.     /**
  311.     * 
  312.     * The PEAR DB object that connects to the database.
  313.     * 
  314.     * @access public
  315.     * 
  316.     * @var object 
  317.     * 
  318.     */
  319.     
  320.     var $db = null;
  321.     
  322.     
  323.     /**
  324.     * 
  325.     * The table or view in the database to which this object binds.
  326.     * 
  327.     * @access public
  328.     * 
  329.     * @var string 
  330.     * 
  331.     */
  332.     
  333.     var $table = null;
  334.     
  335.     
  336.     /**
  337.     * 
  338.     * Associative array of column definitions.
  339.     * 
  340.     * @access public
  341.     * 
  342.     * @var array 
  343.     * 
  344.     */
  345.     
  346.     var $col = array();
  347.     
  348.     
  349.     /**
  350.     * 
  351.     * Associative array of index definitions.
  352.     * 
  353.     * @access public
  354.     * 
  355.     * @var array 
  356.     * 
  357.     */
  358.     
  359.     var $idx = array();
  360.     
  361.     
  362.     /**
  363.     * 
  364.     * Baseline SELECT maps for select(), selectResult(), selectCount().
  365.     * 
  366.     * @access public
  367.     * 
  368.     * @var array 
  369.     * 
  370.     */
  371.     
  372.     var $sql = array();
  373.     
  374.     
  375.     /**
  376.     * 
  377.     * Whether or not to automatically validate data at insert-time.
  378.     * 
  379.     * @access private
  380.     * 
  381.     * @var bool 
  382.     * 
  383.     */
  384.     
  385.     var $_valid_insert = true;
  386.     
  387.     
  388.     /**
  389.     * 
  390.     * Whether or not to automatically validate data at update-time.
  391.     * 
  392.     * @access private
  393.     * 
  394.     * @var bool 
  395.     * 
  396.     */
  397.     
  398.     var $_valid_update = true;
  399.     
  400.     
  401.     /**
  402.     * 
  403.     * When calling select() and selectResult(), use this fetch mode (usually
  404.     * a DB_FETCHMODE_* constant).  If null, uses whatever is set in the $db
  405.     * PEAR DB object.
  406.     * 
  407.     * @access public
  408.     * 
  409.     * @var int 
  410.     * 
  411.     */
  412.     
  413.     var $fetchmode = null;
  414.     
  415.     
  416.     /**
  417.     * 
  418.     * When fetchmode is DB_FETCHMODE_OBJECT, use this class for each
  419.     * returned row.  If null, uses whatever is set in the $db
  420.     * PEAR DB object.
  421.     * 
  422.     * @access public
  423.     * 
  424.     * @var string 
  425.     * 
  426.     */
  427.     
  428.     var $fetchmode_object_class = null;
  429.     
  430.     
  431.     /**
  432.     * 
  433.     * If there is an error on instantiation, this captures that error.
  434.     *
  435.     * This property is used only for errors encountered in the constructor
  436.     * at instantiation time.  To check if there was an instantiation error...
  437.     *
  438.     * <code>
  439.     * $obj =& new DB_Table();
  440.     * if ($obj->error) {
  441.     *     // ... error handling code here ...
  442.     * }
  443.     * </code>
  444.     * 
  445.     * @var object PEAR_Error 
  446.     * 
  447.     */
  448.     
  449.     var $error = null;
  450.     
  451.     
  452.     /**
  453.     * 
  454.     * Whether or not to automatically recast data at insert- and update-time.
  455.     * 
  456.     * @access private
  457.     * 
  458.     * @var bool 
  459.     * 
  460.     */
  461.     
  462.     var $_auto_recast = true;
  463.     
  464.     
  465.     /**
  466.     * 
  467.     * Specialized version of throwError() modeled on PEAR_Error.
  468.     * 
  469.     * Throws a PEAR_Error with a DB_Table error message based on a
  470.     * DB_Table constant error code.
  471.     * 
  472.     * @static
  473.     * 
  474.     * @access public
  475.     * 
  476.     * @param string $code A DB_Table error code constant.
  477.     * 
  478.     * @param string $extra Extra text for the error (in addition to the
  479.     *  regular error message).
  480.     * 
  481.     * @return object PEAR_Error 
  482.     * 
  483.     */
  484.     
  485.     function &throwError($code$extra = null)
  486.     {
  487.         // get the error message text based on the error code
  488.         $text $GLOBALS['_DB_TABLE']['error'][$code];
  489.         
  490.         // add any additional error text
  491.         if ($extra{
  492.             $text .= ' ' $extra;
  493.         }
  494.         
  495.         // done!
  496.         return PEAR::throwError($text$code);
  497.     }
  498.     
  499.     
  500.     /**
  501.     * 
  502.     * Constructor.
  503.     * 
  504.     * If there is an error on instantiation, $this->error will be
  505.     * populated with the PEAR_Error.
  506.     * 
  507.     * @access public
  508.     * 
  509.     * @param object &$db A PEAR DB object.
  510.     * 
  511.     * @param string $table The table name to connect to in the database.
  512.     * 
  513.     * @param mixed $create The automatic table creation mode to pursue:
  514.     *  boolean false to not attempt creation, 'safe' to
  515.     *  create the table only if it does not exist, or
  516.     *  'drop' to drop any existing table with the same name
  517.     *  and re-create it.
  518.     * 
  519.     * @return object DB_Table 
  520.     * 
  521.     */
  522.     
  523.     function DB_Table(&$db$table$create = false)
  524.     {
  525.         // is the first argument a DB object?
  526.         if (is_subclass_of($db'db_common')) {
  527.             $this->error =DB_Table::throwError(DB_TABLE_ERR_NOT_DB_OBJECT);
  528.             return;
  529.         }
  530.         
  531.         // is the RDBMS supported?
  532.         if (DB_Table::supported($db->phptype)) {
  533.             $this->error =DB_Table::throwError(
  534.                 DB_TABLE_ERR_PHPTYPE,
  535.                 "({$db->phptype})"
  536.             );
  537.             return;
  538.         }
  539.         
  540.         // set the class properties
  541.         $this->db =$db;
  542.         $this->table = $table;
  543.         
  544.         // should we attempt table creation?
  545.         if ($create{
  546.             // yes, attempt to create the table with the appropriate
  547.             // flag.
  548.             $result $this->create($create);
  549.             if (PEAR::isError($result)) {
  550.                 // problem creating the table
  551.                 $this->error =$result;
  552.                 return;
  553.             }
  554.         }
  555.     }
  556.     
  557.     
  558.     /**
  559.     * 
  560.     * Is a particular RDBMS supported by DB_Table?
  561.     * 
  562.     * @static
  563.     * 
  564.     * @access public
  565.     * 
  566.     * @param string $phptype The RDBMS type for PHP.
  567.     * 
  568.     * @return bool True if supported, false if not.
  569.     * 
  570.     */
  571.     
  572.     function supported($phptype)
  573.     {
  574.         $supported array_keys($GLOBALS['_DB_TABLE']['type']);
  575.         return in_array(strtolower($phptype)$supported);
  576.     }
  577.     
  578.     
  579.     
  580.     /**
  581.     * 
  582.     * Returns all or part of the $this->col property array.
  583.     * 
  584.     * @access public
  585.     * 
  586.     * @param mixed $col If null, returns the $this->col property array
  587.     *  as it is.  If string, returns that column name from the $this->col
  588.     *  array. If an array, returns those columns named as the array
  589.     *  values from the $this->col array as an array.
  590.     *
  591.     * @return mixed All or part of the $this->col property array, or
  592.     *  boolean false if no matching column names are found.
  593.     * 
  594.     */
  595.     
  596.     function getColumns($col = null)
  597.     {
  598.         // by default, return all column definitions
  599.         if (is_null($col)) {
  600.             return $this->col;
  601.         }
  602.         
  603.         // if the param is a string, only return the column definition
  604.         // named by the that string
  605.         if (is_string($col)) {
  606.             if (isset($this->col[$col])) {
  607.                 return $this->col[$col];
  608.             else {
  609.                 return false;
  610.             }
  611.         }
  612.         
  613.         // if the param is a sequential array of column names,
  614.         // return only those columns named in that array
  615.         if (is_array($col)) {
  616.             $set = array();
  617.             foreach ($col as $name{
  618.                 $set[$name$this->getColumns($name);
  619.             }
  620.             
  621.             if (count($set== 0{
  622.                 return false;
  623.             else {
  624.                 return $set;
  625.             }
  626.         }
  627.         
  628.         // param was not null, string, or array
  629.         return false;
  630.     }
  631.     
  632.     
  633.     /**
  634.     * 
  635.     * Returns all or part of the $this->idx property array.
  636.     * 
  637.     * @access public
  638.     * 
  639.     * @param string $col If specified, returns only this index key
  640.     *  from the $this->col property array.
  641.     * 
  642.     * @return array All or part of the $this->idx property array.
  643.     * 
  644.     */
  645.     
  646.     function getIndexes($idx = null)
  647.     {
  648.         // by default, return all index definitions
  649.         if (is_null($idx)) {
  650.             return $this->idx;
  651.         }
  652.         
  653.         // if the param is a string, only return the index definition
  654.         // named by the that string
  655.         if (is_string($idx)) {
  656.             if (isset($this->idx[$idx])) {
  657.                 return $this->idx[$idx];
  658.             else {
  659.                 return false;
  660.             }
  661.         }
  662.         
  663.         // if the param is a sequential array of index names,
  664.         // return only those indexes named in that array
  665.         if (is_array($idx)) {
  666.             $set = array();
  667.             foreach ($idx as $name{
  668.                 $set[$name$this->getIndexes($name);
  669.             }
  670.             
  671.             if (count($set== 0{
  672.                 return false;
  673.             else {
  674.                 return $set;
  675.             }
  676.         }
  677.         
  678.         // param was not null, string, or array
  679.         return false;
  680.     }
  681.     
  682.     
  683.     /**
  684.     *
  685.     * Selects rows from the table using one of the 'DB::get*()' methods.
  686.     * 
  687.     * @access public
  688.     * 
  689.     * @param string $sqlkey The name of the SQL SELECT to use from the
  690.     *  $this->sql property array.
  691.     * 
  692.     * @param string $filter Ad-hoc SQL snippet to AND with the default
  693.     *  SELECT WHERE clause.
  694.     * 
  695.     * @param string $order Ad-hoc SQL snippet to override the default
  696.     *  SELECT ORDER BY clause.
  697.     * 
  698.     * @param int $start The row number to start listing from in the
  699.     *  result set.
  700.     * 
  701.     * @param int $count The number of rows to list in the result set.
  702.     * 
  703.     * @return mixed An array of records from the table (if anything but
  704.     *  'getOne'), a single value (if 'getOne'), or a PEAR_Error object.
  705.     *
  706.     * @see DB::getAll()
  707.     *
  708.     * @see DB::getAssoc()
  709.     *
  710.     * @see DB::getCol()
  711.     *
  712.     * @see DB::getOne()
  713.     *
  714.     * @see DB::getRow()
  715.     *
  716.     * @see DB_Table::_swapModes()
  717.     *
  718.     */
  719.     
  720.     function select($sqlkey$filter = null$order = null,
  721.         $start = null$count = null)
  722.     {
  723.         // build the base command
  724.         $sql $this->buildSQL($sqlkey$filter$order$start$count);
  725.         
  726.         // set the get*() method name
  727.         if (isset($this->sql[$sqlkey]['get'])) {
  728.             $method ucwords(strtolower(trim($this->sql[$sqlkey]['get'])));
  729.             $method = "get$method";
  730.         else {
  731.             $method 'getAll';
  732.         }
  733.         
  734.         // DB_Table assumes you are using a shared PEAR DB object.  Other
  735.         // scripts using the same object probably expect its fetchmode
  736.         // not to change, unless they change it themselves.  Thus, to
  737.         // provide friendly mode-swapping, we will restore these modes
  738.         // afterwards.
  739.         $restore_mode $this->db->fetchmode;
  740.         $restore_class $this->db->fetchmode_object_class;
  741.         
  742.         // swap modes
  743.         $fetchmode $this->fetchmode;
  744.         $fetchmode_object_class $this->fetchmode_object_class;
  745.         if (isset($this->sql[$sqlkey]['fetchmode'])) {
  746.             $fetchmode $this->sql[$sqlkey]['fetchmode'];
  747.         }
  748.         if (isset($this->sql[$sqlkey]['fetchmode_object_class'])) {
  749.             $fetchmode_object_class $this->sql[$sqlkey]['fetchmode_object_class'];
  750.         }
  751.         $this->_swapModes($fetchmode$fetchmode_object_class);
  752.         
  753.         // get the result
  754.         $result $this->db->$method($sql);
  755.             
  756.         // swap modes back
  757.         $this->_swapModes($restore_mode$restore_class);
  758.         
  759.         // return the result
  760.         return $result;
  761.     }
  762.     
  763.     
  764.     /**
  765.     *
  766.     * Selects rows from the table as a DB_Result object.
  767.     * 
  768.     * @access public
  769.     * 
  770.     * @param string $sqlkey The name of the SQL SELECT to use from the
  771.     *  $this->sql property array.
  772.     * 
  773.     * @param string $filter Ad-hoc SQL snippet to add to the default
  774.     *  SELECT WHERE clause.
  775.     * 
  776.     * @param string $order Ad-hoc SQL snippet to override the default
  777.     *  SELECT ORDER BY clause.
  778.     * 
  779.     * @param int $start The record number to start listing from in the
  780.     *  result set.
  781.     * 
  782.     * @param int $count The number of records to list in the result set.
  783.     * 
  784.     * @return mixed A PEAR_Error on failure, or a DB_Result object on
  785.     *  success.
  786.     *
  787.     * @see DB_Table::_swapModes()
  788.     *
  789.     */
  790.     
  791.     function selectResult($sqlkey$filter = null$order = null
  792.         $start = null$count = null)
  793.     {
  794.         // build the base command
  795.         $sql $this->buildSQL($sqlkey$filter$order$start$count);
  796.         
  797.         // DB_Table assumes you are using a shared PEAR DB object.  Other
  798.         // scripts using the same object probably expect its fetchmode
  799.         // not to change, unless they change it themselves.  Thus, to
  800.         // provide friendly mode-swapping, we will restore these modes
  801.         // afterwards.
  802.         $restore_mode $this->db->fetchmode;
  803.         $restore_class $this->db->fetchmode_object_class;
  804.         
  805.         // swap modes
  806.         $fetchmode $this->fetchmode;
  807.         $fetchmode_object_class $this->fetchmode_object_class;
  808.         if (isset($this->sql[$sqlkey]['fetchmode'])) {
  809.             $fetchmode $this->sql[$sqlkey]['fetchmode'];
  810.         }
  811.         if (isset($this->sql[$sqlkey]['fetchmode_object_class'])) {
  812.             $fetchmode_object_class $this->sql[$sqlkey]['fetchmode_object_class'];
  813.         }
  814.         $this->_swapModes($fetchmode$fetchmode_object_class);
  815.         
  816.         // get the result
  817.         $result =$this->db->query($sql);
  818.         
  819.         // swap modes back
  820.         $this->_swapModes($restore_mode$restore_class);
  821.         
  822.         // return the result
  823.         return $result;
  824.     }
  825.     
  826.     
  827.     /**
  828.     *
  829.     * Counts the number of rows which will be returned by a query.
  830.     *
  831.     * This function works identically to {@link select()}, but it
  832.     * returns the number of rows returned by a query instead of the
  833.     * query results themselves.
  834.     *
  835.     * This makes using DB_Table with Pager easier, since you can pass the
  836.     * return value of this to Pager as totalItems, then select only the
  837.     * rows you need to display on a page.
  838.     *
  839.     * @author Ian Eure <ian@php.net>
  840.     * 
  841.     * @access public
  842.     * 
  843.     * @param string $sqlkey The name of the SQL SELECT to use from the
  844.     *  $this->sql property array.
  845.     * 
  846.     * @param string $filter Ad-hoc SQL snippet to AND with the default
  847.     *  SELECT WHERE clause.
  848.     * 
  849.     * @param string $order Ad-hoc SQL snippet to override the default
  850.     *  SELECT ORDER BY clause.
  851.     * 
  852.     * @param int $start The row number to start listing from in the
  853.     *  result set.
  854.     * 
  855.     * @param int $count The number of rows to list in the result set.
  856.     * 
  857.     * @return mixed An integer number of records from the table, or a
  858.     *  PEAR_Error object.
  859.     *
  860.     * @see DB_Table::select()
  861.     *
  862.     */
  863.     
  864.     function selectCount($sqlkey$filter = null$order = null,
  865.         $start = null$count = null)
  866.     {
  867.         // does the SQL SELECT key exist?
  868.         $tmp array_keys($this->sql);
  869.         if (in_array($sqlkey$tmp)) {
  870.             return $this->throwError(
  871.                 DB_TABLE_ERR_SQL_UNDEF,
  872.                 "('$sqlkey')"
  873.             );
  874.         }
  875.         
  876.         // create a SQL key name for this count-query
  877.         $count_key '__count_' $sqlkey;
  878.         
  879.         // has a count-query for the SQL key already been created?
  880.         if (isset($this->sql[$count_key])) {
  881.             
  882.             // we've not asked for a count on this query yet.
  883.             // get the elements of the query ...
  884.             $count_sql $this->sql[$sqlkey];
  885.             
  886.             // is a count-field set for the query?
  887.             if (isset($count_sql['count']||
  888.                 trim($count_sql['count']== ''{
  889.                 $count_sql['count''*';
  890.             }
  891.             
  892.             // replace the SELECT fields with a COUNT() command
  893.             $count_sql['select'= "COUNT({$count_sql['count']})";
  894.             
  895.             // replace the 'get' key so we only get the one result item
  896.             $count_sql['get''one';
  897.             
  898.             // create the new count-query in the $sql array
  899.             $this->sql[$count_key$count_sql;
  900.         }
  901.         
  902.         // retrieve the count results
  903.         return $this->select($count_key$filter$order$start$count);
  904.     }
  905.     
  906.     
  907.     /**
  908.     * 
  909.     * Changes the $this->db PEAR DB object fetchmode and
  910.     * fetchmode_object_class.
  911.     * 
  912.     * Becase DB_Table objects tend to use the same PEAR DB object, it
  913.     * may sometimes be useful to have one object return results in one
  914.     * mode, and have another object return results in a different mode.
  915.     * This method allows us to switch DB fetch modes on the fly.
  916.     * 
  917.     * @access private
  918.     * 
  919.     * @param string $new_mode A DB_FETCHMODE_* constant.  If null,
  920.     *  defaults to whatever the DB object is currently using.
  921.     * 
  922.     * @param string $new_class The object class to use for results when
  923.     *  the $db object is in DB_FETCHMODE_OBJECT fetch mode.  If null,
  924.     *  defaults to whatever the the DB object is currently using.
  925.     * 
  926.     * @return void 
  927.     * 
  928.     */
  929.     
  930.     function _swapModes($new_mode$new_class)
  931.     {
  932.         // get the old (current) mode and class
  933.         $old_mode $this->db->fetchmode;
  934.         $old_class $this->db->fetchmode_object_class;
  935.         
  936.         // don't need to swap anything if the new modes are both
  937.         // null or if the old and new modes already match.
  938.         if ((is_null($new_mode&& is_null($new_class)) ||
  939.             ($old_mode == $new_mode && $old_class == $new_class)) {
  940.             return;
  941.         }
  942.         
  943.         // set the default new mode
  944.         if (is_null($new_mode)) {
  945.             $new_mode $old_mode;
  946.         }
  947.         
  948.         // set the default new class
  949.         if (is_null($new_class)) {
  950.             $new_class $old_class;
  951.         }
  952.         
  953.         // swap modes
  954.         $this->db->setFetchMode($new_mode$new_class);
  955.     }
  956.     
  957.     
  958.     /**
  959.     * 
  960.     * Builds the SQL command from a specified $this->sql element.
  961.     * 
  962.     * @access public
  963.     * 
  964.     * @param string $sqlkey The $this->sql key to use as the basis for the
  965.     *  SQL query string.
  966.     * 
  967.     * @param string $filter A filter to add to the WHERE clause of the
  968.     *  defined SELECT in $this->sql.
  969.     * 
  970.     * @param string $order An ORDER clause to override the defined order
  971.     *  in $this->sql.
  972.     * 
  973.     * @param int $start The row number to start listing from in the
  974.     *  result set.
  975.     * 
  976.     * @param int $count The number of rows to list in the result set.
  977.     * 
  978.     * @return mixed A PEAR_Error on failure, or an SQL command string on
  979.     *  success.
  980.     * 
  981.     */
  982.     
  983.     function buildSQL($sqlkey$filter = null$order = null,
  984.         $start = null$count = null)
  985.     {
  986.         // does the SQL SELECT key exist?
  987.         $tmp array_keys($this->sql);
  988.         if (in_array($sqlkey$tmp)) {
  989.             return $this->throwError(
  990.                 DB_TABLE_ERR_SQL_UNDEF,
  991.                 "('$sqlkey')"
  992.             );
  993.         }
  994.         
  995.         // the SQL clause parts and their default values
  996.         $part = array(
  997.             'select' => '*',
  998.             'from'   => $this->table,
  999.             'join'   => null,
  1000.             'where'  => null,
  1001.             'group'  => null,
  1002.             'having' => null,
  1003.             'order'  => null
  1004.         );
  1005.         
  1006.         // loop through each possible clause
  1007.         foreach ($part as $key => $val{
  1008.             if (isset($this->sql[$sqlkey][$key])) {
  1009.                 continue;
  1010.             else {
  1011.                 $part[$key$this->sql[$sqlkey][$key];
  1012.             }
  1013.         }
  1014.         
  1015.         // add the filter to the WHERE part
  1016.         if ($filter{
  1017.             if ($part['where']{
  1018.                 $part['where'.= $filter;
  1019.             else {
  1020.                 $part['where'.= " AND ($filter)";
  1021.             }
  1022.         }
  1023.         
  1024.         // override the ORDER part
  1025.         if ($order{
  1026.             $part['order'$order;
  1027.         }
  1028.         
  1029.         // build up the command string form the parts
  1030.         $cmd '';
  1031.         foreach ($part as $key => $val{
  1032.             
  1033.             // if the part value has not been set, skip it
  1034.             if ($val{
  1035.                 continue;
  1036.             }
  1037.             
  1038.             switch ($key{
  1039.             
  1040.             case 'join':
  1041.                 $cmd .= " $val\n";
  1042.                 break;
  1043.                 
  1044.             case 'group':
  1045.             case 'order':
  1046.                 $cmd .= strtoupper($key. " BY $val\n";
  1047.                 break;
  1048.                 
  1049.             default:
  1050.                 $cmd .= strtoupper($key. " $val\n";
  1051.                 break;
  1052.             
  1053.             }
  1054.         }
  1055.         
  1056.         // add LIMIT if requested
  1057.         if (is_null($start&& is_null($count)) {
  1058.             $cmd $this->db->modifyLimitQuery(
  1059.                 $cmd$start$count);
  1060.         }
  1061.         
  1062.         return $cmd;
  1063.     }
  1064.     
  1065.     
  1066.     /**
  1067.     *
  1068.     * Inserts a single table row after validating through validInsert().
  1069.     * 
  1070.     * @access public
  1071.     * 
  1072.     * @param array $data An associative array of key-value pairs where
  1073.     *  the key is the column name and the value is the column value.  This
  1074.     *  is the data that will be inserted into the table.  Data is checked
  1075.     *  against the column data type for validity.
  1076.     * 
  1077.     * @return mixed Void on success, a PEAR_Error object on failure.
  1078.     *
  1079.     * @see validInsert()
  1080.     * 
  1081.     * @see DB::autoExecute()
  1082.     * 
  1083.     */
  1084.         
  1085.     function insert($data)
  1086.     {
  1087.         // forcibly recast the data elements to their proper types?
  1088.         if ($this->_auto_recast{
  1089.             $this->recast($data);
  1090.         }
  1091.         
  1092.         // validate the data if auto-validation is turned on
  1093.         if ($this->_valid_insert{
  1094.             $result $this->validInsert($data);
  1095.             if (PEAR::isError($result)) {
  1096.                 return $result;
  1097.             }
  1098.         }
  1099.         
  1100.         return $this->db->autoExecute($this->table$data,
  1101.             DB_AUTOQUERY_INSERT);
  1102.     }
  1103.     
  1104.     
  1105.     /**
  1106.     * 
  1107.     * Turns on (or off) automatic validation of inserted data.
  1108.     * 
  1109.     * @access public
  1110.     * 
  1111.     * @param bool $flag True to turn on auto-validation, false to turn it off.
  1112.     * 
  1113.     * @return void 
  1114.     * 
  1115.     */
  1116.     
  1117.     function autoValidInsert($flag = true)
  1118.     {
  1119.         if ($flag{
  1120.             $this->_valid_insert = true;
  1121.         else {
  1122.             $this->_valid_insert = false;
  1123.         }
  1124.     }
  1125.     
  1126.     
  1127.     /**
  1128.     *
  1129.     * Validates an array for insertion into the table.
  1130.     * 
  1131.     * @access public
  1132.     * 
  1133.     * @param array $data An associative array of key-value pairs where
  1134.     *  the key is the column name and the value is the column value.  This
  1135.     *  is the data that will be inserted into the table.  Data is checked
  1136.     *  against the column data type for validity.
  1137.     * 
  1138.     * @return mixed Boolean true on success, a PEAR_Error object on
  1139.     *  failure.
  1140.     *
  1141.     * @see insert()
  1142.     * 
  1143.     */
  1144.         
  1145.     function validInsert(&$data)
  1146.     {
  1147.         // loop through the data, and disallow insertion of unmapped
  1148.         // columns
  1149.         foreach ($data as $col => $val{
  1150.             if (isset($this->col[$col])) {
  1151.                 return $this->throwError(
  1152.                     DB_TABLE_ERR_INS_COL_NOMAP,
  1153.                     "('$col')"
  1154.                 );
  1155.             }
  1156.         }
  1157.         
  1158.         // loop through each column mapping, and check the data to be
  1159.         // inserted into it against the column data type. we loop through
  1160.         // column mappings instead of the insert data to make sure that
  1161.         // all necessary columns are being inserted.
  1162.         foreach ($this->col as $col => $val{
  1163.             
  1164.             // is the value allowed to be null?
  1165.             if (isset($val['require']&&
  1166.                 $val['require'== true &&
  1167.                 (isset($data[$col]|| is_null($data[$col]))) {
  1168.                 return $this->throwError(
  1169.                     DB_TABLE_ERR_INS_COL_REQUIRED,
  1170.                     "'$col'"
  1171.                 );
  1172.             }
  1173.             
  1174.             // does the value to be inserted match the column data type?
  1175.             if (isset($data[$col]&&
  1176.                 $this->isValid($data[$col]$col)) {
  1177.                 return $this->throwError(
  1178.                     DB_TABLE_ERR_INS_DATA_INVALID,
  1179.                     "'$col' ('$data[$col]')"
  1180.                 );
  1181.             }
  1182.         }
  1183.         
  1184.         return true;
  1185.     }
  1186.     
  1187.     
  1188.     /**
  1189.     *
  1190.     * Updates table row(s) matching a custom WHERE clause, after checking
  1191.     * against validUpdate().
  1192.     * 
  1193.     * @access public
  1194.     * 
  1195.     * @param array $data An associative array of key-value pairs where
  1196.     *  the key is the column name and the value is the column value.  These
  1197.     *  are the columns that will be updated with new values.
  1198.     * 
  1199.     * @param string $where An SQL WHERE clause limiting which records
  1200.     *  are to be updated.
  1201.     * 
  1202.     * @return mixed Void on success, a PEAR_Error object on failure.
  1203.     *
  1204.     * @see validUpdate()
  1205.     *
  1206.     * @see DB::autoExecute()
  1207.     * 
  1208.     */
  1209.     
  1210.     function update($data$where)
  1211.     {
  1212.         // forcibly recast the data elements to their proper types?
  1213.         if ($this->_auto_recast{
  1214.             $this->recast($data);
  1215.         }
  1216.         
  1217.         // validate the data if auto-validation is turned on
  1218.         if ($this->_valid_update{
  1219.             $result $this->validUpdate($data);
  1220.             if (PEAR::isError($result)) {
  1221.                 return $result;
  1222.             }
  1223.         }
  1224.         
  1225.         return $this->db->autoExecute($this->table$data,
  1226.             DB_AUTOQUERY_UPDATE$where);
  1227.     }
  1228.     
  1229.     
  1230.     /**
  1231.     * 
  1232.     * Turns on (or off) automatic validation of updated data.
  1233.     * 
  1234.     * @access public
  1235.     * 
  1236.     * @param bool $flag True to turn on auto-validation, false to turn it off.
  1237.     * 
  1238.     * @return void 
  1239.     * 
  1240.     */
  1241.     
  1242.     function autoValidUpdate($flag = true)
  1243.     {
  1244.         if ($flag{
  1245.             $this->_valid_update = true;
  1246.         else {
  1247.             $this->_valid_update = false;
  1248.         }
  1249.     }
  1250.     
  1251.     
  1252.     /**
  1253.     *
  1254.     * Validates an array for updating the table.
  1255.     * 
  1256.     * @access public
  1257.     * 
  1258.     * @param array $data An associative array of key-value pairs where
  1259.     *  the key is the column name and the value is the column value.  This
  1260.     *  is the data that will be inserted into the table.  Data is checked
  1261.     *  against the column data type for validity.
  1262.     * 
  1263.     * @return mixed Boolean true on success, a PEAR_Error object on
  1264.     *  failure.
  1265.     *
  1266.     * @see update()
  1267.     * 
  1268.     */
  1269.         
  1270.     function validUpdate(&$data)
  1271.     {
  1272.         // loop through each data element, and check the
  1273.         // data to be updated against the column data type.
  1274.         foreach ($data as $col => $val{
  1275.             
  1276.             // does the column exist?
  1277.             if (isset($this->col[$col])) {
  1278.                 return $this->throwError(
  1279.                     DB_TABLE_ERR_UPD_COL_NOMAP,
  1280.                     "('$col')"
  1281.                 );
  1282.             }
  1283.             
  1284.             // the column definition
  1285.             $defn $this->col[$col];
  1286.             
  1287.             // is it allowed to be null?
  1288.             if (isset($defn['require']&&
  1289.                 $defn['require'== true &&
  1290.                 isset($data[$col]&&
  1291.                 is_null($data[$col])) {
  1292.                 return $this->throwError(
  1293.                     DB_TABLE_ERR_UPD_COL_REQUIRED,
  1294.                     $col
  1295.                 );
  1296.             }
  1297.             
  1298.             // does the value to be inserted match the column data type?
  1299.             if ($this->isValid($data[$col]$col)) {
  1300.                 return $this->throwError(
  1301.                     DB_TABLE_ERR_UPD_DATA_INVALID,
  1302.                     "$col ('$data[$col]')"
  1303.                 );
  1304.             }
  1305.         }
  1306.         
  1307.         return true;
  1308.     }
  1309.     
  1310.     
  1311.     /**
  1312.     *
  1313.     * Deletes table rows matching a custom WHERE clause.
  1314.     * 
  1315.     * @access public
  1316.     * 
  1317.     * @param string $where The WHERE clause for the delete command.
  1318.     *
  1319.     * @return mixed Void on success or a PEAR_Error object on failure.
  1320.     *
  1321.     * @see DB::query()
  1322.     * 
  1323.     */
  1324.     
  1325.     function delete($where)
  1326.     {
  1327.         return $this->db->query("DELETE FROM $this->table WHERE $where");
  1328.     }
  1329.     
  1330.     
  1331.     /**
  1332.     *
  1333.     * Generates a sequence value; sequence name defaults to the table name.
  1334.     * 
  1335.     * @access public
  1336.     * 
  1337.     * @param string $seq_name The sequence name; defaults to table_id.
  1338.     * 
  1339.     * @return integer The next value in the sequence.
  1340.     *
  1341.     * @see DB::nextID()
  1342.     *
  1343.     */
  1344.     
  1345.     function nextID($seq_name = null)
  1346.     {
  1347.         if (is_null($seq_name)) {
  1348.             $seq_name = "{$this->table}";
  1349.         } else {
  1350.             $seq_name = "{$this->table}_{$seq_name}";
  1351.         }
  1352.         
  1353.         // the maximum length is 30, but PEAR DB will add "_seq" to the
  1354.         // name, so the max length here is less 4 chars. we have to
  1355.         // check here because the sequence will be created automatically
  1356.         // by PEAR DB, which will not check for length on its own.
  1357.         if (strlen($seq_name) > 26) {
  1358.             return DB_Table::throwError(
  1359.                 DB_TABLE_ERR_SEQ_STRLEN,
  1360.                 " ('$seq_name')"
  1361.             );
  1362.             
  1363.         }
  1364.         return $this->db->nextId($seq_name);
  1365.     }
  1366.     
  1367.     
  1368.     /**
  1369.     * 
  1370.     * Escapes and enquotes a value for use in an SQL query.
  1371.     * 
  1372.     * Helps makes user input safe against SQL injection attack.
  1373.     * 
  1374.     * @access public
  1375.     * 
  1376.     * @return string The value with quotes escaped, and inside single quotes.
  1377.     * 
  1378.     * @see DB_Common::quoteSmart()
  1379.     * 
  1380.     */
  1381.     
  1382.     function quote($val)
  1383.     {
  1384.         return $this->db->quoteSmart($val);
  1385.     }
  1386.     
  1387.     
  1388.     /**
  1389.     * 
  1390.     * Returns a blank row array based on the column map.
  1391.     * 
  1392.     * The array keys are the column names, and all values are set to null.
  1393.     * 
  1394.     * @access public
  1395.     * 
  1396.     * @return array An associative array where the key is column name
  1397.     * and the value is null.
  1398.     * 
  1399.     */
  1400.     
  1401.     function getBlankRow()
  1402.     {
  1403.         $row = array();
  1404.         
  1405.         foreach ($this->col as $key => $val{
  1406.             $row[$key] = null;
  1407.         }
  1408.         
  1409.         $this->recast($row);
  1410.         
  1411.         return $row;
  1412.     }
  1413.     
  1414.     
  1415.     /**
  1416.     * 
  1417.     * Turns on (or off) automatic recasting of insert and update data.
  1418.     * 
  1419.     * @access public
  1420.     * 
  1421.     * @param bool $flag True to autmatically recast insert and update data,
  1422.     * false to not do so.
  1423.     *
  1424.     * @return void
  1425.     * 
  1426.     */
  1427.     
  1428.     function autoRecast($flag = true)
  1429.     {
  1430.         if ($flag) {
  1431.             $this->_auto_recast = true;
  1432.         } else {
  1433.             $this->_auto_recast = false;
  1434.         }
  1435.     }
  1436.     
  1437.     
  1438.     /**
  1439.     * 
  1440.     * Forces array elements to the proper types for their columns.
  1441.     * 
  1442.     * This will not valiate the data, and will forcibly change the data
  1443.     * to match the recast-type.
  1444.     * 
  1445.     * The date, time, and timestamp recasting has special logic for
  1446.     * arrays coming from an HTML_QuickForm object so that the arrays
  1447.     * are converted into properly-formatted strings.
  1448.     * 
  1449.     * @todo If a column key holds an array of values (say from a multiple
  1450.     * select) then this method will not work properly; it will recast the
  1451.     * value to the string 'Array'.  Is this bad?
  1452.     * 
  1453.     * @access public
  1454.     * 
  1455.     * @param array &$data The data array to re-cast.
  1456.     *
  1457.     * @return void
  1458.     * 
  1459.     */
  1460.     
  1461.     function recast(&$data)
  1462.     {
  1463.         $keys = array_keys($data);
  1464.         
  1465.         foreach ($keys as $key) {
  1466.         
  1467.             if (! isset($this->col[$key])) {
  1468.                 continue;
  1469.             }
  1470.             
  1471.             unset($val);
  1472.             $val =& $data[$key];
  1473.             
  1474.             // skip explicit NULL values
  1475.             if (is_null($val)) {
  1476.                 continue;
  1477.             }
  1478.             
  1479.             // otherwise, recast to the column type
  1480.             switch ($this->col[$key]['type']{
  1481.             
  1482.             case 'boolean':
  1483.                 $val = ($val) ? 1 : 0;
  1484.                 break;
  1485.                 
  1486.             case 'char':
  1487.             case 'varchar':
  1488.             case 'clob':
  1489.                 settype($val, 'string');
  1490.                 break;
  1491.                 
  1492.             case 'date':
  1493.             
  1494.                 if (is_array($val) &&
  1495.                     isset($val['Y']) &&
  1496.                     isset($val['m']) &&
  1497.                     isset($val['d'])) {
  1498.                     
  1499.                     // the date is in HTML_QuickForm format,
  1500.                     // convert into a string
  1501.                     $y = (strlen($val['Y']) < 4)
  1502.                         ? str_pad($val['Y'], 4, '0', STR_PAD_LEFT)
  1503.                         : $val['Y'];
  1504.                     
  1505.                     $m = (strlen($val['m']) < 2)
  1506.                         ? '0'.$val['m'] : $val['m'];
  1507.                         
  1508.                     $d = (strlen($val['d']) < 2)
  1509.                         ? '0'.$val['d'] : $val['d'];
  1510.                         
  1511.                     $val = "$y-$m-$d";
  1512.                     
  1513.                 } else {
  1514.                 
  1515.                     // convert using the Date class
  1516.                     $tmp =& new Date($val);
  1517.                     $val = $tmp->format('%Y-%m-%d');
  1518.                     
  1519.                 }
  1520.                 
  1521.                 break;
  1522.             
  1523.             case 'time':
  1524.             
  1525.                 if (is_array($val) &&
  1526.                     isset($val['H']) &&
  1527.                     isset($val['i']) &&
  1528.                     isset($val['s'])) {
  1529.                     
  1530.                     // the time is in HTML_QuickForm format,
  1531.                     // convert into a string
  1532.                     $h = (strlen($val['H']) < 2)
  1533.                         ? '0' . $val['H'] : $val['H'];
  1534.                     
  1535.                     $i = (strlen($val['i']) < 2)
  1536.                         ? '0' . $val['i'] : $val['i'];
  1537.                         
  1538.                     $s = (strlen($val['s']) < 2)
  1539.                         ? '0' . $val['s'] : $val['s'];
  1540.                         
  1541.                         
  1542.                     $val = "$h:$i:$s";
  1543.                     
  1544.                 } else {
  1545.                     // date does not matter in this case, so
  1546.                     // pre 1970 and post 2040 are not an issue.
  1547.                     $tmp = strtotime(date('Y-m-d') . " $val");
  1548.                     $val = date('H:i:s', $tmp);
  1549.                 }
  1550.                 
  1551.                 break;
  1552.                 
  1553.             case 'timestamp':
  1554.                 if (is_array($val) &&
  1555.                     isset($val['Y']) &&
  1556.                     isset($val['m']) &&
  1557.                     isset($val['d']) &&
  1558.                     isset($val['H']) &&
  1559.                     isset($val['i']) &&
  1560.                     isset($val['s'])) {
  1561.                     
  1562.                     // timestamp is in HTML_QuickForm format,
  1563.                     // convert each element to a string. pad
  1564.                     // with zeroes as needed.
  1565.                 
  1566.                     $y = (strlen($val['Y']) < 4)
  1567.                         ? str_pad($val['Y'], 4, '0', STR_PAD_LEFT)
  1568.                         : $val['Y'];
  1569.                     
  1570.                     $m = (strlen($val['m']) < 2)
  1571.                         ? '0'.$val['m'] : $val['m'];
  1572.                         
  1573.                     $d = (strlen($val['d']) < 2)
  1574.                         ? '0'.$val['d'] : $val['d'];
  1575.                         
  1576.                     $h = (strlen($val['H']) < 2)
  1577.                         ? '0' . $val['H'] : $val['H'];
  1578.                     
  1579.                     $i = (strlen($val['i']) < 2)
  1580.                         ? '0' . $val['i'] : $val['i'];
  1581.                         
  1582.                     $s = (strlen($val['s']) < 2)
  1583.                         ? '0' . $val['s'] : $val['s'];
  1584.                         
  1585.                     $val = "$y-$m-$d $h:$i:$s";
  1586.                     
  1587.                 } else {
  1588.                     // convert using the Date class
  1589.                     $tmp =& new Date($val);
  1590.                     $val = $tmp->format('%Y-%m-%d %H:%M:%S');
  1591.                 }
  1592.                 
  1593.                 break;
  1594.             
  1595.             case 'smallint':
  1596.             case 'integer':
  1597.             case 'bigint':
  1598.                 settype($val, 'integer');
  1599.                 break;
  1600.             
  1601.             case 'decimal':
  1602.             case 'single':
  1603.             case 'double':
  1604.                 settype($val, 'float');
  1605.                 break;
  1606.             }
  1607.         }
  1608.     }
  1609.     
  1610.     
  1611.     /**
  1612.     * 
  1613.     * Creates the table based on $this->col and $this->idx.
  1614.     * 
  1615.     * @access public
  1616.     * 
  1617.     * @param mixed $flag Boolean false to abort the create attempt from
  1618.     * the start, 'drop' to drop the existing table and
  1619.     * re-create it, or 'safe' to only create the table if it
  1620.     * does not exist in the database.
  1621.     * 
  1622.     * @return mixed Boolean false if there was no attempt to create the
  1623.     * table, boolean true if the attempt succeeded, or a PEAR_Error if
  1624.     * the attempt failed.
  1625.     *
  1626.     * @see DB_Table_Manager::create()
  1627.     * 
  1628.     */
  1629.     
  1630.     function create($flag)
  1631.     {
  1632.         // are we OK to create the table?
  1633.         $ok = false;
  1634.         
  1635.         // check the create-flag
  1636.         switch ($flag) {
  1637.         
  1638.         case 'drop':
  1639.             // forcibly drop an existing table
  1640.             $this->db->query("DROP TABLE {$this->table}");
  1641.             $ok = true;
  1642.             break;
  1643.         
  1644.         case 'safe':
  1645.             // create only if table does not exist
  1646.             $list = $this->db->getListOf('tables');
  1647.             // ok to create only if table does not exist
  1648.             $ok (in_array($this->table$list));
  1649.             break;
  1650.             
  1651.         default:
  1652.             // unknown flag
  1653.             return $this->throwError(
  1654.                 DB_TABLE_ERR_CREATE_FLAG,
  1655.                 "('$flag')"
  1656.             );
  1657.         }
  1658.         
  1659.         // are we going to create the table?
  1660.         if (! $ok) {
  1661.             return false;
  1662.         } else {
  1663.             include_once 'DB/Table/Manager.php';
  1664.             return DB_Table_Manager::create(
  1665.                 $this->db$this->table$this->col$this->idx$flag
  1666.             );
  1667.         }
  1668.     }
  1669.     
  1670.     
  1671.     /**
  1672.     * 
  1673.     * Checks if a value validates against the DB_Table data type for a
  1674.     * given column. This only checks that it matches the data type; it
  1675.     * does not do extended validation.
  1676.     * 
  1677.     * @access public
  1678.     * 
  1679.     * @param array $val A value to check against the column's DB_Table
  1680.     * data type.
  1681.     * 
  1682.     * @param array $col A column name from $this->col.
  1683.     * 
  1684.     * @return boolean True if the value validates (matches the
  1685.     * data type), false if not.
  1686.     * 
  1687.     * @see DB_Table_Valid
  1688.     * 
  1689.     */
  1690.     
  1691.     function isValid($val, $col)
  1692.     {
  1693.         // is the value null?
  1694.         if (is_null($val)) {
  1695.             // is the column required?
  1696.             if ($this->isRequired($col)) {
  1697.                 // yes, so not valid
  1698.                 return false;
  1699.             } else {
  1700.                 // not required, so it's valid
  1701.                 return true;
  1702.             }
  1703.         }
  1704.         
  1705.         // make sure we have the validation class
  1706.         include_once 'DB/Table/Valid.php';
  1707.         
  1708.         // validate values per the column type
  1709.         $map = array_keys($GLOBALS['_DB_TABLE']['type']['sqlite']);
  1710.         
  1711.         // is the column type on the map?
  1712.         if (! in_array($this->col[$col]['type']$map)) {
  1713.             return $this->throwError(
  1714.                 DB_TABLE_ERR_VALIDATE_TYPE,
  1715.                 "'$col' ('{$this->col[$col]['type']}')"
  1716.             );
  1717.         }
  1718.         
  1719.         // validate for the type
  1720.         switch ($this->col[$col]['type']{
  1721.         
  1722.         case 'char':
  1723.         case 'varchar':
  1724.             $result = DB_Table_Valid::isChar(
  1725.                 $val,
  1726.                 $this->col[$col]['size']
  1727.             );
  1728.             break;
  1729.         
  1730.         case 'decimal':
  1731.             $result = DB_Table_Valid::isDecimal(
  1732.                 $val,
  1733.                 $this->col[$col]['size'],
  1734.                 $this->col[$col]['scope']
  1735.             );
  1736.             break;
  1737.             
  1738.         default:
  1739.             $result = call_user_func(
  1740.                 array(
  1741.                     'DB_Table_Valid',
  1742.                     'is' . ucwords($this->col[$col]['type'])
  1743.                 ),
  1744.                 $val
  1745.             );
  1746.             break;
  1747.         }
  1748.         
  1749.         // have we passed the check so far, and should we
  1750.         // also check for allowed values?
  1751.         if ($result && isset($this->col[$col]['qf_vals'])) {
  1752.             $keys = array_keys($this->col[$col]['qf_vals']);
  1753.             
  1754.             $result = in_array(
  1755.                 $val,
  1756.                 array_keys($this->col[$col]['qf_vals'])
  1757.             );
  1758.         }
  1759.         
  1760.         return $result;
  1761.     }
  1762.     
  1763.     
  1764.     /**
  1765.     * 
  1766.     * Is a specific column required to be set and non-null?
  1767.     * 
  1768.     * @access public
  1769.     * 
  1770.     * @param mixed $column The column to check against.
  1771.     * 
  1772.     * @return boolean True if required, false if not.
  1773.     * 
  1774.     */
  1775.     
  1776.     function isRequired($column)
  1777.     {
  1778.         if (isset($this->col[$column]['require']&&
  1779.             $this->col[$column]['require'== true{
  1780.             return true;
  1781.         } else {
  1782.             return false;
  1783.         }
  1784.     }
  1785.     
  1786.     
  1787.     /**
  1788.     * 
  1789.     * Creates and returns a QuickForm object based on table columns.
  1790.     *
  1791.     * @access public
  1792.     *
  1793.     * @param array $columns A sequential array of column names to use in
  1794.     * the form; if null, uses all columns.
  1795.     *
  1796.     * @param string $array_name By default, the form will use the names
  1797.     * of the columns as the names of the form elements.  If you pass
  1798.     * $array_name, the column names will become keys in an array named
  1799.     * for this parameter.
  1800.     * 
  1801.     * @param array $args An associative array of optional arguments to
  1802.     * pass to the QuickForm object.  The keys are...
  1803.     *
  1804.     * 'formName' : String, name of the form; defaults to the name of this
  1805.     * table.
  1806.     * 
  1807.     * 'method' : String, form method; defaults to 'post'.
  1808.     * 
  1809.     * 'action' : String, form action; defaults to
  1810.     * $_SERVER['REQUEST_URI'].
  1811.     * 
  1812.     * 'target' : String, form target target; defaults to '_self'
  1813.     * 
  1814.     * 'attributes' : Associative array, extra attributes for <form>
  1815.     * tag; the key is the attribute name and the value is attribute
  1816.     * value.
  1817.     * 
  1818.     * 'trackSubmit' : Boolean, whether to track if the form was
  1819.     * submitted by adding a special hidden field
  1820.     * 
  1821.     * @return object HTML_QuickForm
  1822.     * 
  1823.     * @see HTML_QuickForm
  1824.     * 
  1825.     * @see DB_Table_QuickForm
  1826.     * 
  1827.     */
  1828.     
  1829.     function &getForm($columns = null, $array_name = null, $args = array(),
  1830.         $clientValidate = null)
  1831.     {
  1832.         include_once 'DB/Table/QuickForm.php';
  1833.         $coldefs = $this->_getFormColDefs($columns);
  1834.         return DB_Table_QuickForm::getForm($coldefs$array_name$args,
  1835.             $clientValidate);
  1836.     }
  1837.     
  1838.     
  1839.     /**
  1840.     * 
  1841.     * Adds elements and rules to a pre-existing HTML_QuickForm object.
  1842.     * 
  1843.     * @access public
  1844.     * 
  1845.     * @param object &$form An HTML_QuickForm object.
  1846.     * 
  1847.     * @param array $columns A sequential array of column names to use in
  1848.     * the form; if null, uses all columns.
  1849.     *
  1850.     * @param string $array_name By default, the form will use the names
  1851.     * of the columns as the names of the form elements.  If you pass
  1852.     * $array_name, the column names will become keys in an array named
  1853.     * for this parameter.
  1854.     * 
  1855.     * @return void
  1856.     * 
  1857.     * @see HTML_QuickForm
  1858.     * 
  1859.     * @see DB_Table_QuickForm
  1860.     * 
  1861.     */
  1862.     
  1863.     function addFormElements(&$form, $columns = null, $array_name = null,
  1864.         $clientValidate = null)
  1865.     {
  1866.         include_once 'DB/Table/QuickForm.php';
  1867.         $coldefs = $this->_getFormColDefs($columns);
  1868.         DB_Table_QuickForm::addElements($form$coldefs$array_name);
  1869.         DB_Table_QuickForm::addRules($form$coldefs$array_name,
  1870.             $clientValidate);
  1871.     }
  1872.     
  1873.     
  1874.     /**
  1875.     * 
  1876.     * Creates and returns an array of QuickForm elements based on an
  1877.     * array of DB_Table column names.
  1878.     * 
  1879.     * @access public
  1880.     * 
  1881.     * @param array $columns A sequential array of column names to use in
  1882.     * the form; if null, uses all columns.
  1883.     * 
  1884.     * @param string $array_name By default, the form will use the names
  1885.     * of the columns as the names of the form elements.  If you pass
  1886.     * $array_name, the column names will become keys in an array named
  1887.     * for this parameter.
  1888.     * 
  1889.     * @return array An array of HTML_QuickForm_Element objects.
  1890.     * 
  1891.     * @see HTML_QuickForm
  1892.     * 
  1893.     * @see DB_Table_QuickForm
  1894.     * 
  1895.     */
  1896.     
  1897.     function &getFormGroup($columns = null, $array_name = null)
  1898.     {
  1899.         include_once 'DB/Table/QuickForm.php';
  1900.         $coldefs = $this->_getFormColDefs($columns);
  1901.         return DB_Table_QuickForm::getGroup($coldefs$array_name);
  1902.     }
  1903.     
  1904.     
  1905.     /**
  1906.     * 
  1907.     * Creates and returns a single QuickForm element based on a DB_Table
  1908.     * column name.
  1909.     * 
  1910.     * @access public
  1911.     * 
  1912.     * @param string $column A DB_Table column name.
  1913.     * 
  1914.     * @param string $elemname The name to use for the generated QuickForm
  1915.     * element.
  1916.     * 
  1917.     * @return object HTML_QuickForm_Element
  1918.     * 
  1919.     * @see HTML_QuickForm
  1920.     * 
  1921.     * @see DB_Table_QuickForm
  1922.     * 
  1923.     */
  1924.     
  1925.     function &getFormElement($column, $elemname)
  1926.     {
  1927.         include_once 'DB/Table/QuickForm.php';
  1928.         $coldef = $this->_getFormColDefs($column);
  1929.         return DB_Table_QuickForm::getElement($coldef[$column]$elemname);
  1930.     }
  1931.  
  1932.     /**
  1933.     * 
  1934.     * Creates and returns an array of QuickForm elements based on a DB_Table
  1935.     * column name.
  1936.     * 
  1937.     * @author Ian Eure <ieure@php.net>
  1938.     * 
  1939.     * @access public
  1940.     * 
  1941.     * @param string $cols Array of DB_Table column names
  1942.     * 
  1943.     * @param string $array_name The name to use for the generated QuickForm
  1944.     * elements.
  1945.     * 
  1946.     * @return object HTML_QuickForm_Element
  1947.     * 
  1948.     * @see HTML_QuickForm
  1949.     * 
  1950.     * @see DB_Table_QuickForm
  1951.     * 
  1952.     */
  1953.     function &getFormElements($cols, $array_name = null)
  1954.     {
  1955.         include_once 'DB/Table/QuickForm.php';
  1956.         return DB_Table_QuickForm::getElements($cols, $array_name);
  1957.     }
  1958.     
  1959.     
  1960.     /**
  1961.     * 
  1962.     * Creates a column definition array suitable for DB_Table_QuickForm.
  1963.     * 
  1964.     * @access public
  1965.     * 
  1966.     * @param string|array $column_set A string column name, a sequential
  1967.     * array of columns names, or an associative array where the key is a
  1968.     * column name and the value is the default value for the generated
  1969.     * form element.  If null, uses all columns for this class.
  1970.     * 
  1971.     * @return array An array of columne defintions suitable for passing
  1972.     * to DB_Table_QuickForm.
  1973.     * 
  1974.     */
  1975.     
  1976.     function _getFormColDefs($column_set = null)
  1977.     {
  1978.         if (is_null($column_set)) {
  1979.             // no columns or columns+values; just return the $this->col
  1980.             // array.
  1981.             return $this->getColumns($column_set);
  1982.         }
  1983.         
  1984.         // check to see if the keys are sequential integers.  if so,
  1985.         // the $column_set is just a list of columns.
  1986.         settype($column_set, 'array');
  1987.         $keys = array_keys($column_set);
  1988.         $all_integer = true;
  1989.         foreach ($keys as $val) {
  1990.             if (! is_integer($val)) {
  1991.                 $all_integer = false;
  1992.                 break;
  1993.             }
  1994.         }
  1995.         
  1996.         if ($all_integer) {
  1997.         
  1998.             // the column_set is just a list of columns; get back the $this->col
  1999.             // array elements matching this list.
  2000.             $coldefs = $this->getColumns($column_set);
  2001.             
  2002.         } else {
  2003.             
  2004.             // the columns_set is an associative array where the key is a
  2005.             // column name and the value is the form element value.
  2006.             $coldefs = $this->getColumns($keys);
  2007.             foreach ($coldefs as $key => $val{
  2008.                 $coldefs[$key]['qf_setvalue'] = $column_set[$key];
  2009.             }
  2010.             
  2011.         }
  2012.         
  2013.         return $coldefs;
  2014.     }
  2015.  
  2016. }

Documentation generated on Mon, 11 Mar 2019 14:10:11 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.