<?php

/*
 *  $Id: PHP5BasicPeerBuilder.php 592 2007-03-02 21:41:42Z hans $
 *
 * 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.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information please see
 * <http://propel.phpdb.org>.
 */

require_once 'propel/engine/builder/om/PeerBuilder.php';

/**
 * Generates a PHP5 base Peer class for user object model (OM).
 *
 * This class produces the base peer class (e.g. BaseMyPeer) which contains all
 * the custom-built query and manipulator methods.
 *
 * This class replaces the Peer.tpl, with the intent of being easier for users
 * to customize (through extending & overriding).
 *
 * @author     Hans Lellelid <hans@xmpl.org>
 * @package    propel.engine.builder.om.php5
 */
class PHP5BasicPeerBuilder extends PeerBuilder {

    /**
     * Returns the name of the current class being built.
     * @return     string
     */
    public function getClassname()
    {
        return $this->getBuildProperty('basePrefix') . $this->getStubPeerBuilder()->getClassname();
    }

    /**
     * Gets the package for the [base] peer classes.
     * @return     string
     */
    public function getPackage()
    {
        return parent::getPackage() . ".om";
    }

    /**
     * Adds the include() statements for files that this class depends on or utilizes.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addIncludes(&$script) {

        $table = $this->getTable();

        $basePeerFile = $this->getFilePath($this->basePeerClass);
        $objectFile = $this->getStubObjectBuilder()->getClassFilePath();

        $script .= "
require_once '$basePeerFile';
// The object class -- needed for instanceof checks in this class.
// actual class may be a subclass -- as returned by ".$this->getPeerClassname()."::getOMClass()
include_once '$objectFile';";

        $script .= "
";

    } // addIncludes()

    /**
     * Adds class phpdoc comment and openning of class.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addClassOpen(&$script) {

        $tableName = $this->getTable()->getName();
        $tableDesc = $this->getTable()->getDescription();

        $script .= "
/**
 * Base static class for performing query and update operations on the '$tableName' table.
 *
 * $tableDesc
 *";
        if ($this->getBuildProperty('addTimeStamp')) {
            $now = strftime('%c');
            $script .= "
 * This class was autogenerated by Propel on:
 *
 * $now
 *";
        }
        $script .= "
 * @package    workflow.".$this->getPackage()."
 */
abstract class ".$this->getClassname()."
{
";
    }

    /**
     * Closes class.
     * Adds closing brace at end of class and the static map builder registration code.
     * @param      string &$script The script will be modified in this method.
     * @see        addStaticMapBuilderRegistration()
     */
    protected function addClassClose(&$script)
    {
        $script .= "}

";
        $this->addStaticMapBuilderRegistration($script);
    }

    /**
     * Adds the static map builder registraction code.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addStaticMapBuilderRegistration(&$script)
    {
        $table = $this->getTable();
        $mapBuilderFile = $this->getMapBuilderBuilder()->getClassFilePath();

        $script .= "
// static code to register the map builder for this Peer with the main Propel class
if (Propel::isInit()) {
    // the MapBuilder classes register themselves with Propel during initialization
    // so we need to load them here.
    try {
        ".$this->getClassname()."::getMapBuilder();
    } catch (Exception \$e) {
        Propel::log('Could not initialize Peer: ' . \$e->getMessage(), Propel::LOG_ERR);
    }
} else {
    // even if Propel is not yet initialized, the map builder class can be registered
    // now and then it will be loaded when Propel initializes.
    require_once '$mapBuilderFile';
    Propel::registerMapBuilder('".$this->getMapBuilderBuilder()->getClasspath()."');
}

";
    }

    /**
     * Adds constant and variable declarations that go at the top of the class.
     * @param      string &$script The script will be modified in this method.
     * @see        addColumnNameConstants()
     */
    protected function addConstantsAndAttributes(&$script)
    {
        $tableName = $this->getTable()->getName();
        $dbName = $this->getDatabase()->getName();
        $script .= "
    /** the default database name for this class */
    const DATABASE_NAME = '$dbName';

    /** the table name for this class */
    const TABLE_NAME = '$tableName';

    /** A class that can be returned by this peer. */
    const CLASS_DEFAULT = '".$this->getStubObjectBuilder()->getClasspath()."';

    /** The total number of columns. */
    const NUM_COLUMNS = ".$this->getTable()->getNumColumns().";

    /** The number of lazy-loaded columns. */
    const NUM_LAZY_LOAD_COLUMNS = ".$this->getTable()->getNumLazyLoadColumns().";

";
        $this->addColumnNameConstants($script);
        $this->addInheritanceColumnConstants($script);

        $script .= "
    /** The PHP to DB Name Mapping */
    private static \$phpNameMap = null;

";

        $this->addFieldNamesAttribute($script);
        $this->addFieldKeysAttribute($script);

    }

