1332 lines
		
	
	
	
		
			44 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1332 lines
		
	
	
	
		
			44 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 | 
						|
 | 
						|
/**
 | 
						|
 * DB_Table_Generator - Generates DB_Table subclass skeleton code
 | 
						|
 * 
 | 
						|
 * Parts of this class were adopted from the DB_DataObject PEAR package.
 | 
						|
 * 
 | 
						|
 * PHP versions 4 and 5
 | 
						|
 *
 | 
						|
 * LICENSE:
 | 
						|
 * 
 | 
						|
 * Copyright (c) 1997-2007, Paul M. Jones <pmjones@php.net>
 | 
						|
 *                          Alan Knowles <alan@akbkhome.com>
 | 
						|
 *                          David C. Morse <morse@php.net>
 | 
						|
 *                          Mark Wiesemann <wiesemann@php.net>
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 *
 | 
						|
 *    * Redistributions of source code must retain the above copyright
 | 
						|
 *      notice, this list of conditions and the following disclaimer.
 | 
						|
 *    * Redistributions in binary form must reproduce the above copyright
 | 
						|
 *      notice, this list of conditions and the following disclaimer in the 
 | 
						|
 *      documentation and/or other materials provided with the distribution.
 | 
						|
 *    * The names of the authors may not be used to endorse or promote products 
 | 
						|
 *      derived from this software without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 | 
						|
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
						|
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
						|
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
						|
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | 
						|
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 *
 | 
						|
 * @category Database
 | 
						|
 * @package  DB_Table
 | 
						|
 * @author   Alan Knowles <alan@akbkhome.com> 
 | 
						|
 * @author   David C. Morse <morse@php.net>
 | 
						|
 * @license  http://opensource.org/licenses/bsd-license.php New BSD License
 | 
						|
 * @version  CVS: $Id: Generator.php,v 1.17 2008/05/14 18:36:27 wiesemann Exp $
 | 
						|
 * @link     http://pear.php.net/package/DB_Table
 | 
						|
 */
 | 
						|
 | 
						|
// {{{ Includes
 | 
						|
 | 
						|
/**#@+
 | 
						|
 * Include basic classes
 | 
						|
 */
 | 
						|
/**
 | 
						|
 * The PEAR class (used for errors)
 | 
						|
 */
 | 
						|
require_once 'PEAR.php';
 | 
						|
 | 
						|
/**
 | 
						|
 * DB_Table table abstraction class
 | 
						|
 */
 | 
						|
require_once 'DB/Table.php';
 | 
						|
 | 
						|
/**
 | 
						|
 * DB_Table_Manager class (used to reverse engineer indices)
 | 
						|
 */
 | 
						|
require_once 'DB/Table/Manager.php';
 | 
						|
/**#@-*/
 | 
						|
 | 
						|
// }}}
 | 
						|
// {{{ Error code constants
 | 
						|
 | 
						|
/**#@+
 | 
						|
 * Error codes
 | 
						|
 */
 | 
						|
/**
 | 
						|
 * Parameter is not a DB/MDB2 object
 | 
						|
 */
 | 
						|
define('DB_TABLE_GENERATOR_ERR_DB_OBJECT', -301);
 | 
						|
 | 
						|
/**
 | 
						|
 * Parameter is not a DB/MDB2 object
 | 
						|
 */
 | 
						|
define('DB_TABLE_GENERATOR_ERR_INDEX_COL', -302);
 | 
						|
 | 
						|
/**
 | 
						|
 * Error while creating file/directory
 | 
						|
 */
 | 
						|
define('DB_TABLE_GENERATOR_ERR_FILE', -303);
 | 
						|
/**#@-*/
 | 
						|
 | 
						|
// }}}
 | 
						|
// {{{ Error messages
 | 
						|
/**
 | 
						|
 * US-English default error messages.
 | 
						|
 */
 | 
						|
$GLOBALS['_DB_TABLE_GENERATOR']['default_error'] = array(
 | 
						|
        DB_TABLE_GENERATOR_ERR_DB_OBJECT =>
 | 
						|
            'Invalid DB/MDB2 object parameter. Function',
 | 
						|
        DB_TABLE_GENERATOR_ERR_INDEX_COL =>
 | 
						|
            'Index column is not a valid column name. Index column',
 | 
						|
        DB_TABLE_GENERATOR_ERR_FILE =>
 | 
						|
            'Can\'t create file/directory:'
 | 
						|
);
 | 
						|
 | 
						|
// merge default and user-defined error messages
 | 
						|
