home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / DB / Table / Generator.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  44.3 KB  |  1,333 lines

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * DB_Table_Generator - Generates DB_Table subclass skeleton code
  7.  * 
  8.  * Parts of this class were adopted from the DB_DataObject PEAR package.
  9.  * 
  10.  * PHP versions 4 and 5
  11.  *
  12.  * LICENSE:
  13.  * 
  14.  * Copyright (c) 1997-2007, Paul M. Jones <pmjones@php.net>
  15.  *                          Alan Knowles <alan@akbkhome.com>
  16.  *                          David C. Morse <morse@php.net>
  17.  *                          Mark Wiesemann <wiesemann@php.net>
  18.  * All rights reserved.
  19.  *
  20.  * Redistribution and use in source and binary forms, with or without
  21.  * modification, are permitted provided that the following conditions
  22.  * are met:
  23.  *
  24.  *    * Redistributions of source code must retain the above copyright
  25.  *      notice, this list of conditions and the following disclaimer.
  26.  *    * Redistributions in binary form must reproduce the above copyright
  27.  *      notice, this list of conditions and the following disclaimer in the 
  28.  *      documentation and/or other materials provided with the distribution.
  29.  *    * The names of the authors may not be used to endorse or promote products 
  30.  *      derived from this software without specific prior written permission.
  31.  *
  32.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  33.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  34.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  35.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  37.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  38.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  39.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  40.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  41.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  *
  44.  * @category Database
  45.  * @package  DB_Table
  46.  * @author   Alan Knowles <alan@akbkhome.com> 
  47.  * @author   David C. Morse <morse@php.net>
  48.  * @license  http://opensource.org/licenses/bsd-license.php New BSD License
  49.  * @version  CVS: $Id: Generator.php,v 1.17 2008/05/14 18:36:27 wiesemann Exp $
  50.  * @link     http://pear.php.net/package/DB_Table
  51.  */
  52.  
  53. // {{{ Includes
  54.  
  55. /**#@+
  56.  * Include basic classes
  57.  */
  58. /**
  59.  * The PEAR class (used for errors)
  60.  */
  61. require_once 'PEAR.php';
  62.  
  63. /**
  64.  * DB_Table table abstraction class
  65.  */
  66. require_once 'DB/Table.php';
  67.  
  68. /**
  69.  * DB_Table_Manager class (used to reverse engineer indices)
  70.  */
  71. require_once 'DB/Table/Manager.php';
  72. /**#@-*/
  73.  
  74. // }}}
  75. // {{{ Error code constants
  76.  
  77. /**#@+
  78.  * Error codes
  79.  */
  80. /**
  81.  * Parameter is not a DB/MDB2 object
  82.  */
  83. define('DB_TABLE_GENERATOR_ERR_DB_OBJECT', -301);
  84.  
  85. /**
  86.  * Parameter is not a DB/MDB2 object
  87.  */
  88. define('DB_TABLE_GENERATOR_ERR_INDEX_COL', -302);
  89.  
  90. /**
  91.  * Error while creating file/directory
  92.  */
  93. define('DB_TABLE_GENERATOR_ERR_FILE', -303);
  94. /**#@-*/
  95.  
  96. // }}}
  97. // {{{ Error messages
  98. /**
  99.  * US-English default error messages.
  100.  */
  101. $GLOBALS['_DB_TABLE_GENERATOR']['default_error'] = array(
  102.         DB_TABLE_GENERATOR_ERR_DB_OBJECT =>
  103.             'Invalid DB/MDB2 object parameter. Function',
  104.         DB_TABLE_GENERATOR_ERR_INDEX_COL =>
  105.             'Index column is not a valid column name. Index column',
  106.         DB_TABLE_GENERATOR_ERR_FILE =>
  107.             'Can\'t create file/directory:'
  108. );
  109.  
  110. // merge default and user-defined error messages
  111. if (!isset($GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
  112.     $GLOBALS['_DB_TABLE_GENERATOR']['error'] = array();
  113. }
  114. foreach ($GLOBALS['_DB_TABLE_GENERATOR']['default_error'] as $code => $message) {
  115.     if (!array_key_exists($code, $GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
  116.         $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
  117.     }
  118. }
  119.  
  120. // }}}
  121. // {{{ class DB_Table_Generator
  122.  
  123. /**
  124.  * class DB_Table_Generator - Generates DB_Table subclass skeleton code
  125.  *
  126.  * This class generates the php code necessary to use the DB_Table
  127.  * package to interact with an existing database. This requires the
  128.  * generation of a skeleton subclass definition be generated for each
  129.  * table in the database, in which the $col, $idx, and $auto_inc_col
  130.  * properties are constructed using a table schema that is obtained
  131.  * by querying the database.
  132.  *
  133.  * The class can also generate a file, named 'Database.php' by default,
  134.  * that includes (require_once) each of the table subclass definitions,
  135.  * instantiates one object of each DB_Table subclass (i.e., one object
  136.  * for each table), instantiates a parent DB_Table_Database object,
  137.  * adds all the tables to that parent, attempts to guess foreign key
  138.  * relationships between tables based on the column names, and adds
  139.  * the inferred references to the parent object.
  140.  *
  141.  * All of the code is written to a directory whose path is given by
  142.  * the property $class_write_path. By default, this is the current
  143.  * directory.  By default, the name of the class constructed for a
  144.  * table named 'thing' is "Thing_Table". That is, the class name is
  145.  * the table name, with the first letter upper case, with a suffix
  146.  * '_Table'.  This suffix can be changed by setting the $class_suffix
  147.  * property. The file containing a subclass definition is the
  148.  * subclass name with a php extension, e.g., 'Thing_Table.php'. The
  149.  * object instantiated from that subclass is the same as the table
  150.  * name, with no suffix, e.g., 'thing'.
  151.  *
  152.  * To generate the code for all of the tables in a database named
  153.  * $database, instantiate a MDB2 or DB object named $db that connects
  154.  * to the database of interest, and execute the following code:
  155.  * <code>
  156.  *     $generator = new DB_Table_Generator($db, $database);
  157.  *     $generator->class_write_path = $class_write_path;
  158.  *     $generator->generateTableClassFiles();
  159.  *     $generator->generateDatabaseFile();
  160.  * </code>
  161.  * Here $class_write_path should be the path (without a trailing
  162.  * separator) to a directory in which all of the code should be
  163.  * written. If this directory does not exist, it will be created.
  164.  * If the directory does already exist, exising files will not
  165.  * be overwritten. If $class_write_path is not set (i.e., if this
  166.  * line is omitted) all the code will be written to the current
  167.  * directory.  If ->generateDatabaseFile() is called, it must be
  168.  * called after ->generateTableClassFiles().
  169.  *
  170.  * By default, ->generateTableClassFiles() and ->generateDatabaseFiles()
  171.  * generate code for all of the tables in the current database. To
  172.  * generate code for a specified list of tables, set the value of the
  173.  * public $tables property to a sequential list of table names before
  174.  * calling either of these methods. Code can be generated for three
  175.  * tables named 'table1', 'table2', and 'table3' as follows:
  176.  * <code>
  177.  *     $generator = new DB_Table_Generator($db, $database);
  178.  *     $generator->class_write_path = $class_write_path;
  179.  *     $generator->tables = array('table1', 'table2', 'table3');
  180.  *     $generator->generateTableClassFiles();
  181.  *     $generator->generateDatabaseFile();
  182.  * </code>
  183.  * If the $tables property is not set to a non-null value prior
  184.  * to calling ->generateTableClassFiles() then, by default, the
  185.  * database is queried for a list of all table names, by calling the
  186.  * ->getTableNames() method from within ->generateTableClassFiles().
  187.  *
  188.  * PHP version 4 and 5
  189.  *
  190.  * @category Database
  191.  * @package  DB_Table
  192.  * @author   Alan Knowles <alan@akbkhome.com> 
  193.  * @author   David C. Morse <morse@php.net>
  194.  * @license  http://www.gnu.org/copyleft/lesser.html LGPL
  195.  * @version  Release: 1.5.5
  196.  * @link     http://pear.php.net/package/DB_Table
  197.  */
  198. class DB_Table_Generator
  199. {
  200.  
  201.     // {{{ Properties
  202.  
  203.     /**
  204.      * Name of the database
  205.      *
  206.      * @var string
  207.      * @access public
  208.      */
  209.     var $name = null;
  210.  
  211.     /**
  212.      * The PEAR DB/MDB2 object that connects to the database.
  213.      *
  214.      * @var object
  215.      * @access private
  216.      */
  217.     var $db = null;
  218.  
  219.     /**
  220.      * The backend type. May have values 'db' or 'mdb2'
  221.      *
  222.      * @var string
  223.      * @access private
  224.      */
  225.     var $backend = null;
  226.  
  227.     /**
  228.     * If there is an error on instantiation, this captures that error.
  229.     *
  230.     * This property is used only for errors encountered in the constructor
  231.     * at instantiation time.  To check if there was an instantiation error...
  232.     *
  233.     * <code>
  234.     *     $obj =& new DB_Table_Generator();
  235.     *     if ($obj->error) {
  236.     *         // ... error handling code here ...
  237.     *     }
  238.     * </code>
  239.     *
  240.     * @var object PEAR_Error
  241.     * @access public
  242.     */
  243.     var $error = null;
  244.  
  245.     /**
  246.      * Numerical array of table name strings
  247.      *
  248.      * @var array
  249.      * @access public
  250.      */
  251.     var $tables = array();
  252.  
  253.     /**
  254.      * Class being extended (DB_Table or generic subclass)
  255.      *
  256.      * @var string
  257.      * @access public
  258.      */
  259.     var $extends = 'DB_Table';
  260.  
  261.     /**
  262.      * Path to definition of the class $this->extends
  263.      *
  264.      * @var string
  265.      * @access public
  266.      */
  267.     var $extends_file = 'DB/Table.php';
  268.  
  269.     /**
  270.      * Suffix to add to table names to obtain corresponding class names
  271.      *
  272.      * @var string
  273.      * @access public
  274.      */
  275.     var $class_suffix = "_Table";
  276.  
  277.     /**
  278.      * Path to directory in which subclass definitions should be written
  279.      *
  280.      * Value should not include a trailing "/".
  281.      *
  282.      * @var string
  283.      * @access public
  284.      */
  285.     var $class_write_path = '';
  286.  
  287.     /**
  288.      * Include path to subclass definition files from database file
  289.      *
  290.      * Used to create require_once statements in the Database.php file,
  291.      * which is in the same directory as the class definition files. Leave
  292.      * as empty string if your PHP include_path contains ".". The value
  293.      * should not include a trailing "/", which is added automatically
  294.      * to values other than the empty string.
  295.      *
  296.      * @var string
  297.      * @access public
  298.      */
  299.     var $class_include_path = '';
  300.  
  301.     /**
  302.      * Array of column definitions
  303.      *
  304.      * Array $this->col[table_name][column_name] = column definition.
  305.      * Column definition is an array with the same format as the $col
  306.      * property of a DB_Table object
  307.      *
  308.      * @var array
  309.      * @access public
  310.      */
  311.     var $col = array();
  312.  
  313.     /**
  314.      * Array of index/constraint definitions.
  315.      *
  316.      * Array $this->idx[table_table][index_name] = Index definition.
  317.      * The index definition is an array with the same format as the
  318.      * DB_Table $idx property property array.
  319.      *
  320.      * @var array
  321.      * @access public
  322.      */
  323.      var $idx = array();
  324.  
  325.     /**
  326.      * Array of auto_increment column names
  327.      *
  328.      * Array $this->auto_inc_col[table_name] = auto-increment column
  329.      *
  330.      * @var array
  331.      * @access public
  332.      */
  333.      var $auto_inc_col = array();
  334.  
  335.     /**
  336.      * Array of primary keys
  337.      *
  338.      * @var array
  339.      * @access public
  340.      */
  341.      var $primary_key = array();
  342.  
  343.     /**
  344.      * MDB2 'idxname_format' option, format of index names
  345.      *
  346.      * For use in printf() formatting. Use '%s' to use index names as
  347.      * returned by getTableConstraints/Indexes, and '%s_idx' to add an
  348.      * '_idx' suffix. For MySQL, use the default value '%'.
  349.      *
  350.      * @var string
  351.      * @access public
  352.      */
  353.     var $idxname_format = '%s';
  354.  
  355.     // }}}
  356.     // {{{ function DB_Table_Generator(&$db, $name)
  357.  
  358.     /**
  359.      * Constructor
  360.      *
  361.      * If an error is encountered during instantiation, the error
  362.      * message is stored in the $this->error property of the resulting
  363.      * object. See $error property docblock for a discussion of error
  364.      * handling.
  365.      *
  366.      * @param object &$db  DB/MDB2 database connection object
  367.      * @param string $name database name string
  368.      *
  369.      * @return object DB_Table_Generator
  370.      * @access public
  371.      */
  372.     function DB_Table_Generator(&$db, $name)
  373.     {
  374.         // Is $db an DB/MDB2 object or null?
  375.         if (is_a($db, 'db_common')) {
  376.             $this->backend = 'db';
  377.         } elseif (is_a($db, 'mdb2_driver_common')) {
  378.             $this->backend = 'mdb2';
  379.         } else {
  380.             $this->error =&
  381.                 DB_Table_Generator::throwError(DB_TABLE_GENERATOR_ERR_DB_OBJECT,
  382.                 'DB_Table_Generator');
  383.             return;
  384.         }
  385.         $this->db   =& $db;
  386.         $this->name =  $name;
  387.  
  388.     }
  389.  
  390.     // }}}
  391.     // {{{ function &throwError($code, $extra = null)
  392.  
  393.     /**
  394.      * Specialized version of throwError() modeled on PEAR_Error.
  395.      *
  396.      * Throws a PEAR_Error with a DB_Table_Generator error message based
  397.      * on a DB_Table_Generator constant error code.
  398.      *
  399.      * @param string $code  A DB_Table_Generator error code constant.
  400.      * @param string $extra Extra text for the error (in addition to the
  401.      *                       regular error message).
  402.      *
  403.      * @return object PEAR_Error
  404.      * @access public
  405.      * @static
  406.      */
  407.     function &throwError($code, $extra = null)
  408.     {
  409.         // get the error message text based on the error code
  410.         $text = 'DB_TABLE_GENERATOR ERROR - ' . "\n"
  411.               . $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code];
  412.  
  413.         // add any additional error text
  414.         if ($extra) {
  415.             $text .= ' ' . $extra;
  416.         }
  417.  
  418.         // done!
  419.         $error = PEAR::throwError($text, $code);
  420.         return $error;
  421.     }
  422.  
  423.     // }}}
  424.     // {{{ function setErrorMessage($code, $message = null)
  425.  
  426.     /**
  427.      * Overwrites one or more error messages, e.g., to internationalize them.
  428.      *
  429.      * @param mixed  $code    If string, the error message with code $code will be
  430.      *                        overwritten by $message. If array, each key is a
  431.      *                        code and each value is a new message.
  432.      * @param string $message Only used if $key is not an array.
  433.      *
  434.      * @return void
  435.      * @access public
  436.      */
  437.     function setErrorMessage($code, $message = null)
  438.     {
  439.         if (is_array($code)) {
  440.             foreach ($code as $single_code => $single_message) {
  441.                 $GLOBALS['_DB_TABLE_GENERATOR']['error'][$single_code]
  442.                     = $single_message;
  443.             }
  444.         } else {
  445.             $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
  446.         }
  447.     }
  448.  
  449.     // }}}
  450.     // {{{ function getTableNames()
  451.  
  452.     /**
  453.      * Gets a list of tables from the database
  454.      *
  455.      * Upon successful completion, names are stored in the $this->tables
  456.      * array. If an error is encountered, a PEAR Error is returned, and
  457.      * $this->tables is reset to null.
  458.      *
  459.      * @return mixed true on success, PEAR Error on failure
  460.      * @access public
  461.      */
  462.     function getTableNames()
  463.     {
  464.  
  465.         if ($this->backend == 'db') {
  466.             // try getting a list of schema tables first. (postgres)
  467.             $this->db->expectError(DB_ERROR_UNSUPPORTED);
  468.             $this->tables = $this->db->getListOf('schema.tables');
  469.             $this->db->popExpect();
  470.             if (PEAR::isError($this->tables)) {
  471.                 // try a list of tables, not qualified by 'schema'
  472.                 $this->db->expectError(DB_ERROR_UNSUPPORTED);
  473.                 $this->tables = $this->db->getListOf('tables');
  474.                 $this->db->popExpect();
  475.             }
  476.         } else {
  477.             // Temporarily change 'portability' MDB2 option
  478.             $portability = $this->db->getOption('portability');
  479.             $this->db->setOption('portability',
  480.                 MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
  481.  
  482.             $this->db->loadModule('Manager');
  483.             $this->db->loadModule('Reverse');
  484.  
  485.             // Get list of tables
  486.             $this->tables = $this->db->manager->listTables();
  487.  
  488.             // Restore original MDB2 'portability'
  489.             $this->db->setOption('portability', $portability);
  490.         }
  491.         if (PEAR::isError($this->tables)) {
  492.             $error        = $this->tables;
  493.             $this->tables = null;
  494.             return $error;
  495.         } else {
  496.             $this->tables = array_map(array($this, 'tableName'),
  497.                                       $this->tables);
  498.             return true;
  499.         }
  500.     }
  501.  
  502.     // }}}
  503.     // {{{ function getTableDefinition($table)
  504.  
  505.     /**
  506.      * Gets column and index definitions by querying database
  507.      *
  508.      * Upon return, column definitions are stored in $this->col[$table],
  509.      * and index definitions in $this->idx[$table].
  510.      *
  511.      * Calls DB/MDB2::tableInfo() for column definitions, and uses
  512.      * the DB_Table_Manager class to obtain index definitions.
  513.      *
  514.      * @param string $table name of table
  515.      *
  516.      * @return mixed true on success, PEAR Error on failure
  517.      * @access public
  518.      */
  519.     function getTableDefinition($table)
  520.     {
  521.         /*
  522.         // postgres strip the schema bit from the
  523.         if (!empty($options['generator_strip_schema'])) {
  524.             $bits = explode('.', $table,2);
  525.             $table = $bits[0];
  526.             if (count($bits) > 1) {
  527.                 $table = $bits[1];
  528.             }
  529.         }
  530.         */
  531.  
  532.         if ($this->backend == 'db') {
  533.  
  534.             $defs = $this->db->tableInfo($table);
  535.             if (PEAR::isError($defs)) {
  536.                 return $defs;
  537.             }
  538.             $this->columns[$table] = $defs;
  539.  
  540.         } else {
  541.  
  542.             // Temporarily change 'portability' MDB2 option
  543.             $portability = $this->db->getOption('portability');
  544.             $this->db->setOption('portability',
  545.                 MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
  546.  
  547.             $this->db->loadModule('Manager');
  548.             $this->db->loadModule('Reverse');
  549.  
  550.             // Columns
  551.             $defs = $this->db->reverse->tableInfo($table);
  552.             if (PEAR::isError($defs)) {
  553.                 return $defs;
  554.             }
  555.  
  556.             // rename the 'length' key, so it matches db's return.
  557.             foreach ($defs as $k => $v) {
  558.                 if (isset($defs[$k]['length'])) {
  559.                     $defs[$k]['len'] = $defs[$k]['length'];
  560.                 }
  561.             }
  562.  
  563.             $this->columns[$table] = $defs;
  564.  
  565.             // Temporarily set 'idxname_format' MDB2 option to $this->idx_format
  566.             $idxname_format = $this->db->getOption('idxname_format');
  567.             $this->db->setOption('idxname_format', $this->idxname_format);
  568.         }
  569.  
  570.         // Default - no auto increment column
  571.         $this->auto_inc_col[$table] = null;
  572.  
  573.         // Loop over columns to create $this->col[$table]
  574.         $this->col[$table] = array();
  575.         foreach ($defs as $t) {
  576.  
  577.             $name = $t['name'];
  578.             $col  = array();
  579.  
  580.             switch (strtoupper($t['type'])) {
  581.             case 'INT2':     // postgres
  582.             case 'TINYINT':
  583.             case 'TINY':     //mysql
  584.             case 'SMALLINT':
  585.                 $col['type'] = 'smallint';
  586.                 break;
  587.             case 'INT4':      // postgres
  588.             case 'SERIAL4':   // postgres
  589.             case 'INT':
  590.             case 'SHORT':     // mysql
  591.             case 'INTEGER':
  592.             case 'MEDIUMINT':
  593.             case 'YEAR':
  594.                 $col['type'] = 'integer';
  595.                 break;
  596.             case 'BIGINT':
  597.             case 'LONG':    // mysql
  598.             case 'INT8':    // postgres
  599.             case 'SERIAL8': // postgres
  600.                 $col['type'] = 'bigint';
  601.                 break;
  602.             case 'REAL':
  603.             case 'NUMERIC':
  604.             case 'NUMBER': // oci8
  605.             case 'FLOAT':  // mysql
  606.             case 'FLOAT4': // real (postgres)
  607.                 $col['type'] = 'single';
  608.                 break;
  609.             case 'DOUBLE':
  610.             case 'DOUBLE PRECISION': // double precision (firebird)
  611.             case 'FLOAT8':           // double precision (postgres)
  612.                 $col['type'] = 'double';
  613.                 break;
  614.             case 'DECIMAL':
  615.             case 'MONEY':   // mssql and maybe others
  616.                 $col['type'] = 'decimal';
  617.                 break;
  618.             case 'BIT':
  619.             case 'BOOL':
  620.             case 'BOOLEAN':
  621.                 $col['type'] = 'boolean';
  622.                 break;
  623.             case 'STRING':
  624.             case 'CHAR':
  625.                 $col['type'] = 'char';
  626.                 break;
  627.             case 'VARCHAR':
  628.             case 'VARCHAR2':
  629.             case 'TINYTEXT':
  630.                 $col['type'] = 'varchar';
  631.                 break;
  632.             case 'TEXT':
  633.             case 'MEDIUMTEXT':
  634.             case 'LONGTEXT':
  635.                 $col['type'] = 'clob';
  636.                 break;
  637.             case 'DATE':
  638.                 $col['type'] = 'date';
  639.                 break;
  640.             case 'TIME':
  641.                 $col['type'] = 'time';
  642.                 break;
  643.             case 'DATETIME':  // mysql
  644.             case 'TIMESTAMP':
  645.                 $col['type'] = 'timestamp';
  646.                 break;
  647.             case 'ENUM':
  648.             case 'SET':         // not really but oh well
  649.             case 'TIMESTAMPTZ': // postgres
  650.             case 'BPCHAR':      // postgres
  651.             case 'INTERVAL':    // postgres (eg. '12 days')
  652.             case 'CIDR':        // postgres IP net spec
  653.             case 'INET':        // postgres IP
  654.             case 'MACADDR':     // postgress network Mac address.
  655.             case 'INTEGER[]':   // postgres type
  656.             case 'BOOLEAN[]':   // postgres type
  657.                 $col['type'] = 'varchar';
  658.                 break;
  659.             default:
  660.                 $col['type'] = $t['type'] . ' (Unknown type)';
  661.                 break;
  662.             }
  663.  
  664.             // Set length and scope if required
  665.             if (in_array($col['type'], array('char','varchar','decimal'))) {
  666.                 if (isset($t['len'])) {
  667.                     $col['size'] = (int) $t['len'];
  668.                 } elseif ($col['type'] == 'varchar') {
  669.                     $col['size'] = 255; // default length
  670.                 } elseif ($col['type'] == 'char') {
  671.                     $col['size'] = 128; // default length
  672.                 } elseif ($col['type'] == 'decimal') {
  673.                     $col['size'] = 15; // default length
  674.                 }
  675.                 if ($col['type'] == 'decimal') {
  676.                     $col['scope'] = 2;
  677.                 }
  678.             }
  679.             if (isset($t['notnull'])) {
  680.                 if ($t['notnull']) {
  681.                     $col['require'] = true;
  682.                 }
  683.             }
  684.             if (isset($t['autoincrement'])) {
  685.                 $this->auto_inc_col[$table] = $name;
  686.             }
  687.             if (isset($t['flags'])) {
  688.                 $flags = $t['flags'];
  689.                 if (preg_match('/not[ _]null/i', $flags)) {
  690.                     $col['require'] = true;
  691.                 }
  692.                 if (preg_match("/(auto_increment|nextval\()/i", $flags)) {
  693.                     $this->auto_inc_col[$table] = $name;
  694.                 }
  695.             }
  696.             $require = isset($col['require']) ? $col['require'] : false;
  697.             if ($require) {
  698.                 if (isset($t['default'])) {
  699.                     $default = $t['default'];
  700.                     $type    = $col['type'];
  701.                     if (in_array($type,
  702.                                  array('smallint', 'integer', 'bigint'))) {
  703.                         $default = (int) $default;
  704.                     } elseif (in_array($type, array('single', 'double'))) {
  705.                         $default = (float) $default;
  706.                     } elseif ($type == 'boolean') {
  707.                         $default = (int) $default ? 1 : 0;
  708.                     }
  709.                     $col['default'] = $default;
  710.                 }
  711.             }
  712.             $this->col[$table][$name] = $col;
  713.  
  714.         }
  715.  
  716.         // Make array with lower case column array names as keys
  717.         $col_lc = array();
  718.         foreach ($this->col[$table] as $name => $def) {
  719.             $name_lc          = strtolower($name);
  720.             $col_lc[$name_lc] = $name;
  721.         }
  722.  
  723.         // Constraints/Indexes
  724.         $DB_indexes = DB_Table_Manager::getIndexes($this->db, $table);
  725.         if (PEAR::isError($DB_indexes)) {
  726.             return $DB_indexes;
  727.         }
  728.  
  729.         // Check that index columns correspond to valid column names.
  730.         // Try to correct problems with capitalization, if necessary.
  731.         foreach ($DB_indexes as $type => $indexes) {
  732.             foreach ($indexes as $name => $fields) {
  733.                 foreach ($fields as $key => $field) {
  734.  
  735.                     // If index column is not a valid column name
  736.                     if (!array_key_exists($field, $this->col[$table])) {
  737.  
  738.                         // Try a case-insensitive match
  739.                         $field_lc = strtolower($field);
  740.                         if (isset($col_lc[$field_lc])) {
  741.                             $correct = $col_lc[$field_lc];
  742.                             $DB_indexes[$type][$name][$key]
  743.                                  = $correct;
  744.                         } else {
  745.                             $code   =  DB_TABLE_GENERATOR_ERR_INDEX_COL;
  746.                             $return =&
  747.                                 DB_Table_Generator::throwError($code, $field);
  748.                         }
  749.  
  750.                     }
  751.                 }
  752.             }
  753.         }
  754.  
  755.         // Generate index definitions, if any, as php code
  756.         $n_idx = 0;
  757.         $u     = array();
  758.  
  759.         $this->idx[$table]         = array();
  760.         $this->primary_key[$table] = null;
  761.         foreach ($DB_indexes as $type => $indexes) {
  762.             if (count($indexes) > 0) {
  763.                 foreach ($indexes as $name => $fields) {
  764.                     $this->idx[$table][$name]         = array();
  765.                     $this->idx[$table][$name]['type'] = $type;
  766.                     if (count($fields) == 1) {
  767.                         $key = $fields[0];
  768.                     } else {
  769.                         $key = array();
  770.                         foreach ($fields as $value) {
  771.                             $key[] = $value;
  772.                         }
  773.                     }
  774.                     $this->idx[$table][$name]['cols'] = $key;
  775.                     if ($type == 'primary') {
  776.                         $this->primary_key[$table] = $key;
  777.                     }
  778.                 }
  779.             }
  780.         }
  781.  
  782.         if ($this->backend == 'mdb2') {
  783.             // Restore original MDB2 'idxname_format' and 'portability'
  784.             $this->db->setOption('idxname_format', $idxname_format);
  785.             $this->db->setOption('portability', $portability);
  786.         }
  787.  
  788.         return true;
  789.     }
  790.  
  791.     // }}}
  792.     // {{{ function buildTableClass($table, $indent = '')
  793.  
  794.     /**
  795.      * Returns one skeleton DB_Table subclass definition, as php code
  796.      *
  797.      * The returned subclass definition string contains values for the
  798.      * $col (column), $idx (index) and $auto_inc_col properties, with
  799.      * no method definitions.
  800.      *
  801.      * @param string $table  name of table
  802.      * @param string $indent string of whitespace for base indentation
  803.      *
  804.      * @return string skeleton DB_Table subclass definition
  805.      * @access public
  806.      */
  807.     function buildTableClass($table, $indent = '')
  808.     {
  809.         $s   = array();
  810.         $idx = array();
  811.         $u   = array();
  812.         $v   = array();
  813.         $l   = 0;
  814.  
  815.         $s[]     = $indent . '/*';
  816.         $s[]     = $indent . ' * Create the table object';
  817.         $s[]     = $indent . ' */';
  818.         $s[]     = $indent . 'class ' . $this->className($table)
  819.                  . " extends {$this->extends} {\n";
  820.         $indent .= '    ';
  821.  
  822.         $s[]     = $indent . '/*';
  823.         $s[]     = $indent . ' * Column definitions';
  824.         $s[]     = $indent . ' */';
  825.         $s[]     = $indent . 'var $col = array(' . "\n";
  826.         $indent .= '    ';
  827.  
  828.         // Begin loop over columns
  829.         foreach ($this->col[$table] as $name => $col) {
  830.  
  831.             // Generate DB_Table column definitions as php code
  832.             $t  = array();
  833.             $t1 = array();
  834.             $l1 = 0;
  835.  
  836.             $name     = $indent . "'{$name}'";
  837.             $l        = max($l, strlen($name));
  838.             $v[$name] = "array(\n";
  839.             $indent  .= '    ';
  840.             foreach ($col as $key => $value) {
  841.                 if (is_string($value)) {
  842.                     $value = "'{$value}'";
  843.                 } elseif (is_bool($value)) {
  844.                     $value = $value ? 'true' : 'false';
  845.                 } else {
  846.                     $value = (string) $value;
  847.                 }
  848.                 $l1   = max($l1, strlen($key) + 2);
  849.                 $t1[] = array("'{$key}'", $value) ;
  850.             }
  851.             foreach ($t1 as $value) {
  852.                 $t[] = $indent . str_pad($value[0], $l1, ' ', STR_PAD_RIGHT)
  853.                      . ' => ' . $value[1];
  854.             }
  855.             $v[$name] .= implode(",\n", $t) . "\n";
  856.             $indent    = substr($indent, 0, -4);
  857.             $v[$name] .= $indent . ')';
  858.         } //end loop over columns
  859.  
  860.         foreach ($v as $key => $value) {
  861.             $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
  862.                  . ' => ' . $value;
  863.         }
  864.         $s[]    = implode(",\n\n", $u) . "\n";
  865.         $indent = substr($indent, 0, -4);
  866.         $s[]    = $indent . ");\n";
  867.  
  868.         // Generate index definitions, if any, as php code
  869.         if (count($this->idx[$table]) > 0) {
  870.             $u = array();
  871.             $v = array();
  872.             $l = 0;
  873.  
  874.             $s[]     = $indent . '/*';
  875.             $s[]     = $indent . ' * Index definitions';
  876.             $s[]     = $indent . ' */';
  877.             $s[]     = $indent . 'var $idx = array(' . "\n";
  878.             $indent .= '    ';
  879.             foreach ($this->idx[$table] as $name => $def) {
  880.                 $type      = $def['type'];
  881.                 $cols      = $def['cols'];
  882.                 $name      = $indent . "'{$name}'";
  883.                 $l         = max($l, strlen($name));
  884.                 $v[$name]  = "array(\n";
  885.                 $indent   .= '    ';
  886.                 $v[$name] .= $indent . "'type' => '{$type}',\n";
  887.                 if (is_array($cols)) {
  888.                     $v[$name] .= $indent . "'cols' => array(\n";
  889.                     $indent   .= '    ';
  890.                     $t         = array();
  891.                     foreach ($cols as $value) {
  892.                         $t[] = $indent . "'{$value}'";
  893.                     }
  894.                     $v[$name] .= implode(",\n", $t) . "\n";
  895.                     $indent    = substr($indent, 0, -4);
  896.                     $v[$name] .= $indent . ")\n";
  897.                 } else {
  898.                     $v[$name] = $v[$name] . $indent . "'cols' => '{$cols}'\n";
  899.                 }
  900.                 $indent    = substr($indent, 0, -4);
  901.                 $v[$name] .= $indent . ")";
  902.             }
  903.  
  904.             foreach ($v as $key => $value) {
  905.                 $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
  906.                      . ' => ' . $value;
  907.             }
  908.             $s[]    = implode(",\n\n", $u) . "\n";
  909.             $indent = substr($indent, 0, -4);
  910.             $s[]    = $indent . ");\n";
  911.         } // end index generation
  912.  
  913.         // Write auto_inc_col
  914.         if (isset($this->auto_inc_col[$table])) {
  915.             $s[] = $indent . '/*';
  916.             $s[] = $indent . ' * Auto-increment declaration';
  917.             $s[] = $indent . ' */';
  918.             $s[] = $indent . 'var $auto_inc_col = '
  919.                            . "'{$this->auto_inc_col[$table]}';\n";
  920.         }
  921.         $indent = substr($indent, 0, -4);
  922.         $s[]    = $indent . '}';
  923.  
  924.         // Implode and return lines of class definition
  925.         return implode("\n", $s) . "\n";
  926.  
  927.     }
  928.  
  929.     // }}}
  930.     // {{{ function buildTableClasses()
  931.  
  932.     /**
  933.      * Returns a string containing all table class definitions in one file
  934.      *
  935.      * The returned string contains the contents of a single php file with
  936.      * definitions of DB_Table subclasses associated with all of the tables
  937.      * in $this->tables. If $this->tables is initially null, method
  938.      * $this->getTableNames() is called internally to generate a list of
  939.      * table names.
  940.      *
  941.      * The returned string includes the opening and closing <?php and ?>
  942.      * script elements, and the require_once line needed to include the
  943.      * $this->extend_class (i.e., DB_Table or a subclass) that is being
  944.      * extended. To use, write this string to a new php file.
  945.      *
  946.      * Usage:
  947.      * <code>
  948.      *     $generator = new DB_Table_Generator($db, $database);
  949.      *     echo $generator->buildTablesClasses();
  950.      * </code>
  951.      *
  952.      * @return mixed a string with all table class definitions,
  953.      *                PEAR Error on failure
  954.      * @access public
  955.      */
  956.     function buildTableClasses()
  957.     {
  958.         // If $this->tables is null, call getTableNames()
  959.         if (!$this->tables) {
  960.             $return = $this->getTableNames();
  961.             if (PEAR::isError($return)) {
  962.                 return $return;
  963.             }
  964.         }
  965.  
  966.         $s   = array();
  967.         $s[] = '<?php';
  968.         $s[] = '/*';
  969.         $s[] = ' * Include basic class';
  970.         $s[] = ' */';
  971.         $s[] = "require_once '{$this->extends_file}';\n";
  972.         foreach ($this->tables as $table) {
  973.             $return = $this->getTableDefinition($table);
  974.             if (PEAR::isError($return)) {
  975.                 return $return;
  976.             }
  977.             $s[] = $this->buildTableClass($table) . "\n";
  978.         }
  979.         $s[] = '?>';
  980.         return implode("\n", $s);
  981.     }
  982.  
  983.     // }}}
  984.     // {{{ function generateTableClassFiles()
  985.  
  986.     /**
  987.      * Writes all table class definitions to separate files
  988.      *
  989.      * Usage:
  990.      * <code>
  991.      *     $generator = new DB_Table_Generator($db, $database);
  992.      *     $generator->generateTableClassFiles();
  993.      * </code>
  994.      *
  995.      * @return mixed true on success, PEAR Error on failure
  996.      * @access public
  997.      */
  998.     function generateTableClassFiles()
  999.     {
  1000.         // If $this->tables is null, call getTableNames()
  1001.         if (!$this->tables) {
  1002.             $return = $this->getTableNames();
  1003.             if (PEAR::isError($return)) {
  1004.                 return $return;
  1005.             }
  1006.         }
  1007.  
  1008.         // Write all table class definitions to separate files
  1009.         foreach ($this->tables as $table) {
  1010.             $classname = $this->className($table);
  1011.             $filename  = $this->classFileName($classname);
  1012.             $base      = $this->class_write_path;
  1013.             if ($base) {
  1014.                 if (!file_exists($base)) {
  1015.                     include_once 'System.php';
  1016.                     if (!@System::mkdir(array('-p', $base))) {
  1017.                         return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
  1018.                             $base);
  1019.                     }
  1020.  
  1021.                 }
  1022.                 $filename = "{$base}/{$filename}";
  1023.             }
  1024.             if (!file_exists($filename)) {
  1025.                 $s      = array();
  1026.                 $s[]    = '<?php';
  1027.                 $s[]    = '/*';
  1028.                 $s[]    = ' * Include basic class';
  1029.                 $s[]    = ' */';
  1030.                 $s[]    = "require_once '{$this->extends_file}';\n";
  1031.                 $return = $this->getTableDefinition($table);
  1032.                 if (PEAR::isError($return)) {
  1033.                     return $return;
  1034.                 }
  1035.                 $s[] = $this->buildTableClass($table);
  1036.                 $s[] = '?>';
  1037.                 $s[] = '';
  1038.                 $out = implode("\n", $s);
  1039.                 if (!$file = @fopen($filename, 'wb')) {
  1040.                     return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
  1041.                             $filename);
  1042.                 }
  1043.                 fputs($file, $out);
  1044.                 fclose($file);
  1045.             }
  1046.         }
  1047.  
  1048.         return true;
  1049.     }
  1050.  
  1051.     // }}}
  1052.     // {{{ function generateDatabaseFile($object_name = null)
  1053.  
  1054.     /**
  1055.      * Writes a file to instantiate Table and Database objects
  1056.      *
  1057.      * After successful completion, a file named 'Database.php' will be
  1058.      * have been created in the $this->class_write_path directory. This
  1059.      * file should normally be included in application php scripts. It
  1060.      * can be renamed by the user.
  1061.      *
  1062.      * Usage:
  1063.      * <code>
  1064.      *     $generator = new DB_Table_Generator($db, $database);
  1065.      *     $generator->generateTableClassFiles();
  1066.      *     $generator->generateDatabaseFile();
  1067.      * </code>
  1068.      *
  1069.      * @param string $object_name variable name for DB_Table_Database object
  1070.      *
  1071.      * @return mixed true on success, PEAR Error on failure
  1072.      * @access public
  1073.      */
  1074.     function generateDatabaseFile($object_name = null)
  1075.     {
  1076.         // Set name for DB_Table_Database object
  1077.         if ($object_name) {
  1078.             $object_name = "\${$object_name}";
  1079.         } else {
  1080.             $object_name = '$db'; //default
  1081.         }
  1082.         $backend = strtoupper($this->backend); // 'DB' or 'MDB2'
  1083.  
  1084.         if ('DB' == $backend) {
  1085.             $dsn = $this->db->dsn;
  1086.         } else {
  1087.             $dsn = $this->db->getDSN('array');
  1088.         }
  1089.  
  1090.         // Create array d[] containing lines of database php file
  1091.         $d   = array();
  1092.         $d[] = '<?php';
  1093.         $d[] = '/*';
  1094.         $d[] = ' * Include basic classes';
  1095.         $d[] = ' */';
  1096.         $d[] = "require_once '{$backend}.php';";
  1097.         $d[] = "require_once 'DB/Table/Database.php';";
  1098.  
  1099.         // Require_once statements for subclass definitions
  1100.         foreach ($this->tables as $table) {
  1101.             $classname      = $this->className($table);
  1102.             $class_filename = $this->classFileName($classname);
  1103.             if ($this->class_include_path) {
  1104.                 $d[] = 'require_once '
  1105.                      . "'{$this->class_include_path}/{$class_filename}';";
  1106.             } else {
  1107.                 $d[] = "require_once '{$class_filename}';";
  1108.             }
  1109.         }
  1110.         $d[] = '';
  1111.  
  1112.         $d[] = '/*';
  1113.         $d[] = ' * NOTE: User must uncomment & edit code to create $dsn';
  1114.         $d[] = ' */';
  1115.         $d[] = "//\$phptype  = '{$dsn['phptype']}';";
  1116.         $d[] = "//\$username = '{$dsn['username']}';";
  1117.         $d[] = "//\$password = ''; // put your password here";
  1118.         $d[] = "//\$hostname = '{$dsn['hostspec']}';";
  1119.         $d[] = "//\$database = '{$dsn['database']}';";
  1120.         $d[] = "//\$create   = false; // 'drop', 'safe', 'verify', 'alter'";
  1121.         $d[] = '//$dsn      = "{$phptype}://{$username}:{$password}@{$hostname}'
  1122.              . '/{$database}";';
  1123.         $d[] = '';
  1124.  
  1125.         $d[] = '/*';
  1126.         $d[] = " * Instantiate {$backend} connection object \$conn";
  1127.         $d[] = ' */';
  1128.         $d[] = "\$conn =& {$backend}::connect(\$dsn);";
  1129.         $d[] = 'if (PEAR::isError($conn)) {';
  1130.         $d[] = '    echo "Error connecting to database server\n";';
  1131.         $d[] = '    echo $conn->getMessage();';
  1132.         $d[] = '    die;';
  1133.         $d[] = '}';
  1134.         $d[] = '';
  1135.  
  1136.         $d[] = '/*';
  1137.         $d[] = ' * Create one instance of each DB_Table subclass';
  1138.         $d[] = ' */';
  1139.         foreach ($this->tables as $table) {
  1140.             $classname = $this->className($table);
  1141.  
  1142.             $d[] = "\${$table} = new {$classname}("
  1143.                  . '$conn, ' . "'{$table}'" . ', $create);';
  1144.             $d[] = "if (PEAR::isError(\${$table}->error)) {";
  1145.             $d[] = '    echo "Can\'t create table object.\n";';
  1146.             $d[] = "    echo \${$table}->error->getMessage();";
  1147.             $d[] = '    die;';
  1148.             $d[] = '}';
  1149.  
  1150.         }
  1151.         $d[] = '';
  1152.  
  1153.         $d[] = '/*';
  1154.         $d[] = ' * Instantiate a parent DB_Table_Database object';
  1155.         $d[] = ' */';
  1156.         $d[] = "{$object_name} = new DB_Table_Database(\$conn, \$database);";
  1157.         $d[] = "if (PEAR::isError({$object_name}->error)) {";
  1158.         $d[] = '    echo "Can\'t create database object.\n";';
  1159.         $d[] = "    echo {$object_name}->error->getMessage();";
  1160.         $d[] = '    die;';
  1161.         $d[] = '}';
  1162.         $d[] = '';
  1163.  
  1164.         $d[] = '/*';
  1165.         $d[] = ' * Add DB_Table objects to parent DB_Table_Database object';
  1166.         $d[] = ' */';
  1167.         foreach ($this->tables as $table) {
  1168.             $classname = $this->className($table);
  1169.  
  1170.             $d[] = "\$result = {$object_name}->addTable(\${$table});";
  1171.             $d[] = 'if (PEAR::isError($result)) {';
  1172.             $d[] = '    echo "Can\'t add table object to database object.\n";';
  1173.             $d[] = '    echo $result->getMessage();';
  1174.             $d[] = '    die;';
  1175.             $d[] = '}';
  1176.         }
  1177.         $d[] = '';
  1178.  
  1179.         // Add foreign key references: If the name of an integer column
  1180.         // matches "/id$/i" (i.e., the names ends with id, ID, or Id), the
  1181.         // remainder of the name matches the name $rtable of another table,
  1182.         // and $rtable has an integer primary key, then the column is
  1183.         // assumed to be a foreign key that references $rtable.
  1184.  
  1185.         $d[] = '/*';
  1186.         $d[] = ' * Add auto-guessed foreign references';
  1187.         $d[] = ' */';
  1188.         foreach ($this->col as $table => $col) {
  1189.             foreach ($col as $col_name => $def) {
  1190.  
  1191.                 // Only consider integer columns
  1192.                 $ftype = $def['type'];
  1193.                 if (!in_array($ftype, array('integer','smallint','bigint'))) {
  1194.                     continue;
  1195.                 }
  1196.                 if (preg_match("/id$/i", $col_name)) {
  1197.                     $column_base = preg_replace('/_?id$/i', '', $col_name);
  1198.                     foreach ($this->tables as $rtable) {
  1199.                         if (!preg_match("/^{$rtable}$/i", $column_base)) {
  1200.                             continue;
  1201.                         }
  1202.                         if (preg_match("/^{$table}$/i", $column_base)) {
  1203.                             continue;
  1204.                         }
  1205.                         if (!isset($this->primary_key[$rtable])) {
  1206.                             continue;
  1207.                         }
  1208.                         $rkey = $this->primary_key[$rtable];
  1209.                         if (is_array($rkey)) {
  1210.                             continue;
  1211.                         }
  1212.                         $rtype = $this->col[$rtable][$rkey]['type'];
  1213.                         if (!in_array($rtype,
  1214.                             array('integer','smallint','bigint'))) {
  1215.                             continue;
  1216.                         }
  1217.                         $d[] = "\$result = {$object_name}->addRef('{$table}', "
  1218.                              . "'{$col_name}', '{$rtable}');";
  1219.                         $d[] = 'if (PEAR::isError($result)) {';
  1220.                         $d[] = '    echo "Can\'t add foreign key reference.\n";';
  1221.                         $d[] = '    echo $result->getMessage();';
  1222.                         $d[] = '    die;';
  1223.                         $d[] = '}';
  1224.                     }
  1225.                 }
  1226.             }
  1227.         }
  1228.         $d[] = '';
  1229.         $d[] = '/*';
  1230.         $d[] = ' * Add any additional foreign key references here';
  1231.         $d[] = ' *';
  1232.         $d[] = ' * Add any linking table declarations here';
  1233.         $d[] = ' * Uncomment next line to add all possible linking tables;';
  1234.         $d[] = ' */';
  1235.         $d[] = "//\$result = {$object_name}->addAllLinks();";
  1236.         $d[] = '//if (PEAR::isError($result)) {';
  1237.         $d[] = '//    echo "Can\'t add linking tables.\n";';
  1238.         $d[] = '//    echo $result->getMessage();';
  1239.         $d[] = '//    die;';
  1240.         $d[] = '//}';
  1241.         $d[] = '';
  1242.  
  1243.         // Closing script element
  1244.         $d[] = '?>';
  1245.         $d[] = '';
  1246.  
  1247.         // Open and write file
  1248.         $base = $this->class_write_path;
  1249.         if ($base) {
  1250.             if (!file_exists($base)) {
  1251.                 include_once 'System.php';
  1252.                 if (!@System::mkdir(array('-p', $base))) {
  1253.                     return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $base);
  1254.                 }
  1255.             }
  1256.             $filename = $base . '/Database.php';
  1257.         } else {
  1258.             $filename = 'Database.php';
  1259.         }
  1260.         if (!$file = @fopen($filename, 'wb')) {
  1261.             return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $filename);
  1262.         }
  1263.         $out = implode("\n", $d);
  1264.         fputs($file, $out);
  1265.         fclose($file);
  1266.  
  1267.         return true;
  1268.     }
  1269.  
  1270.     // }}}
  1271.     // {{{ function className($table)
  1272.  
  1273.     /**
  1274.      * Convert a table name into a class name
  1275.      *
  1276.      * Converts all non-alphanumeric characters to '_', capitalizes
  1277.      * first letter, and adds $this->class_suffix to end. Override
  1278.      * this if you want something else.
  1279.      *
  1280.      * @param string $table name of table
  1281.      *
  1282.      * @return string class name;
  1283.      * @access public
  1284.      */
  1285.     function className($table)
  1286.     {
  1287.         $name = preg_replace('/[^A-Z0-9]/i', '_', ucfirst(trim($table)));
  1288.         return  $name . $this->class_suffix;
  1289.     }
  1290.  
  1291.     // }}}
  1292.     // {{{ function tableName($table)
  1293.  
  1294.     /**
  1295.      * Returns a valid variable name from a table name
  1296.      *
  1297.      * Converts all non-alphanumeric characters to '_'. Override
  1298.      * this if you want something else.
  1299.      *
  1300.      * @param string $table name of table
  1301.      *
  1302.      * @return string variable name;
  1303.      * @access public
  1304.      */
  1305.     function tableName($table)
  1306.     {
  1307.         return preg_replace('/[^A-Z0-9]/i', '_', trim($table));
  1308.     }
  1309.  
  1310.     // }}}
  1311.     // {{{ function classFileName($class_name)
  1312.  
  1313.     /**
  1314.      * Returns the path to a file containing a class definition
  1315.      *
  1316.      * Appends '.php' to class name.
  1317.      *
  1318.      * @param string $class_name name of class
  1319.      *
  1320.      * @return string file name
  1321.      * @access public
  1322.      */
  1323.     function classFileName($class_name)
  1324.     {
  1325.         $filename = $class_name . '.php';
  1326.         return $filename;
  1327.     }
  1328.  
  1329.     // }}}
  1330.  
  1331. }
  1332. // }}}
  1333.