    /**
     * Adds the COLUMN_NAME contants to the class definition.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addColumnNameConstants(&$script)
    {
        foreach ($this->getTable()->getColumns() as $col) {

            $script .= "
    /** the column name for the ".strtoupper($col->getName()) ." field */
    const ".$this->getColumnName($col) ." = '".$this->getTable()->getName().".".strtoupper($col->getName())."';
";
        } // foreach
    }

    protected function addFieldNamesAttribute(&$script)
    {
        $table = $this->getTable();

        $tableColumns = $table->getColumns();
        $tablePhpname = $table->getPhpName();

        $script .= "
    /**
     * holds an array of fieldnames
     *
     * first dimension keys are the type constants
     * e.g. self::\$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
     */
    private static \$fieldNames = array (
        BasePeer::TYPE_PHPNAME => array (";
        foreach ($tableColumns as $col) {
            $script .= "'".$col->getPhpName()."', ";
        }
        $script .= "),
        BasePeer::TYPE_COLNAME => array (";
        foreach ($tableColumns as $col) {
            $script .= $this->getColumnConstant($col).", ";
        }
        $script .= "),
        BasePeer::TYPE_FIELDNAME => array (";
        foreach ($tableColumns as $col) {
            $script .= "'".$col->getName()."', ";
        }
        $script .= "),
        BasePeer::TYPE_NUM => array (";
        foreach ($tableColumns as $num => $col) {
            $script .= "$num, ";
        }
        $script .= ")
    );
";
    }

    protected function addFieldKeysAttribute(&$script)
    {
        $table = $this->getTable();

        $tableColumns = $table->getColumns();
        $tablePhpname = $table->getPhpName();

        $script .= "
    /**
     * holds an array of keys for quick access to the fieldnames array
     *
     * first dimension keys are the type constants
     * e.g. self::\$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
     */
    private static \$fieldKeys = array (
        BasePeer::TYPE_PHPNAME => array (";
        foreach ($tableColumns as $num => $col) {
            $script .= "'".$col->getPhpName()."' => $num, ";
        }
        $script .= "),
        BasePeer::TYPE_COLNAME => array (";
        foreach ($tableColumns as $num => $col) {
            $script .= $this->getColumnConstant($col)." => $num, ";
        }
        $script .= "),
        BasePeer::TYPE_FIELDNAME => array (";
        foreach ($tableColumns as $num => $col) {
            $script .= "'".$col->getName()."' => $num, ";
        }
        $script .= "),
        BasePeer::TYPE_NUM => array (";
        foreach ($tableColumns as $num => $col) {
            $script .= "$num, ";
        }
        $script .= ")
    );
";
    } // addFielKeysAttribute


    protected function addGetFieldNames(&$script)
    {
        $script .= "
    /**
     * Returns an array of of field names.
     *
     * @param      string \$type The type of fieldnames to return:
     *                      One of the class type constants TYPE_PHPNAME,
     *                      TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
     * @return     array A list of field names
     */

    static public function getFieldNames(\$type = BasePeer::TYPE_PHPNAME)
    {
        if (!array_key_exists(\$type, self::\$fieldNames)) {
            throw new PropelException('Method getFieldNames() expects the parameter \$type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . \$type . ' was given.');
        }
        return self::\$fieldNames[\$type];
    }
";

    } // addGetFieldNames()

    protected function addTranslateFieldName(&$script)
    {
        $script .= "
    /**
     * Translates a fieldname to another type
     *
     * @param      string \$name field name
     * @param      string \$fromType One of the class type constants TYPE_PHPNAME,
     *                         TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM
     * @param      string \$toType   One of the class type constants
     * @return     string translated name of the field.
     */
    static public function translateFieldName(\$name, \$fromType, \$toType)
    {
        \$toNames = self::getFieldNames(\$toType);
        \$key = isset(self::\$fieldKeys[\$fromType][\$name]) ? self::\$fieldKeys[\$fromType][\$name] : null;
        if (\$key === null) {
            throw new PropelException(\"'\$name' could not be found in the field names of type '\$fromType'. These are: \" . print_r(self::\$fieldKeys[\$fromType], true));
        }
        return \$toNames[\$key];
    }
";
    } // addTranslateFieldName()

    /**
     * Adds the getMapBuilder() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetMapBuilder(&$script)
    {
        $script .= "
    /**
     * @return     MapBuilder the map builder for this peer
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function getMapBuilder()
    {
        include_once '" . $this->getMapBuilderBuilder()->getClassFilePath()."';
        return ".$this->basePeerClassname."::getMapBuilder('". $this->getMapBuilderBuilder()->getClasspath() ."');
    }";
    }

    /**
     * Adds the getPhpNameMap() method.
     * @param      string &$script The script will be modified in this method.
     * @todo       Replace with static version (this can be built at build-time).
     */
    protected function addGetPhpNameMap(&$script)
    {
        $script .= "
    /**
     * Gets a map (hash) of PHP names to DB column names.
     *
     * @return     array The PHP to DB name map for this peer
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     * @deprecated Use the getFieldNames() and translateFieldName() methods instead of this.
     */
    public static function getPhpNameMap()
    {
        if (self::\$phpNameMap === null) {
            \$map = ".$this->getTable()->getPhpName()."Peer::getTableMap();
            \$columns = \$map->getColumns();
            \$nameMap = array();
            foreach (\$columns as \$column) {
                \$nameMap[\$column->getPhpName()] = \$column->getColumnName();
            }
            self::\$phpNameMap = \$nameMap;
        }
        return self::\$phpNameMap;
    }";
    }

    /**
     * Adds the CLASSKEY_* and CLASSNAME_* constants used for inheritance.
     * @param      string &$script The script will be modified in this method.
     */
    public function addInheritanceColumnConstants(&$script)
    {
        if ($this->getTable()->getChildrenColumn()) {

            $col = $this->getTable()->getChildrenColumn();
            $tfc = $this->getTable()->getPhpName();
            $cfc = $col->getPhpName();

            if ($col->isEnumeratedClasses()) {

                if ($col->isPrimitiveNumeric()) $quote = "";
                else $quote = '"';

                foreach ($col->getChildren() as $child) {
                    $childBuilder = $this->getMultiExtendObjectBuilder();
                    $childBuilder->setChild($child);

                    $script .= "
    /** A key representing a particular subclass */
    const CLASSKEY_".strtoupper($child->getKey())." = '" . $child->getKey() . "';
";

    if (strtoupper($child->getClassname()) != strtoupper($child->getKey())) {
        $script .= "
    /** A key representing a particular subclass */
    const CLASSKEY_".strtoupper($child->getClassname())." = '" . $child->getKey() . "';
";
    }

    $script .= "
    /** A class that can be returned by this peer. */
    const CLASSNAME_".strtoupper($child->getKey())." = '". $childBuilder->getClasspath() . "';
";
                    } /* foreach children */
            } /* if col->isenumerated...() */
        } /* if table->getchildrencolumn() */

    } //



    /**
     * Adds the alias() utility method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addAlias(&$script)
    {
        $script .= "
    /**
     * Convenience method which changes table.column to alias.column.
     *
     * Using this method you can maintain SQL abstraction while using column aliases.
     * <code>
     *      \$c->addAlias(\"alias1\", TablePeer::TABLE_NAME);
     *      \$c->addJoin(TablePeer::alias(\"alias1\", TablePeer::PRIMARY_KEY_COLUMN), TablePeer::PRIMARY_KEY_COLUMN);
     * </code>
     * @param      string \$alias The alias for the current table.
     * @param      string \$column The column name for current table. (i.e. ".$this->getTable()->getPhpName()."Peer::COLUMN_NAME).
     * @return     string
     */
    public static function alias(\$alias, \$column)
    {
        return str_replace(".$this->getPeerClassname()."::TABLE_NAME.'.', \$alias.'.', \$column);
    }
";
    } // addAliasMethod

    /**
     * Adds the addSelectColumns() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addAddSelectColumns(&$script)
    {
        $script .= "
    /**
     * Add all the columns needed to create a new object.
     *
     * Note: any columns that were marked with lazyLoad=\"true\" in the
     * XML schema will not be added to the select list and only loaded
     * on demand.
     *
     * @param      criteria object containing the columns to add.
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function addSelectColumns(Criteria \$criteria)
    {
";
        foreach ($this->getTable()->getColumns() as $col) {
            if (!$col->isLazyLoad()) {
                $script .= "
        \$criteria->addSelectColumn(".$this->getPeerClassname()."::".$this->getColumnName($col).");
";
            } // if !col->isLazyLoad
        } // foreach
        $script .="
    }
";
    } // addAddSelectColumns()



    /**
     * Adds the COUNT constants.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addCountConstants(&$script)
    {
        $table = $this->getTable();
        $count_col = "*";
        /*
        * FIXME
        * (HL) wanted to remove this because AFAIK count(*) is generally
        * optimized in databases, and furthermore the code below isn't correct
        * (multi-pkey needs to be accounted for)....
        */
        if ($table->hasPrimaryKey()) {
            $pk = $table->getPrimaryKey();
            $count_col = $table->getName().".".strtoupper($pk[0]->getName());
        }

        $script .= "
    const COUNT = 'COUNT($count_col)';
    const COUNT_DISTINCT = 'COUNT(DISTINCT $count_col)';
";
    }

    /**
     * Adds the doCount() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoCount(&$script)
    {
        $script .= "
    /**
     * Returns the number of rows matching criteria.
     *
     * @param      Criteria \$criteria
     * @param      boolean \$distinct Whether to select only distinct columns (You can also set DISTINCT modifier in Criteria).
     * @param      Connection \$con
     * @return     int Number of matching rows.
     */
    public static function doCount(Criteria \$criteria, \$distinct = false, \$con = null)
    {
        // we're going to modify criteria, so copy it first
        \$criteria = clone \$criteria;

        // clear out anything that might confuse the ORDER BY clause
        \$criteria->clearSelectColumns()->clearOrderByColumns();
        if (\$distinct || in_array(Criteria::DISTINCT, \$criteria->getSelectModifiers())) {
            \$criteria->addSelectColumn(".$this->getPeerClassname()."::COUNT_DISTINCT);
        } else {
            \$criteria->addSelectColumn(".$this->getPeerClassname()."::COUNT);
        }

        // just in case we're grouping: add those columns to the select statement
        foreach (\$criteria->getGroupByColumns() as \$column) {
            \$criteria->addSelectColumn(\$column);
        }

        \$rs = ".$this->getPeerClassname()."::doSelectRS(\$criteria, \$con);
        if (\$rs->next()) {
            return \$rs->getInt(1);
        } else {
            // no rows returned; we infer that means 0 matches.
            return 0;
        }
    }";
    }

    /**
     * Adds the doSelectOne() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoSelectOne(&$script)
    {
        $script .= "
    /**
     * Method to select one object from the DB.
     *
     * @param      Criteria \$criteria object used to create the SELECT statement.
     * @param      Connection \$con
     * @return     ".$this->getTable()->getPhpName()."
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function doSelectOne(Criteria \$criteria, \$con = null)
    {
        \$critcopy = clone \$criteria;
        \$critcopy->setLimit(1);
        \$objects = ".$this->getPeerClassname()."::doSelect(\$critcopy, \$con);
        if (\$objects) {
            return \$objects[0];
        }
        return null;
    }";
    }

    /**
     * Adds the doSelect() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoSelect(&$script)
    {
        $script .= "
    /**
     * Method to do selects.
     *
     * @param      Criteria \$criteria The Criteria object used to build the SELECT statement.
     * @param      Connection \$con
     * @return     array Array of selected Objects
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function doSelect(Criteria \$criteria, \$con = null)
    {
        return ".$this->getPeerClassname()."::populateObjects(".$this->getPeerClassname()."::doSelectRS(\$criteria, \$con));
    }";
    }

    /**
     * Adds the doSelectRS() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoSelectRS(&$script)
    {

        $script .= "
    /**
     * Prepares the Criteria object and uses the parent doSelect()
     * method to get a ResultSet.
     *
     * Use this method directly if you want to just get the resultset
     * (instead of an array of objects).
     *
     * @param      Criteria \$criteria The Criteria object used to build the SELECT statement.
     * @param      Connection \$con the connection to use
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     * @return     ResultSet The resultset object with numerically-indexed fields.
     * @see        ".$this->basePeerClassname."::doSelect()
     */
    public static function doSelectRS(Criteria \$criteria, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }

        if (!\$criteria->getSelectColumns()) {
            \$criteria = clone \$criteria;
            ".$this->getPeerClassname()."::addSelectColumns(\$criteria);
        }

        // Set the correct dbName
        \$criteria->setDbName(self::DATABASE_NAME);

        // BasePeer returns a Creole ResultSet, set to return
        // rows indexed numerically.
        return ".$this->basePeerClassname."::doSelect(\$criteria, \$con);
    }";
    }

    /**
     * Adds the populateObjects() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addPopulateObjects(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * The returned array will contain objects of the default type or
     * objects that inherit from the default.
     *
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function populateObjects(ResultSet \$rs)
    {
        \$results = array();
";
        if (!$table->getChildrenColumn()) {
            $script .= "
        // set the class once to avoid overhead in the loop
        \$cls = ".$this->getPeerClassname()."::getOMClass();
        \$cls = Propel::import(\$cls);";
        }

        $script .= "
        // populate the object(s)
        while (\$rs->next()) {
";
        if ($table->getChildrenColumn()) {
            $script .= "
            // class must be set each time from the record row
            \$cls = Propel::import(".$this->getPeerClassname()."::getOMClass(\$rs, 1));
            \$obj = new \$cls();
            \$obj->hydrate(\$rs);
            \$results[] = \$obj;
";
        } else {
            $script .= "
            \$obj = new \$cls();
            \$obj->hydrate(\$rs);
            \$results[] = \$obj;
";
        }
        $script .= "
        }
        return \$results;
    }";
    }

    /**
     * Adds a getOMClass() for non-abstract tables that have inheritance.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetOMClass_Inheritance(&$script)
    {
        $col = $this->getTable()->getChildrenColumn();
        $script .= "
    /**
     * The returned Class will contain objects of the default type or
     * objects that inherit from the default.
     *
     * @param      ResultSet \$rs ResultSet with pointer to record containing om class.
     * @param      int \$colnum Column to examine for OM class information (first is 1).
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function getOMClass(ResultSet \$rs, \$colnum)
    {
        try {
";
        if ($col->isEnumeratedClasses()) {
            $script .= "
            \$omClass = null;
            \$classKey = \$rs->getString(\$colnum - 1 + " . $col->getPosition() . ");

            switch(\$classKey) {
";
            foreach ($col->getChildren() as $child) {
                $script .= "
                case self::CLASSKEY_".strtoupper($child->getKey()).":
                    \$omClass = self::CLASSNAME_".strtoupper($child->getKey()).";
                    break;
";
            } /* foreach */
            $script .= "
                default:
                    \$omClass = self::CLASS_DEFAULT;
";
            $script .= "
            } // switch
";
        } else { /* if not enumerated */
            $script .= "
            \$omClass = Propel::import(\$rs->getString(\$colnum - 1 + ".$col->getPosition()."));
";
        }
        $script .= "
        } catch (Exception \$e) {
            throw new PropelException('Unable to get OM class.', \$e);
        }
        return \$omClass;
    }
";
    }

    /**
     * Adds a getOMClass() signature for abstract tables that have inheritance.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetOMClass_Inheritance_Abstract(&$script)
    {
        $script .= "
    /**
     * The returned Class will contain objects of the default type or
     * objects that inherit from the default.
     *
     * This method must be overridden by the stub subclass, because
     * ".$this->getTable()->getPhpName()." is declared abstract in the schema.
     *
     * @param      ResultSet \$rs ResultSet with pointer to record containing om class.
     * @param      int \$colnum Column to examine for OM class information (first is 1).
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    abstract public static function getOMClass();
";
    }

    /**
     * Adds a getOMClass() for non-abstract tables that do note use inheritance.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetOMClass_NoInheritance(&$script)
    {
        $script .= "
    /**
     * The class that the Peer will make instances of.
     *
     * This uses a dot-path notation which is tranalted into a path
     * relative to a location on the PHP include_path.
     * (e.g. path.to.MyClass -> 'path/to/MyClass.php')
     *
     * @return     string path.to.ClassName
     */
    public static function getOMClass()
    {
        return ".$this->getPeerClassname()."::CLASS_DEFAULT;
    }