if (!isset($GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
 | 
						|
    $GLOBALS['_DB_TABLE_GENERATOR']['error'] = array();
 | 
						|
}
 | 
						|
foreach ($GLOBALS['_DB_TABLE_GENERATOR']['default_error'] as $code => $message) {
 | 
						|
    if (!array_key_exists($code, $GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
 | 
						|
        $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// }}}
 | 
						|
// {{{ class DB_Table_Generator
 | 
						|
 | 
						|
/**
 | 
						|
 * class DB_Table_Generator - Generates DB_Table subclass skeleton code
 | 
						|
 *
 | 
						|
 * This class generates the php code necessary to use the DB_Table
 | 
						|
 * package to interact with an existing database. This requires the
 | 
						|
 * generation of a skeleton subclass definition be generated for each
 | 
						|
 * table in the database, in which the $col, $idx, and $auto_inc_col
 | 
						|
 * properties are constructed using a table schema that is obtained
 | 
						|
 * by querying the database.
 | 
						|
 *
 | 
						|
 * The class can also generate a file, named 'Database.php' by default,
 | 
						|
 * that includes (require_once) each of the table subclass definitions,
 | 
						|
 * instantiates one object of each DB_Table subclass (i.e., one object
 | 
						|
 * for each table), instantiates a parent DB_Table_Database object,
 | 
						|
 * adds all the tables to that parent, attempts to guess foreign key
 | 
						|
 * relationships between tables based on the column names, and adds
 | 
						|
 * the inferred references to the parent object.
 | 
						|
 *
 | 
						|
 * All of the code is written to a directory whose path is given by
 | 
						|
 * the property $class_write_path. By default, this is the current
 | 
						|
 * directory.  By default, the name of the class constructed for a
 | 
						|
 * table named 'thing' is "Thing_Table". That is, the class name is
 | 
						|
 * the table name, with the first letter upper case, with a suffix
 | 
						|
 * '_Table'.  This suffix can be changed by setting the $class_suffix
 | 
						|
 * property. The file containing a subclass definition is the
 | 
						|
 * subclass name with a php extension, e.g., 'Thing_Table.php'. The
 | 
						|
 * object instantiated from that subclass is the same as the table
 | 
						|
 * name, with no suffix, e.g., 'thing'.
 | 
						|
 *
 | 
						|
 * To generate the code for all of the tables in a database named
 | 
						|
 * $database, instantiate a MDB2 or DB object named $db that connects
 | 
						|
 * to the database of interest, and execute the following code:
 | 
						|
 * <code>
 | 
						|
 *     $generator = new DB_Table_Generator($db, $database);
 | 
						|
 *     $generator->class_write_path = $class_write_path;
 | 
						|
 *     $generator->generateTableClassFiles();
 | 
						|
 *     $generator->generateDatabaseFile();
 | 
						|
 * </code>
 | 
						|
 * Here $class_write_path should be the path (without a trailing
 | 
						|
 * separator) to a directory in which all of the code should be
 | 
						|
 * written. If this directory does not exist, it will be created.
 | 
						|
 * If the directory does already exist, exising files will not
 | 
						|
 * be overwritten. If $class_write_path is not set (i.e., if this
 | 
						|
 * line is omitted) all the code will be written to the current
 | 
						|
 * directory.  If ->generateDatabaseFile() is called, it must be
 | 
						|
 * called after ->generateTableClassFiles().
 | 
						|
 *
 | 
						|
 * By default, ->generateTableClassFiles() and ->generateDatabaseFiles()
 | 
						|
 * generate code for all of the tables in the current database. To
 | 
						|
 * generate code for a specified list of tables, set the value of the
 | 
						|
 * public $tables property to a sequential list of table names before
 | 
						|
 * calling either of these methods. Code can be generated for three
 | 
						|
 * tables named 'table1', 'table2', and 'table3' as follows:
 | 
						|
 * <code>
 | 
						|
 *     $generator = new DB_Table_Generator($db, $database);
 | 
						|
 *     $generator->class_write_path = $class_write_path;
 | 
						|
 *     $generator->tables = array('table1', 'table2', 'table3');
 | 
						|
 *     $generator->generateTableClassFiles();
 | 
						|
 *     $generator->generateDatabaseFile();
 | 
						|
 * </code>
 | 
						|
 * If the $tables property is not set to a non-null value prior
 | 
						|
 * to calling ->generateTableClassFiles() then, by default, the
 | 
						|
 * database is queried for a list of all table names, by calling the
 | 
						|
 * ->getTableNames() method from within ->generateTableClassFiles().
 | 
						|
 *
 | 
						|
 * PHP version 4 and 5
 | 
						|
 *
 | 
						|
 * @category Database
 | 
						|
 * @package  DB_Table
 | 
						|
 * @author   Alan Knowles <alan@akbkhome.com> 
 | 
						|
 * @author   David C. Morse <morse@php.net>
 | 
						|
 * @license  http://www.gnu.org/copyleft/lesser.html LGPL
 | 
						|
 * @version  Release: 1.5.6
 | 
						|
 * @link     http://pear.php.net/package/DB_Table
 | 
						|
 */
 | 
						|
class DB_Table_Generator
 | 
						|
{
 | 
						|
 | 
						|
    // {{{ Properties
 | 
						|
 | 
						|
    /**
 | 
						|
     * Name of the database
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $name = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The PEAR DB/MDB2 object that connects to the database.
 | 
						|
     *
 | 
						|
     * @var object
 | 
						|
     * @access private
 | 
						|
     */
 | 
						|
    var $db = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The backend type. May have values 'db' or 'mdb2'
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access private
 | 
						|
     */
 | 
						|
    var $backend = null;
 | 
						|
 | 
						|
    /**
 | 
						|
    * If there is an error on instantiation, this captures that error.
 | 
						|
    *
 | 
						|
    * This property is used only for errors encountered in the constructor
 | 
						|
    * at instantiation time.  To check if there was an instantiation error...
 | 
						|
    *
 | 
						|
    * <code>
 | 
						|
    *     $obj =& new DB_Table_Generator();
 | 
						|
    *     if ($obj->error) {
 | 
						|
    *         // ... error handling code here ...
 | 
						|
    *     }
 | 
						|
    * </code>
 | 
						|
    *
 | 
						|
    * @var object PEAR_Error
 | 
						|
    * @access public
 | 
						|
    */
 | 
						|
    var $error = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Numerical array of table name strings
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $tables = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Class being extended (DB_Table or generic subclass)
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $extends = 'DB_Table';
 | 
						|
 | 
						|
    /**
 | 
						|
     * Path to definition of the class $this->extends
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $extends_file = 'DB/Table.php';
 | 
						|
 | 
						|
    /**
 | 
						|
     * Suffix to add to table names to obtain corresponding class names
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $class_suffix = "_Table";
 | 
						|
 | 
						|
    /**
 | 
						|
     * Path to directory in which subclass definitions should be written
 | 
						|
     *
 | 
						|
     * Value should not include a trailing "/".
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $class_write_path = '';
 | 
						|
 | 
						|
    /**
 | 
						|
     * Include path to subclass definition files from database file
 | 
						|
     *
 | 
						|
     * Used to create require_once statements in the Database.php file,
 | 
						|
     * which is in the same directory as the class definition files. Leave
 | 
						|
     * as empty string if your PHP include_path contains ".". The value
 | 
						|
     * should not include a trailing "/", which is added automatically
 | 
						|
     * to values other than the empty string.
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $class_include_path = '';
 | 
						|
 | 
						|
    /**
 | 
						|
     * Array of column definitions
 | 
						|
     *
 | 
						|
     * Array $this->col[table_name][column_name] = column definition.
 | 
						|
     * Column definition is an array with the same format as the $col
 | 
						|
     * property of a DB_Table object
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $col = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Array of index/constraint definitions.
 | 
						|
     *
 | 
						|
     * Array $this->idx[table_table][index_name] = Index definition.
 | 
						|
     * The index definition is an array with the same format as the
 | 
						|
     * DB_Table $idx property property array.
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
     var $idx = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Array of auto_increment column names
 | 
						|
     *
 | 
						|
     * Array $this->auto_inc_col[table_name] = auto-increment column
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
     var $auto_inc_col = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Array of primary keys
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
     var $primary_key = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * MDB2 'idxname_format' option, format of index names
 | 
						|
     *
 | 
						|
     * For use in printf() formatting. Use '%s' to use index names as
 | 
						|
     * returned by getTableConstraints/Indexes, and '%s_idx' to add an
 | 
						|
     * '_idx' suffix. For MySQL, use the default value '%'.
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    var $idxname_format = '%s';
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function DB_Table_Generator(&$db, $name)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     *
 | 
						|
     * If an error is encountered during instantiation, the error
 | 
						|
     * message is stored in the $this->error property of the resulting
 | 
						|
     * object. See $error property docblock for a discussion of error
 | 
						|
     * handling.
 | 
						|
     *
 | 
						|
     * @param object &$db  DB/MDB2 database connection object
 | 
						|
     * @param string $name database name string
 | 
						|
     *
 | 
						|
     * @return object DB_Table_Generator
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function __construct(&$db, $name)
 | 
						|
    {
 | 
						|
        // Is $db an DB/MDB2 object or null?
 | 
						|
        if (is_a($db, 'db_common')) {
 | 
						|
            $this->backend = 'db';
 | 
						|
        } elseif (is_a($db, 'mdb2_driver_common')) {
 | 
						|
            $this->backend = 'mdb2';
 | 
						|
        } else {
 | 
						|
            $this->error =&
 | 
						|
                DB_Table_Generator::throwError(DB_TABLE_GENERATOR_ERR_DB_OBJECT,
 | 
						|
                'DB_Table_Generator');
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        $this->db   =& $db;
 | 
						|
        $this->name =  $name;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function &throwError($code, $extra = null)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specialized version of throwError() modeled on PEAR_Error.
 | 
						|
     *
 | 
						|
     * Throws a PEAR_Error with a DB_Table_Generator error message based
 | 
						|
     * on a DB_Table_Generator constant error code.
 | 
						|
     *
 | 
						|
     * @param string $code  A DB_Table_Generator error code constant.
 | 
						|
     * @param string $extra Extra text for the error (in addition to the
 | 
						|
     *                       regular error message).
 | 
						|
     *
 | 
						|
     * @return object PEAR_Error
 | 
						|
     * @access public
 | 
						|
     * @static
 | 
						|
     */
 | 
						|
    function &throwError($code, $extra = null)
 | 
						|
    {
 | 
						|
        // get the error message text based on the error code
 | 
						|
        $text = 'DB_TABLE_GENERATOR ERROR - ' . "\n"
 | 
						|
              . $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code];
 | 
						|
 | 
						|
        // add any additional error text
 | 
						|
        if ($extra) {
 | 
						|
            $text .= ' ' . $extra;
 | 
						|
        }
 | 
						|
 | 
						|
        // done!
 | 
						|
        $error = PEAR::throwError($text, $code);
 | 
						|
        return $error;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function setErrorMessage($code, $message = null)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Overwrites one or more error messages, e.g., to internationalize them.
 | 
						|
     *
 | 
						|
     * @param mixed  $code    If string, the error message with code $code will be
 | 
						|
     *                        overwritten by $message. If array, each key is a
 | 
						|
     *                        code and each value is a new message.
 | 
						|
     * @param string $message Only used if $key is not an array.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function setErrorMessage($code, $message = null)
 | 
						|
    {
 | 
						|
        if (is_array($code)) {
 | 
						|
            foreach ($code as $single_code => $single_message) {
 | 
						|
                $GLOBALS['_DB_TABLE_GENERATOR']['error'][$single_code]
 | 
						|
                    = $single_message;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function getTableNames()
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets a list of tables from the database
 | 
						|
     *
 | 
						|
     * Upon successful completion, names are stored in the $this->tables
 | 
						|
     * array. If an error is encountered, a PEAR Error is returned, and
 | 
						|
     * $this->tables is reset to null.
 | 
						|
     *
 | 
						|
     * @return mixed true on success, PEAR Error on failure
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function getTableNames()
 | 
						|
    {
 | 
						|
 | 
						|
        if ($this->backend == 'db') {
 | 
						|
            // try getting a list of schema tables first. (postgres)
 | 
						|
            $this->db->expectError(DB_ERROR_UNSUPPORTED);
 | 
						|
            $this->tables = $this->db->getListOf('schema.tables');
 | 
						|
            $this->db->popExpect();
 | 
						|
            if (PEAR::isError($this->tables)) {
 | 
						|
                // try a list of tables, not qualified by 'schema'
 | 
						|
                $this->db->expectError(DB_ERROR_UNSUPPORTED);
 | 
						|
                $this->tables = $this->db->getListOf('tables');
 | 
						|
                $this->db->popExpect();
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            // Temporarily change 'portability' MDB2 option
 | 
						|
            $portability = $this->db->getOption('portability');
 | 
						|
            $this->db->setOption('portability',
 | 
						|
                MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
 | 
						|
 | 
						|
            $this->db->loadModule('Manager');
 | 
						|
            $this->db->loadModule('Reverse');
 | 
						|
 | 
						|
            // Get list of tables
 | 
						|
            $this->tables = $this->db->manager->listTables();
 | 
						|
 | 
						|
            // Restore original MDB2 'portability'
 | 
						|
            $this->db->setOption('portability', $portability);
 | 
						|
        }
 | 
						|
        if (PEAR::isError($this->tables)) {
 | 
						|
            $error        = $this->tables;
 | 
						|
            $this->tables = null;
 | 
						|
            return $error;
 | 
						|
        } else {
 | 
						|
            $this->tables = array_map(array($this, 'tableName'),
 | 
						|
                                      $this->tables);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function getTableDefinition($table)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets column and index definitions by querying database
 | 
						|
     *
 | 
						|
     * Upon return, column definitions are stored in $this->col[$table],
 | 
						|
     * and index definitions in $this->idx[$table].
 | 
						|
     *
 | 
						|
     * Calls DB/MDB2::tableInfo() for column definitions, and uses
 | 
						|
     * the DB_Table_Manager class to obtain index definitions.
 | 
						|
     *
 | 
						|
     * @param string $table name of table
 | 
						|
     *
 | 
						|
     * @return mixed true on success, PEAR Error on failure
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function getTableDefinition($table)
 | 
						|
    {
 | 
						|
        /*
 | 
						|
        // postgres strip the schema bit from the
 | 
						|
        if (!empty($options['generator_strip_schema'])) {
 | 
						|
            $bits = explode('.', $table,2);
 | 
						|
            $table = $bits[0];
 | 
						|
            if (count($bits) > 1) {
 | 
						|
                $table = $bits[1];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        */
 | 
						|
 | 
						|
        if ($this->backend == 'db') {
 | 
						|
 | 
						|
            $defs = $this->db->tableInfo($table);
 | 
						|
            if (PEAR::isError($defs)) {
 | 
						|
                return $defs;
 | 
						|
            }
 | 
						|
            $this->columns[$table] = $defs;
 | 
						|
 | 
						|
        } else {
 | 
						|
 | 
						|
            // Temporarily change 'portability' MDB2 option
 | 
						|
            $portability = $this->db->getOption('portability');
 | 
						|
            $this->db->setOption('portability',
 | 
						|
                MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
 | 
						|
 | 
						|
            $this->db->loadModule('Manager');
 | 
						|
            $this->db->loadModule('Reverse');
 | 
						|
 | 
						|
            // Columns
 | 
						|
            $defs = $this->db->reverse->tableInfo($table);
 | 
						|
            if (PEAR::isError($defs)) {
 | 
						|
                return $defs;
 | 
						|
            }
 | 
						|
 | 
						|
            // rename the 'length' key, so it matches db's return.
 | 
						|
            foreach ($defs as $k => $v) {
 | 
						|
                if (isset($defs[$k]['length'])) {
 | 
						|
                    $defs[$k]['len'] = $defs[$k]['length'];
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            $this->columns[$table] = $defs;
 | 
						|
 | 
						|
            // Temporarily set 'idxname_format' MDB2 option to $this->idx_format
 | 
						|
            $idxname_format = $this->db->getOption('idxname_format');
 | 
						|
            $this->db->setOption('idxname_format', $this->idxname_format);
 | 
						|
        }
 | 
						|
 | 
						|
        // Default - no auto increment column
 | 
						|
        $this->auto_inc_col[$table] = null;
 | 
						|
 | 
						|
        // Loop over columns to create $this->col[$table]
 | 
						|
        $this->col[$table] = array();
 | 
						|
        foreach ($defs as $t) {
 | 
						|
 | 
						|
            $name = $t['name'];
 | 
						|
            $col  = array();
 | 
						|
 | 
						|
            switch (strtoupper($t['type'])) {
 | 
						|
            case 'INT2':     // postgres
 | 
						|
            case 'TINYINT':
 | 
						|
            case 'TINY':     //mysql
 | 
						|
            case 'SMALLINT':
 | 
						|
                $col['type'] = 'smallint';
 | 
						|
                break;
 | 
						|
            case 'INT4':      // postgres
 | 
						|
            case 'SERIAL4':   // postgres
 | 
						|
            case 'INT':
 | 
						|
            case 'SHORT':     // mysql
 | 
						|
            case 'INTEGER':
 | 
						|
            case 'MEDIUMINT':
 | 
						|
            case 'YEAR':
 | 
						|
                $col['type'] = 'integer';
 | 
						|
                break;
 | 
						|
            case 'BIGINT':
 | 
						|
            case 'LONG':    // mysql
 | 
						|
            case 'INT8':    // postgres
 | 
						|
            case 'SERIAL8': // postgres
 | 
						|
                $col['type'] = 'bigint';
 | 
						|
                break;
 | 
						|
            case 'REAL':
 | 
						|
            case 'NUMERIC':
 | 
						|
            case 'NUMBER': // oci8
 | 
						|
            case 'FLOAT':  // mysql
 | 
						|
            case 'FLOAT4': // real (postgres)
 | 
						|
                $col['type'] = 'single';
 | 
						|
                break;
 | 
						|
            case 'DOUBLE':
 | 
						|
            case 'DOUBLE PRECISION': // double precision (firebird)
 | 
						|
            case 'FLOAT8':           // double precision (postgres)
 | 
						|
                $col['type'] = 'double';
 | 
						|
                break;
 | 
						|
            case 'DECIMAL':
 | 
						|
            case 'MONEY':   // mssql and maybe others
 | 
						|
                $col['type'] = 'decimal';
 | 
						|
                break;
 | 
						|
            case 'BIT':
 | 
						|
            case 'BOOL':
 | 
						|
            case 'BOOLEAN':
 | 
						|
                $col['type'] = 'boolean';
 | 
						|
                break;
 | 
						|
            case 'STRING':
 | 
						|
            case 'CHAR':
 | 
						|
                $col['type'] = 'char';
 | 
						|
                break;
 | 
						|
            case 'VARCHAR':
 | 
						|
            case 'VARCHAR2':
 | 
						|
            case 'TINYTEXT':
 | 
						|
                $col['type'] = 'varchar';
 | 
						|
                break;
 | 
						|
            case 'TEXT':
 | 
						|
            case 'MEDIUMTEXT':
 | 
						|
            case 'LONGTEXT':
 | 
						|
                $col['type'] = 'clob';
 | 
						|
                break;
 | 
						|
            case 'DATE':
 | 
						|
                $col['type'] = 'date';
 | 
						|
                break;
 | 
						|
            case 'TIME':
 | 
						|
                $col['type'] = 'time';
 | 
						|
                break;
 | 
						|
            case 'DATETIME':  // mysql
 | 
						|
            case 'TIMESTAMP':
 | 
						|
                $col['type'] = 'timestamp';
 | 
						|
                break;
 | 
						|
            case 'ENUM':
 | 
						|
            case 'SET':         // not really but oh well
 | 
						|
            case 'TIMESTAMPTZ': // postgres
 | 
						|
            case 'BPCHAR':      // postgres
 | 
						|
            case 'INTERVAL':    // postgres (eg. '12 days')
 | 
						|
            case 'CIDR':        // postgres IP net spec
 | 
						|
            case 'INET':        // postgres IP
 | 
						|
            case 'MACADDR':     // postgress network Mac address.
 | 
						|
            case 'INTEGER[]':   // postgres type
 | 
						|
            case 'BOOLEAN[]':   // postgres type
 | 
						|
                $col['type'] = 'varchar';
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                $col['type'] = $t['type'] . ' (Unknown type)';
 | 
						|
                break;
 | 
						|
            }
 | 
						|
 | 
						|
            // Set length and scope if required
 | 
						|
            if (in_array($col['type'], array('char','varchar','decimal'))) {
 | 
						|
                if (isset($t['len'])) {
 | 
						|
                    $col['size'] = (int) $t['len'];
 | 
						|
                } elseif ($col['type'] == 'varchar') {
 | 
						|
                    $col['size'] = 255; // default length
 | 
						|
                } elseif ($col['type'] == 'char') {
 | 
						|
                    $col['size'] = 128; // default length
 | 
						|
                } elseif ($col['type'] == 'decimal') {
 | 
						|
                    $col['size'] = 15; // default length
 | 
						|
                }
 | 
						|
                if ($col['type'] == 'decimal') {
 | 
						|
                    $col['scope'] = 2;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (isset($t['notnull'])) {
 | 
						|
                if ($t['notnull']) {
 | 
						|
                    $col['require'] = true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (isset($t['autoincrement'])) {
 | 
						|
                $this->auto_inc_col[$table] = $name;
 | 
						|
            }
 | 
						|
            if (isset($t['flags'])) {
 | 
						|
                $flags = $t['flags'];
 | 
						|
                if (preg_match('/not[ _]null/i', $flags)) {
 | 
						|
                    $col['require'] = true;
 | 
						|
                }
 | 
						|
                if (preg_match("/(auto_increment|nextval\()/i", $flags)) {
 | 
						|
                    $this->auto_inc_col[$table] = $name;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $require = isset($col['require']) ? $col['require'] : false;
 | 
						|
            if ($require) {
 | 
						|
                if (isset($t['default'])) {
 | 
						|
                    $default = $t['default'];
 | 
						|
                    $type    = $col['type'];
 | 
						|
                    if (in_array($type,
 | 
						|
                                 array('smallint', 'integer', 'bigint'))) {
 | 
						|
                        $default = (int) $default;
 | 
						|
                    } elseif (in_array($type, array('single', 'double'))) {
 | 
						|
                        $default = (float) $default;
 | 
						|
                    } elseif ($type == 'boolean') {
 | 
						|
                        $default = (int) $default ? 1 : 0;
 | 
						|
                    }
 | 
						|
                    $col['default'] = $default;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $this->col[$table][$name] = $col;
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        // Make array with lower case column array names as keys
 | 
						|
        $col_lc = array();
 | 
						|
        foreach ($this->col[$table] as $name => $def) {
 | 
						|
            $name_lc          = strtolower($name);
 | 
						|
            $col_lc[$name_lc] = $name;
 | 
						|
        }
 | 
						|
 | 
						|
        // Constraints/Indexes
 | 
						|
        $DB_indexes = DB_Table_Manager::getIndexes($this->db, $table);
 | 
						|
        if (PEAR::isError($DB_indexes)) {
 | 
						|
            return $DB_indexes;
 | 
						|
        }
 | 
						|
 | 
						|
        // Check that index columns correspond to valid column names.
 | 
						|
        // Try to correct problems with capitalization, if necessary.
 | 
						|
        foreach ($DB_indexes as $type => $indexes) {
 | 
						|
            foreach ($indexes as $name => $fields) {
 | 
						|
                foreach ($fields as $key => $field) {
 | 
						|
 | 
						|
                    // If index column is not a valid column name
 | 
						|
                    if (!array_key_exists($field, $this->col[$table])) {
 | 
						|
 | 
						|
                        // Try a case-insensitive match
 | 
						|
                        $field_lc = strtolower($field);
 | 
						|
                        if (isset($col_lc[$field_lc])) {
 | 
						|
                            $correct = $col_lc[$field_lc];
 | 
						|
                            $DB_indexes[$type][$name][$key]
 | 
						|
                                 = $correct;
 | 
						|
                        } else {
 | 
						|
                            $code   =  DB_TABLE_GENERATOR_ERR_INDEX_COL;
 | 
						|
                            $return =&
 | 
						|
                                DB_Table_Generator::throwError($code, $field);
 | 
						|
                        }
 | 
						|
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Generate index definitions, if any, as php code
 | 
						|
        $n_idx = 0;
 | 
						|
        $u     = array();
 | 
						|
 | 
						|
        $this->idx[$table]         = array();
 | 
						|
        $this->primary_key[$table] = null;
 | 
						|
        foreach ($DB_indexes as $type => $indexes) {
 | 
						|
            if (count($indexes) > 0) {
 | 
						|
                foreach ($indexes as $name => $fields) {
 | 
						|
                    $this->idx[$table][$name]         = array();
 | 
						|
                    $this->idx[$table][$name]['type'] = $type;
 | 
						|
                    if (count($fields) == 1) {
 | 
						|
                        $key = $fields[0];
 | 
						|
                    } else {
 | 
						|
                        $key = array();
 | 
						|
                        foreach ($fields as $value) {
 | 
						|
                            $key[] = $value;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    $this->idx[$table][$name]['cols'] = $key;
 | 
						|
                    if ($type == 'primary') {
 | 
						|
                        $this->primary_key[$table] = $key;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($this->backend == 'mdb2') {
 | 
						|
            // Restore original MDB2 'idxname_format' and 'portability'
 | 
						|
            $this->db->setOption('idxname_format', $idxname_format);
 | 
						|
            $this->db->setOption('portability', $portability);
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function buildTableClass($table, $indent = '')
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns one skeleton DB_Table subclass definition, as php code
 | 
						|
     *
 | 
						|
     * The returned subclass definition string contains values for the
 | 
						|
     * $col (column), $idx (index) and $auto_inc_col properties, with
 | 
						|
     * no method definitions.
 | 
						|
     *
 | 
						|
     * @param string $table  name of table
 | 
						|
     * @param string $indent string of whitespace for base indentation
 | 
						|
     *
 | 
						|
     * @return string skeleton DB_Table subclass definition
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function buildTableClass($table, $indent = '')
 | 
						|
    {
 | 
						|
        $s   = array();
 | 
						|
        $idx = array();
 | 
						|
        $u   = array();
 | 
						|
        $v   = array();
 | 
						|
        $l   = 0;
 | 
						|
 | 
						|
        $s[]     = $indent . '/*';
 | 
						|
        $s[]     = $indent . ' * Create the table object';
 | 
						|
        $s[]     = $indent . ' */';
 | 
						|
        $s[]     = $indent . 'class ' . $this->className($table)
 | 
						|
                 . " extends {$this->extends} {\n";
 | 
						|
        $indent .= '    ';
 | 
						|
 | 
						|
        $s[]     = $indent . '/*';
 | 
						|
        $s[]     = $indent . ' * Column definitions';
 | 
						|
        $s[]     = $indent . ' */';
 | 
						|
        $s[]     = $indent . 'var $col = array(' . "\n";
 | 
						|
        $indent .= '    ';
 | 
						|
 | 
						|
        // Begin loop over columns
 | 
						|
        foreach ($this->col[$table] as $name => $col) {
 | 
						|
 | 
						|
            // Generate DB_Table column definitions as php code
 | 
						|
            $t  = array();
 | 
						|
            $t1 = array();
 | 
						|
            $l1 = 0;
 | 
						|
 | 
						|
            $name     = $indent . "'{$name}'";
 | 
						|
            $l        = max($l, strlen($name));
 | 
						|
            $v[$name] = "array(\n";
 | 
						|
            $indent  .= '    ';
 | 
						|
            foreach ($col as $key => $value) {
 | 
						|
                if (is_string($value)) {
 | 
						|
                    $value = "'{$value}'";
 | 
						|
                } elseif (is_bool($value)) {
 | 
						|
                    $value = $value ? 'true' : 'false';
 | 
						|
                } else {
 | 
						|
                    $value = (string) $value;
 | 
						|
                }
 | 
						|
                $l1   = max($l1, strlen($key) + 2);
 | 
						|
                $t1[] = array("'{$key}'", $value) ;
 | 
						|
            }
 | 
						|
            foreach ($t1 as $value) {
 | 
						|
                $t[] = $indent . str_pad($value[0], $l1, ' ', STR_PAD_RIGHT)
 | 
						|
                     . ' => ' . $value[1];
 | 
						|
            }
 | 
						|
            $v[$name] .= implode(",\n", $t) . "\n";
 | 
						|
            $indent    = substr($indent, 0, -4);
 | 
						|
            $v[$name] .= $indent . ')';
 | 
						|
        } //end loop over columns
 | 
						|
 | 
						|
        foreach ($v as $key => $value) {
 | 
						|
            $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
 | 
						|
                 . ' => ' . $value;
 | 
						|
        }
 | 
						|
        $s[]    = implode(",\n\n", $u) . "\n";
 | 
						|
        $indent = substr($indent, 0, -4);
 | 
						|
        $s[]    = $indent . ");\n";
 | 
						|
 | 
						|
        // Generate index definitions, if any, as php code
 | 
						|
        if (count($this->idx[$table]) > 0) {
 | 
						|
            $u = array();
 | 
						|
            $v = array();
 | 
						|
            $l = 0;
 | 
						|
 | 
						|
            $s[]     = $indent . '/*';
 | 
						|
            $s[]     = $indent . ' * Index definitions';
 | 
						|
            $s[]     = $indent . ' */';
 | 
						|
            $s[]     = $indent . 'var $idx = array(' . "\n";
 | 
						|
            $indent .= '    ';
 | 
						|
            foreach ($this->idx[$table] as $name => $def) {
 | 
						|
                $type      = $def['type'];
 | 
						|
                $cols      = $def['cols'];
 | 
						|
                $name      = $indent . "'{$name}'";
 | 
						|
                $l         = max($l, strlen($name));
 | 
						|
                $v[$name]  = "array(\n";
 | 
						|
                $indent   .= '    ';
 | 
						|
                $v[$name] .= $indent . "'type' => '{$type}',\n";
 | 
						|
                if (is_array($cols)) {
 | 
						|
                    $v[$name] .= $indent . "'cols' => array(\n";
 | 
						|
                    $indent   .= '    ';
 | 
						|
                    $t         = array();
 | 
						|
                    foreach ($cols as $value) {
 | 
						|
                        $t[] = $indent . "'{$value}'";
 | 
						|
                    }
 | 
						|
                    $v[$name] .= implode(",\n", $t) . "\n";
 | 
						|
                    $indent    = substr($indent, 0, -4);
 | 
						|
                    $v[$name] .= $indent . ")\n";
 | 
						|
                } else {
 | 
						|
                    $v[$name] = $v[$name] . $indent . "'cols' => '{$cols}'\n";
 | 
						|
                }
 | 
						|
                $indent    = substr($indent, 0, -4);
 | 
						|
                $v[$name] .= $indent . ")";
 | 
						|
            }
 | 
						|
 | 
						|
            foreach ($v as $key => $value) {
 | 
						|
                $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
 | 
						|
                     . ' => ' . $value;
 | 
						|
            }
 | 
						|
            $s[]    = implode(",\n\n", $u) . "\n";
 | 
						|
            $indent = substr($indent, 0, -4);
 | 
						|
            $s[]    = $indent . ");\n";
 | 
						|
        } // end index generation
 | 
						|
 | 
						|
        // Write auto_inc_col
 | 
						|
        if (isset($this->auto_inc_col[$table])) {
 | 
						|
            $s[] = $indent . '/*';
 | 
						|
            $s[] = $indent . ' * Auto-increment declaration';
 | 
						|
            $s[] = $indent . ' */';
 | 
						|
            $s[] = $indent . 'var $auto_inc_col = '
 | 
						|
                           . "'{$this->auto_inc_col[$table]}';\n";
 | 
						|
        }
 | 
						|
        $indent = substr($indent, 0, -4);
 | 
						|
        $s[]    = $indent . '}';
 | 
						|
 | 
						|
        // Implode and return lines of class definition
 | 
						|
        return implode("\n", $s) . "\n";
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function buildTableClasses()
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a string containing all table class definitions in one file
 | 
						|
     *
 | 
						|
     * The returned string contains the contents of a single php file with
 | 
						|
     * definitions of DB_Table subclasses associated with all of the tables
 | 
						|
     * in $this->tables. If $this->tables is initially null, method
 | 
						|
     * $this->getTableNames() is called internally to generate a list of
 | 
						|
     * table names.
 | 
						|
     *
 | 
						|
     * The returned string includes the opening and closing <?php and ?>
 | 
						|
     * script elements, and the require_once line needed to include the
 | 
						|
     * $this->extend_class (i.e., DB_Table or a subclass) that is being
 | 
						|
     * extended. To use, write this string to a new php file.
 | 
						|
     *
 | 
						|
     * Usage:
 | 
						|
     * <code>
 | 
						|
     *     $generator = new DB_Table_Generator($db, $database);
 | 
						|
     *     echo $generator->buildTablesClasses();
 | 
						|
     * </code>
 | 
						|
     *
 | 
						|
     * @return mixed a string with all table class definitions,
 | 
						|
     *                PEAR Error on failure
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function buildTableClasses()
 | 
						|
    {
 | 
						|
        // If $this->tables is null, call getTableNames()
 | 
						|
        if (!$this->tables) {
 | 
						|
            $return = $this->getTableNames();
 | 
						|
            if (PEAR::isError($return)) {
 | 
						|
                return $return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $s   = array();
 | 
						|
        $s[] = '<?php';
 | 
						|
        $s[] = '/*';
 | 
						|
        $s[] = ' * Include basic class';
 | 
						|
        $s[] = ' */';
 | 
						|
        $s[] = "require_once '{$this->extends_file}';\n";
 | 
						|
        foreach ($this->tables as $table) {
 | 
						|
            $return = $this->getTableDefinition($table);
 | 
						|
            if (PEAR::isError($return)) {
 | 
						|
                return $return;
 | 
						|
            }
 | 
						|
            $s[] = $this->buildTableClass($table) . "\n";
 | 
						|
        }
 | 
						|
        $s[] = '?>';
 | 
						|
        return implode("\n", $s);
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function generateTableClassFiles()
 | 
						|
 | 
						|
    /**
 | 
						|
     * Writes all table class definitions to separate files
 | 
						|
     *
 | 
						|
     * Usage:
 | 
						|
     * <code>
 | 
						|
     *     $generator = new DB_Table_Generator($db, $database);
 | 
						|
     *     $generator->generateTableClassFiles();
 | 
						|
     * </code>
 | 
						|
     *
 | 
						|
     * @return mixed true on success, PEAR Error on failure
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function generateTableClassFiles()
 | 
						|
    {
 | 
						|
        // If $this->tables is null, call getTableNames()
 | 
						|
        if (!$this->tables) {
 | 
						|
            $return = $this->getTableNames();
 | 
						|
            if (PEAR::isError($return)) {
 | 
						|
                return $return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Write all table class definitions to separate files
 | 
						|
        foreach ($this->tables as $table) {
 | 
						|
            $classname = $this->className($table);
 | 
						|
            $filename  = $this->classFileName($classname);
 | 
						|
            $base      = $this->class_write_path;
 | 
						|
            if ($base) {
 | 
						|
                if (!file_exists($base)) {
 | 
						|
                    include_once 'System.php';
 | 
						|
                    if (!@System::mkdir(array('-p', $base))) {
 | 
						|
                        return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
 | 
						|
                            $base);
 | 
						|
                    }
 | 
						|
 | 
						|
                }
 | 
						|
                $filename = "{$base}/{$filename}";
 | 
						|
            }
 | 
						|
            if (!file_exists($filename)) {
 | 
						|
                $s      = array();
 | 
						|
                $s[]    = '<?php';
 | 
						|
                $s[]    = '/*';
 | 
						|
                $s[]    = ' * Include basic class';
 | 
						|
                $s[]    = ' */';
 | 
						|
                $s[]    = "require_once '{$this->extends_file}';\n";
 | 
						|
                $return = $this->getTableDefinition($table);
 | 
						|
                if (PEAR::isError($return)) {
 | 
						|
                    return $return;
 | 
						|
                }
 | 
						|
                $s[] = $this->buildTableClass($table);
 | 
						|
                $s[] = '?>';
 | 
						|
                $s[] = '';
 | 
						|
                $out = implode("\n", $s);
 | 
						|
                if (!$file = @fopen($filename, 'wb')) {
 | 
						|
                    return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
 | 
						|
                            $filename);
 | 
						|
                }
 | 
						|
                fputs($file, $out);
 | 
						|
                fclose($file);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function generateDatabaseFile($object_name = null)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Writes a file to instantiate Table and Database objects
 | 
						|
     *
 | 
						|
     * After successful completion, a file named 'Database.php' will be
 | 
						|
     * have been created in the $this->class_write_path directory. This
 | 
						|
     * file should normally be included in application php scripts. It
 | 
						|
     * can be renamed by the user.
 | 
						|
     *
 | 
						|
     * Usage:
 | 
						|
     * <code>
 | 
						|
     *     $generator = new DB_Table_Generator($db, $database);
 | 
						|
     *     $generator->generateTableClassFiles();
 | 
						|
     *     $generator->generateDatabaseFile();
 | 
						|
     * </code>
 | 
						|
     *
 | 
						|
     * @param string $object_name variable name for DB_Table_Database object
 | 
						|
     *
 | 
						|
     * @return mixed true on success, PEAR Error on failure
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function generateDatabaseFile($object_name = null)
 | 
						|
    {
 | 
						|
        // Set name for DB_Table_Database object
 | 
						|
        if ($object_name) {
 | 
						|
            $object_name = "\${$object_name}";
 | 
						|
        } else {
 | 
						|
            $object_name = '$db'; //default
 | 
						|
        }
 | 
						|
        $backend = strtoupper($this->backend); // 'DB' or 'MDB2'
 | 
						|
 | 
						|
        if ('DB' == $backend) {
 | 
						|
            $dsn = $this->db->dsn;
 | 
						|
        } else {
 | 
						|
            $dsn = $this->db->getDSN('array');
 | 
						|
        }
 | 
						|
 | 
						|
        // Create array d[] containing lines of database php file
 | 
						|
        $d   = array();
 | 
						|
        $d[] = '<?php';
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Include basic classes';
 | 
						|
        $d[] = ' */';
 | 
						|
        $d[] = "require_once '{$backend}.php';";
 | 
						|
        $d[] = "require_once 'DB/Table/Database.php';";
 | 
						|
 | 
						|
        // Require_once statements for subclass definitions
 | 
						|
        foreach ($this->tables as $table) {
 | 
						|
            $classname      = $this->className($table);
 | 
						|
            $class_filename = $this->classFileName($classname);
 | 
						|
            if ($this->class_include_path) {
 | 
						|
                $d[] = 'require_once '
 | 
						|
                     . "'{$this->class_include_path}/{$class_filename}';";
 | 
						|
            } else {
 | 
						|
                $d[] = "require_once '{$class_filename}';";
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * NOTE: User must uncomment & edit code to create $dsn';
 | 
						|
        $d[] = ' */';
 | 
						|
        $d[] = "//\$phptype  = '{$dsn['phptype']}';";
 | 
						|
        $d[] = "//\$username = '{$dsn['username']}';";
 | 
						|
        $d[] = "//\$password = ''; // put your password here";
 | 
						|
        $d[] = "//\$hostname = '{$dsn['hostspec']}';";
 | 
						|
        $d[] = "//\$database = '{$dsn['database']}';";
 | 
						|
        $d[] = "//\$create   = false; // 'drop', 'safe', 'verify', 'alter'";
 | 
						|
        $d[] = '//$dsn      = "{$phptype}://{$username}:{$password}@{$hostname}'
 | 
						|
             . '/{$database}";';
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = " * Instantiate {$backend} connection object \$conn";
 | 
						|
        $d[] = ' */';
 | 
						|
        $d[] = "\$conn =& {$backend}::connect(\$dsn);";
 | 
						|
        $d[] = 'if (PEAR::isError($conn)) {';
 | 
						|
        $d[] = '    echo "Error connecting to database server\n";';
 | 
						|
        $d[] = '    echo $conn->getMessage();';
 | 
						|
        $d[] = '    die;';
 | 
						|
        $d[] = '}';
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Create one instance of each DB_Table subclass';
 | 
						|
        $d[] = ' */';
 | 
						|
        foreach ($this->tables as $table) {
 | 
						|
            $classname = $this->className($table);
 | 
						|
 | 
						|
            $d[] = "\${$table} = new {$classname}("
 | 
						|
                 . '$conn, ' . "'{$table}'" . ', $create);';
 | 
						|
            $d[] = "if (PEAR::isError(\${$table}->error)) {";
 | 
						|
            $d[] = '    echo "Can\'t create table object.\n";';
 | 
						|
            $d[] = "    echo \${$table}->error->getMessage();";
 | 
						|
            $d[] = '    die;';
 | 
						|
            $d[] = '}';
 | 
						|
 | 
						|
        }
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Instantiate a parent DB_Table_Database object';
 | 
						|
        $d[] = ' */';
 | 
						|
        $d[] = "{$object_name} = new DB_Table_Database(\$conn, \$database);";
 | 
						|
        $d[] = "if (PEAR::isError({$object_name}->error)) {";
 | 
						|
        $d[] = '    echo "Can\'t create database object.\n";';
 | 
						|
        $d[] = "    echo {$object_name}->error->getMessage();";
 | 
						|
        $d[] = '    die;';
 | 
						|
        $d[] = '}';
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Add DB_Table objects to parent DB_Table_Database object';
 | 
						|
        $d[] = ' */';
 | 
						|
        foreach ($this->tables as $table) {
 | 
						|
            $classname = $this->className($table);
 | 
						|
 | 
						|
            $d[] = "\$result = {$object_name}->addTable(\${$table});";
 | 
						|
            $d[] = 'if (PEAR::isError($result)) {';
 | 
						|
            $d[] = '    echo "Can\'t add table object to database object.\n";';
 | 
						|
            $d[] = '    echo $result->getMessage();';
 | 
						|
            $d[] = '    die;';
 | 
						|
            $d[] = '}';
 | 
						|
        }
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        // Add foreign key references: If the name of an integer column
 | 
						|
        // matches "/id$/i" (i.e., the names ends with id, ID, or Id), the
 | 
						|
        // remainder of the name matches the name $rtable of another table,
 | 
						|
        // and $rtable has an integer primary key, then the column is
 | 
						|
        // assumed to be a foreign key that references $rtable.
 | 
						|
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Add auto-guessed foreign references';
 | 
						|
        $d[] = ' */';
 | 
						|
        foreach ($this->col as $table => $col) {
 | 
						|
            foreach ($col as $col_name => $def) {
 | 
						|
 | 
						|
                // Only consider integer columns
 | 
						|
                $ftype = $def['type'];
 | 
						|
                if (!in_array($ftype, array('integer','smallint','bigint'))) {
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
                if (preg_match("/id$/i", $col_name)) {
 | 
						|
                    $column_base = preg_replace('/_?id$/i', '', $col_name);
 | 
						|
                    foreach ($this->tables as $rtable) {
 | 
						|
                        if (!preg_match("/^{$rtable}$/i", $column_base)) {
 | 
						|
                            continue;
 | 
						|
                        }
 | 
						|
                        if (preg_match("/^{$table}$/i", $column_base)) {
 | 
						|
                            continue;
 | 
						|
                        }
 | 
						|
                        if (!isset($this->primary_key[$rtable])) {
 | 
						|
                            continue;
 | 
						|
                        }
 | 
						|
                        $rkey = $this->primary_key[$rtable];
 | 
						|
                        if (is_array($rkey)) {
 | 
						|
                            continue;
 | 
						|
                        }
 | 
						|
                        $rtype = $this->col[$rtable][$rkey]['type'];
 | 
						|
                        if (!in_array($rtype,
 | 
						|
                            array('integer','smallint','bigint'))) {
 | 
						|
                            continue;
 | 
						|
                        }
 | 
						|
                        $d[] = "\$result = {$object_name}->addRef('{$table}', "
 | 
						|
                             . "'{$col_name}', '{$rtable}');";
 | 
						|
                        $d[] = 'if (PEAR::isError($result)) {';
 | 
						|
                        $d[] = '    echo "Can\'t add foreign key reference.\n";';
 | 
						|
                        $d[] = '    echo $result->getMessage();';
 | 
						|
                        $d[] = '    die;';
 | 
						|
                        $d[] = '}';
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $d[] = '';
 | 
						|
        $d[] = '/*';
 | 
						|
        $d[] = ' * Add any additional foreign key references here';
 | 
						|
        $d[] = ' *';
 | 
						|
        $d[] = ' * Add any linking table declarations here';
 | 
						|
        $d[] = ' * Uncomment next line to add all possible linking tables;';
 | 
						|
        $d[] = ' */';
 | 
						|
        $d[] = "//\$result = {$object_name}->addAllLinks();";
 | 
						|
        $d[] = '//if (PEAR::isError($result)) {';
 | 
						|
        $d[] = '//    echo "Can\'t add linking tables.\n";';
 | 
						|
        $d[] = '//    echo $result->getMessage();';
 | 
						|
        $d[] = '//    die;';
 | 
						|
        $d[] = '//}';
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        // Closing script element
 | 
						|
        $d[] = '?>';
 | 
						|
        $d[] = '';
 | 
						|
 | 
						|
        // Open and write file
 | 
						|
        $base = $this->class_write_path;
 | 
						|
        if ($base) {
 | 
						|
            if (!file_exists($base)) {
 | 
						|
                include_once 'System.php';
 | 
						|
                if (!@System::mkdir(array('-p', $base))) {
 | 
						|
                    return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $base);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $filename = $base . '/Database.php';
 | 
						|
        } else {
 | 
						|
            $filename = 'Database.php';
 | 
						|
        }
 | 
						|
        if (!$file = @fopen($filename, 'wb')) {
 | 
						|
            return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $filename);
 | 
						|
        }
 | 
						|
        $out = implode("\n", $d);
 | 
						|
        fputs($file, $out);
 | 
						|
        fclose($file);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function className($table)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Convert a table name into a class name
 | 
						|
     *
 | 
						|
     * Converts all non-alphanumeric characters to '_', capitalizes
 | 
						|
     * first letter, and adds $this->class_suffix to end. Override
 | 
						|
     * this if you want something else.
 | 
						|
     *
 | 
						|
     * @param string $table name of table
 | 
						|
     *
 | 
						|
     * @return string class name;
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function className($table)
 | 
						|
    {
 | 
						|
        $name = preg_replace('/[^A-Z0-9]/i', '_', ucfirst(trim($table)));
 | 
						|
        return  $name . $this->class_suffix;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function tableName($table)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a valid variable name from a table name
 | 
						|
     *
 | 
						|
     * Converts all non-alphanumeric characters to '_'. Override
 | 
						|
     * this if you want something else.
 | 
						|
     *
 | 
						|
     * @param string $table name of table
 | 
						|
     *
 | 
						|
     * @return string variable name;
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function tableName($table)
 | 
						|
    {
 | 
						|
        return preg_replace('/[^A-Z0-9]/i', '_', trim($table));
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
    // {{{ function classFileName($class_name)
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the path to a file containing a class definition
 | 
						|
     *
 | 
						|
     * Appends '.php' to class name.
 | 
						|
     *
 | 
						|
     * @param string $class_name name of class
 | 
						|
     *
 | 
						|
     * @return string file name
 | 
						|
     * @access public
 | 
						|
     */
 | 
						|
    function classFileName($class_name)
 | 
						|
    {
 | 
						|
        $filename = $class_name . '.php';
 | 
						|
        return $filename;
 | 
						|
    }
 | 
						|
 | 
						|
    // }}}
 | 
						|
 | 
						|
}
 | 
						|
// }}}
 |