";
    }

    /**
     * Adds a getOMClass() signature for abstract tables that do not have inheritance.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetOMClass_NoInheritance_Abstract(&$script)
    {
        $script .= "
    /**
     * The class that the Peer will make instances of.
     *
     * This method must be overridden by the stub subclass, because
     * ".$this->getTable()->getPhpName()." is declared abstract in the schema.
     */
    abstract public static function getOMClass();
";
    }

    /**
     * Adds the doInsert() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoInsert(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Method perform an INSERT on the database, given a ".$table->getPhpName()." or Criteria object.
     *
     * @param      mixed \$values Criteria or ".$table->getPhpName()." object containing data that is used to create the INSERT statement.
     * @param      Connection \$con the connection to use
     * @return     mixed The new primary key.
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function doInsert(\$values, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }

        if (\$values instanceof Criteria) {
            \$criteria = clone \$values; // rename for clarity
        } else {
            \$criteria = \$values->buildCriteria(); // build Criteria from ".$table->getPhpName()." object
        }
";

        foreach ($table->getColumns() as $col) {
            $cfc = $col->getPhpName();
            if ($col->isPrimaryKey() && $col->isAutoIncrement() && $table->getIdMethod() != "none") {
                $comment = ($col->isPrimaryKey() && $col->isAutoIncrement()) ? "//" : "";

                $script .= "
                " . $comment . "\$criteria->remove(".$this->getColumnConstant($col)."); // remove pkey col since this table uses auto-increment
                ";
            }
        }

        $script .= "

        // Set the correct dbName
        \$criteria->setDbName(self::DATABASE_NAME);

        try {
            // use transaction because \$criteria could contain info
            // for more than one table (I guess, conceivably)
            \$con->begin();
            \$pk = ".$this->basePeerClassname."::doInsert(\$criteria, \$con);
            \$con->commit();
        } catch (PropelException \$e) {
            \$con->rollback();
            throw \$e;
        }

        return \$pk;
    }
";
    }

    /**
     * Adds the doUpdate() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoUpdate(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Method perform an UPDATE on the database, given a ".$table->getPhpName()." or Criteria object.
     *
     * @param      mixed \$values Criteria or ".$table->getPhpName()." object containing data create the UPDATE statement.
     * @param      Connection \$con The connection to use (specify Connection exert more control over transactions).
     * @return     int The number of affected rows (if supported by underlying database driver).
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function doUpdate(\$values, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }

        \$selectCriteria = new Criteria(self::DATABASE_NAME);

        if (\$values instanceof Criteria) {
            \$criteria = clone \$values; // rename for clarity
";
        foreach ($table->getColumns() as $col) {
            if($col->isPrimaryKey()) {
                $script .= "
            \$comparison = \$criteria->getComparison(".$this->getColumnConstant($col).");
            \$selectCriteria->add(".$this->getColumnConstant($col).", \$criteria->remove(".$this->getColumnConstant($col)."), \$comparison);
";
            }  /* if col is prim key */
        } /* foreach */

        $script .= "
        } else {
            \$criteria = \$values->buildCriteria(); // gets full criteria
            \$selectCriteria = \$values->buildPkeyCriteria(); // gets criteria w/ primary key(s)
        }

        // set the correct dbName
        \$criteria->setDbName(self::DATABASE_NAME);

        return {$this->basePeerClassname}::doUpdate(\$selectCriteria, \$criteria, \$con);
    }
";
    }

    /**
     * Adds the doDeleteAll() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoDeleteAll(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Method to DELETE all rows from the ".$table->getName()." table.
     *
     * @return     int The number of affected rows (if supported by underlying database driver).
     */
    public static function doDeleteAll(\$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }
        \$affectedRows = 0; // initialize var to track total num of affected rows
        try {
            // use transaction because \$criteria could contain info
            // for more than one table or we could emulating ON DELETE CASCADE, etc.
            \$con->begin();
            ";
            if ($this->isDeleteCascadeEmulationNeeded()) {
                $script .="\$affectedRows += ".$this->getPeerClassname()."::doOnDeleteCascade(new Criteria(), \$con);
            ";
            }
            if ($this->isDeleteSetNullEmulationNeeded()) {
                $script .= $this->getPeerClassname() . "::doOnDeleteSetNull(new Criteria(), \$con);
            ";
            }
            $script .= "\$affectedRows += BasePeer::doDeleteAll(".$this->getPeerClassname()."::TABLE_NAME, \$con);
            \$con->commit();
            return \$affectedRows;
        } catch (PropelException \$e) {
            \$con->rollback();
            throw \$e;
        }
    }
";
    }

    /**
     * Adds the doDelete() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoDelete(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Method perform a DELETE on the database, given a ".$table->getPhpName()." or Criteria object OR a primary key value.
     *
     * @param      mixed \$values Criteria or ".$table->getPhpName()." object or primary key or array of primary keys
     *              which is used to create the DELETE statement
     * @param      Connection \$con the connection to use
     * @return     int  The number of affected rows (if supported by underlying database driver).
     *             This includes CASCADE-related rows
     *              if supported by native driver or if emulated using Propel.
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
    */
    public static function doDelete(\$values, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(".$this->getPeerClassname()."::DATABASE_NAME);
        }

        if (\$values instanceof Criteria) {
            \$criteria = clone \$values; // rename for clarity
        } elseif (\$values instanceof ".$table->getPhpName().") {
";
        if (count($table->getPrimaryKey()) > 0) {
            $script .= "
            \$criteria = \$values->buildPkeyCriteria();";
        } else {
            $script .= "
            \$criteria = \$values->buildCriteria();";
        }

        $script .= "
        } else {
            // it must be the primary key
            \$criteria = new Criteria(self::DATABASE_NAME);";

        if (count($table->getPrimaryKey()) === 1) {
            $pkey = $table->getPrimaryKey();
            $col = array_shift($pkey);
            $script .= "
            \$criteria->add(".$this->getColumnConstant($col).", (array) \$values, Criteria::IN);";
        } else {
            $script .= "
            // primary key is composite; we therefore, expect
            // the primary key passed to be an array of pkey
            // values
            if (count(\$values) == count(\$values, COUNT_RECURSIVE)) {
                // array is not multi-dimensional
                \$values = array(\$values);
            }
            \$vals = array();
            foreach (\$values as \$value) {
";
            $i=0;
            foreach($table->getPrimaryKey() as $col) {
                $script .= "
                \$vals[$i][] = \$value[$i];";
                $i++;
            }
            $script .= "
            }
";
            $i=0;
            foreach($table->getPrimaryKey() as $col) {
                $script .= "
            \$criteria->add(".$this->getColumnConstant($col).", \$vals[$i], Criteria::IN);";
                $i++;
            }
        } /* if count(table->getPrimaryKeys()) */

        $script .= "
        }

        // Set the correct dbName
        \$criteria->setDbName(self::DATABASE_NAME);

        \$affectedRows = 0; // initialize var to track total num of affected rows

        try {
            // use transaction because \$criteria could contain info
            // for more than one table or we could emulating ON DELETE CASCADE, etc.
            \$con->begin();
";

        if ($this->isDeleteCascadeEmulationNeeded()) {
            $script .= "\$affectedRows += ".$this->getPeerClassname()."::doOnDeleteCascade(\$criteria, \$con);";
        }
        if ($this->isDeleteSetNullEmulationNeeded()) {
            $script .= $this->getPeerClassname() . "::doOnDeleteSetNull(\$criteria, \$con);";
        }

        $script .= "
            \$affectedRows += {$this->basePeerClassname}::doDelete(\$criteria, \$con);
            \$con->commit();
            return \$affectedRows;
        } catch (PropelException \$e) {
            \$con->rollback();
            throw \$e;
        }
    }
";
    }

    /**
     * Adds the doOnDeleteCascade() method, which provides ON DELETE CASCADE emulation.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoOnDeleteCascade(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * This is a method for emulating ON DELETE CASCADE for DBs that don't support this
     * feature (like MySQL or SQLite).
     *
     * This method is not very speedy because it must perform a query first to get
     * the implicated records and then perform the deletes by calling those Peer classes.
     *
     * This method should be used within a transaction if possible.
     *
     * @param      Criteria \$criteria
     * @param      Connection \$con
     * @return     int The number of affected rows (if supported by underlying database driver).
     */
    protected static function doOnDeleteCascade(Criteria \$criteria, Connection \$con)
    {
        // initialize var to track total num of affected rows
        \$affectedRows = 0;

        // first find the objects that are implicated by the \$criteria
        \$objects = ".$this->getPeerClassname()."::doSelect(\$criteria, \$con);
        foreach(\$objects as \$obj) {
";

        foreach ($table->getReferrers() as $fk) {

            // $fk is the foreign key in the other table, so localTableName will
            // actually be the table name of other table
            $tblFK = $fk->getTable();

            $joinedTablePeerBuilder = OMBuilder::getNewPeerBuilder($tblFK);
            $tblFKPackage = $joinedTablePeerBuilder->getStubPeerBuilder()->getPackage();

            if (!$tblFK->isForReferenceOnly()) {
                // we can't perform operations on tables that are
                // not within the schema (i.e. that we have no map for, etc.)

                $fkClassName = $tblFK->getPhpName();

                // i'm not sure whether we can allow delete cascade for foreign keys
                // within the same table?  perhaps we can?
                if ( $fk->getOnDelete() == ForeignKey::CASCADE && $tblFK->getName() != $table->getName()) {

                    // backwards on purpose
                    $columnNamesF = $fk->getLocalColumns();
                    $columnNamesL = $fk->getForeignColumns();

                    $script .= "

            include_once '".$this->getFilePath($tblFKPackage, $tblFK->getPhpName())."';

            // delete related $fkClassName objects
            \$c = new Criteria();
            ";
                    for($x=0,$xlen=count($columnNamesF); $x < $xlen; $x++) {
                        $columnFK = $tblFK->getColumn($columnNamesF[$x]);
                        $columnL = $table->getColumn($columnNamesL[$x]);

                        $script .= "
            \$c->add(".$joinedTablePeerBuilder->getColumnConstant($columnFK) .", \$obj->get".$columnL->getPhpName()."());";
                    }

                    $script .= "
            \$affectedRows += ".$joinedTablePeerBuilder->getPeerClassname()."::doDelete(\$c, \$con);";

                } // if cascade && fkey table name != curr table name

            } // if not for ref only
        } // foreach foreign keys
            $script .= "
        }
        return \$affectedRows;
    }
";
    } // end addDoOnDeleteCascade

    /**
     * Adds the doOnDeleteSetNull() method, which provides ON DELETE SET NULL emulation.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoOnDeleteSetNull(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * This is a method for emulating ON DELETE SET NULL DBs that don't support this
     * feature (like MySQL or SQLite).
     *
     * This method is not very speedy because it must perform a query first to get
     * the implicated records and then perform the deletes by calling those Peer classes.
     *
     * This method should be used within a transaction if possible.
     *
     * @param      Criteria \$criteria
     * @param      Connection \$con
     * @return     void
     */
    protected static function doOnDeleteSetNull(Criteria \$criteria, Connection \$con)
    {

        // first find the objects that are implicated by the \$criteria
        \$objects = ".$this->getPeerClassname()."::doSelect(\$criteria, \$con);
        foreach(\$objects as \$obj) {
";

        // This logic is almost exactly the same as that in doOnDeleteCascade()
        // it may make sense to refactor this, provided that thigns don't
        // get too complicated.

        foreach ($table->getReferrers() as $fk) {

            // $fk is the foreign key in the other table, so localTableName will
            // actually be the table name of other table
            $tblFK = $fk->getTable();
            $refTablePeerBuilder = OMBuilder::getNewPeerBuilder($tblFK);

            if (!$tblFK->isForReferenceOnly()) {
                // we can't perform operations on tables that are
                // not within the schema (i.e. that we have no map for, etc.)

                $fkClassName = $tblFK->getPhpName();

                // i'm not sure whether we can allow delete setnull for foreign keys
                // within the same table?  perhaps we can?
                if ( $fk->getOnDelete() == ForeignKey::SETNULL &&
                        $fk->getTable()->getName() != $table->getName()) {

                            // backwards on purpose
                            $columnNamesF = $fk->getLocalColumns();
                            $columnNamesL = $fk->getForeignColumns(); // should be same num as foreign
                    $script .= "
            // set fkey col in related $fkClassName rows to NULL
            \$selectCriteria = new Criteria(".$this->getPeerClassname()."::DATABASE_NAME);
            \$updateValues = new Criteria(".$this->getPeerClassname()."::DATABASE_NAME);";

                    for ($x=0,$xlen=count($columnNamesF); $x < $xlen; $x++) {
                        $columnFK = $tblFK->getColumn($columnNamesF[$x]);
                        $columnL = $table->getColumn($columnNamesL[$x]);
                        $script .= "
            \$selectCriteria->add(".$refTablePeerBuilder->getColumnConstant($columnFK).", \$obj->get".$columnL->getPhpName()."());
            \$updateValues->add(".$refTablePeerBuilder->getColumnConstant($columnFK).", null);
";
                    }

                    $script .= "
            {$this->basePeerClassname}::doUpdate(\$selectCriteria, \$updateValues, \$con); // use BasePeer because generated Peer doUpdate() methods only update using pkey
";
                } // if setnull && fkey table name != curr table name
            } // if not for ref only
        } // foreach foreign keys

        $script .= "
        }
    }
";
    }

    /**
     * Adds the doValidate() method.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addDoValidate(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Validates all modified columns of given ".$table->getPhpName()." object.
     * If parameter \$columns is either a single column name or an array of column names
     * than only those columns are validated.
     *
     * NOTICE: This does not apply to primary or foreign keys for now.
     *
     * @param      ".$table->getPhpName()." \$obj The object to validate.
     * @param      mixed \$cols Column name or array of column names.
     *
     * @return     mixed TRUE if all columns are valid or the error message of the first invalid column.
     */
    public static function doValidate(".$table->getPhpName()." \$obj, \$cols = null)
    {
        \$columns = array();

        if (\$cols) {
            \$dbMap = Propel::getDatabaseMap(".$this->getPeerClassname()."::DATABASE_NAME);
            \$tableMap = \$dbMap->getTable(".$this->getPeerClassname()."::TABLE_NAME);

            if (! is_array(\$cols)) {
                \$cols = array(\$cols);
            }

            foreach (\$cols as \$colName) {
                if (\$tableMap->containsColumn(\$colName)) {
                    \$get = 'get' . \$tableMap->getColumn(\$colName)->getPhpName();
                    \$columns[\$colName] = \$obj->\$get();
                }
            }
        } else {
";
        foreach ($table->getValidators() as $val) {
            $col = $val->getColumn();
            if (!$col->isAutoIncrement()) {
                $script .= "
        if (\$obj->isNew() || \$obj->isColumnModified(".$this->getColumnConstant($col)."))
            \$columns[".$this->getColumnConstant($col)."] = \$obj->get".$col->getPhpName()."();
";
            } // if
        } // foreach

        $script .= "
        }

        return {$this->basePeerClassname}::doValidate(".$this->getPeerClassname()."::DATABASE_NAME, ".$this->getPeerClassname()."::TABLE_NAME, \$columns);
    }
";
    } // end addDoValidate()

    /**
     * Adds the retrieveByPK method for tables with single-column primary key.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addRetrieveByPK_SinglePK(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Retrieve a single object by pkey.
     *
     * @param      mixed \$pk the primary key.
     * @param      Connection \$con the connection to use
     * @return     " . $table->getPhpName() . "
     */
    public static function ".$this->getRetrieveMethodName()."(\$pk, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }

        \$criteria = new Criteria(".$this->getPeerClassname()."::DATABASE_NAME);
";
        if (count($table->getPrimaryKey()) === 1) {
            $pkey = $table->getPrimaryKey();
            $col = array_shift($pkey);
            $script .= "
        \$criteria->add(".$this->getColumnConstant($col).", \$pk);
";
        } else {
            // primary key is composite; we therefore, expect
            // the primary key passed to be an array of pkey
            // values
            $i=0;
            foreach($table->getPrimaryKey() as $col) {
                $script .= "
        \$criteria->add(".$this->getColumnConstant($col).", \$pk[$i]);";
                $i++;
            }
        } /* if count(table.PrimaryKeys) */
        $script .= "

        \$v = ".$this->getPeerClassname()."::doSelect(\$criteria, \$con);

        return !empty(\$v) > 0 ? \$v[0] : null;
    }
";
    }

    /**
     * Adds the retrieveByPKs method for tables with single-column primary key.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addRetrieveByPKs_SinglePK(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Retrieve multiple objects by pkey.
     *
     * @param      array \$pks List of primary keys
     * @param      Connection \$con the connection to use
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function ".$this->getRetrieveMethodName()."s(\$pks, \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }

        \$objs = null;
        if (empty(\$pks)) {
            \$objs = array();
        } else {
            \$criteria = new Criteria();";
        if (count($table->getPrimaryKey()) == 1) {
            $k1 = $table->getPrimaryKey();
            $script .= "
            \$criteria->add(".$this->getColumnConstant($k1[0]).", \$pks, Criteria::IN);";
        } else {
            $script .= "
            foreach(\$pks as \$pk) {";
            $i = 0;
            foreach($table->getPrimaryKey() as $col) {
                $script .= "
                \$c{$i} = \$criteria->getNewCriterion(".$this->getPeerClassname($col).", \$pk[$i], Criteria::EQUAL);";
                $j = $i - 1;
                if ($i > 0) {
                    $script .= "
                \$c{$j}->addAnd(\$c{$i});";
                } /* if $i > 0 */
                $i++;
            } /* foreach */

            $script .= "

                \$criteria->addOr(\$c0);
            }";
        } /* if count prim keys == 1 */
        $script .= "
            \$objs = ".$this->getPeerClassname()."::doSelect(\$criteria, \$con);
        }
        return \$objs;
    }
";
    }

    /**
     * Adds the retrieveByPK method for tables with multi-column primary key.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addRetrieveByPK_MultiPK(&$script)
    {
        $table = $this->getTable();
        $script .= "
    /**
     * Retrieve object using using composite pkey values.
     ";
        foreach ($table->getPrimaryKey() as $col) {
            $clo = strtolower($col->getName());
            $cptype = $col->getPhpNative();
            $script .= "* @param $cptype $".$clo."
       ";
       }
       $script .= " * @param      Connection \$con
     * @return     ".$table->getPhpName()."
     */
    public static function ".$this->getRetrieveMethodName()."(";
        $co = 0;
        foreach ($table->getPrimaryKey() as $col) {
            $clo = strtolower($col->getName());
            $script .= ($co++ ? ", " : "") . "$".$clo;
        } /* foreach */
        $script .= ", \$con = null)
    {
        if (\$con === null) {
            \$con = Propel::getConnection(self::DATABASE_NAME);
        }
        \$criteria = new Criteria();";
        foreach ($table->getPrimaryKey() as $col) {
            $clo = strtolower($col->getName());
            $script .= "
        \$criteria->add(".$this->getColumnConstant($col).", $".$clo.");";
        }
        $script .= "
        \$v = ".$this->getPeerClassname()."::doSelect(\$criteria, \$con);

        return !empty(\$v) ? \$v[0] : null;
    }
";
    }

    /**
     * Adds the getTableMap() method which is a convenience method for apps to get DB metadata.
     * @param      string &$script The script will be modified in this method.
     */
    protected function addGetTableMap(&$script)
    {
        $script .= "
    /**
     * Returns the TableMap related to this peer.
     * This method is not needed for general use but a specific application could have a need.
     * @return     TableMap
     * @throws     PropelException Any exceptions caught during processing will be
     *       rethrown wrapped into a PropelException.
     */
    public static function getTableMap()
    {
        return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    }
";

    }
} // PHP5BasicPeerBuilder
