/**
     * Generates the base object class
     *
     * @return string the generated PHP code
     * @author Anthony Bush
     **/
    protected function generateBaseObject($table)
    {
        $dbName = $table->getDatabase()->getDatabaseName();
        $tableName = $table->getTableName();
        $starterObjectClassName = $this->config->getStarterObjectClassName($table);
        $starterCollectionClassName = $this->config->getStarterCollectionClassName($table);
        $baseObjectClassName = $this->config->getBaseObjectClassName($table);
        $baseCollectionClassName = $this->config->getBaseCollectionClassName($table);
        $phpdocTags = $this->generatePhpdocTags($table);
        $phpdocTags[] = '@see ' . $starterObjectClassName . ', CoughObject';
        $extensionClassName = $this->config->getObjectExtensionClassName($table);
        // Generate attribute methods
        ob_start();
        foreach ($table->getColumns() as $columnName => $column) {
            $titleCase = $this->config->getTitleCase($columnName);
            ?>
	public function get<?php 
            echo $titleCase;
            ?>
() {
		return $this->getField('<?php 
            echo $columnName;
            ?>
');
	}
	
	public function set<?php 
            echo $titleCase;
            ?>
($value) {
		$this->setField('<?php 
            echo $columnName;
            ?>
', $value);
	}
	
<?php 
        }
        $attributeMethods = ob_get_clean();
        // Generate one-to-one methods
        $oneToOneMethods = '';
        $objectDefinitions = array();
        foreach ($table->getHasOneRelationships() as $hasOne) {
            if (!$this->config->shouldGenerateHasOneMethods($hasOne)) {
                continue;
            }
            $objectClassName = $this->config->getStarterObjectClassName($hasOne->getRefTable());
            $entityName = $this->config->getForeignTableAliasName($hasOne);
            // e.g. 'billing_address'
            $objectName = $this->config->getForeignObjectName($hasOne);
            // e.g. 'BillingAddress_Object'
            // Get the local variable name
            $localVarName = $this->config->getCamelCase($entityName);
            // e.g. 'billingAddress';
            if ($localVarName == 'this') {
                // avoid naming conflict by renaming a "this" object name to "object"
                $localVarName = 'object';
            }
            $localKey = $hasOne->getLocalKey();
            $objectDefinitions[] = "\n\t\t'" . $objectName . "' => array(" . "\n\t\t\t'class_name' => '" . $objectClassName . "'\n\t\t),";
            // generate load*_Object()
            $oneToOneMethods .= "\tpublic function load" . $objectName . "() {\n";
            $refKey = $hasOne->getRefKey();
            if (count($refKey) == 1) {
                // Only one column key -- generate simplified code (one line)
                reset($refKey);
                list($key) = each($refKey);
                $titleCase = $this->config->getTitleCase($localKey[$key]->getColumnName());
                $oneToOneMethods .= "\t\t\$this->set" . $objectName . "(" . $objectClassName . "::constructByKey(\$this->get" . $titleCase . "()));\n";
            } else {
                // Multi-column key
                $oneToOneMethods .= "\t\t\$tableName = " . $objectClassName . "::getTableName();\n" . "\t\t\$" . $localVarName . " = " . $objectClassName . "::constructByKey(array(\n";
                foreach ($refKey as $key => $column) {
                    $titleCase = $this->config->getTitleCase($localKey[$key]->getColumnName());
                    $oneToOneMethods .= "\t\t\t'`' . \$tableName . '`.`" . $column->getColumnName() . "`' => \$this->get" . $titleCase . "(),\n";
                }
                $oneToOneMethods .= "\t\t));\n" . "\t\t\$this->set" . $objectName . "(\$" . $localVarName . ");\n";
            }
            $oneToOneMethods .= "\t}\n\t\n";
            // generate get*_Object()
            $oneToOneMethods .= "\tpublic function get" . $objectName . "() {\n" . "\t\tif (!isset(\$this->objects['" . $objectName . "'])) {\n" . "\t\t\t\$this->load" . $objectName . "();\n" . "\t\t}\n" . "\t\treturn \$this->objects['" . $objectName . "'];\n" . "\t}\n\t\n";
            // generate set*_Object()
            $oneToOneMethods .= "\tpublic function set" . $objectName . "(\$" . $localVarName . ") {\n" . "\t\t\$this->objects['" . $objectName . "'] = \$" . $localVarName . ";\n" . "\t}\n\t\n";
        }
        // Generate the objectDefinitions parameter
        if (empty($objectDefinitions)) {
            $objectDefinitionsPhp = "\t" . 'protected $objectDefinitions = array();' . "\n\t\n";
        } else {
            $objectDefinitionsPhp = "\t" . 'protected $objectDefinitions = array(' . implode('', $objectDefinitions) . "\n\t" . ');' . "\n\t\n";
        }
        // Generate one-to-many methods
        ob_start();
        $notifyCollections = array();
        // store generated foreachs for the `notifyChildrenOfKeyChange()` method we will be generating.
        foreach ($table->getHasManyRelationships() as $hasMany) {
            if (!$this->config->shouldGenerateHasManyMethods($hasMany)) {
                continue;
            }
            $localCollectionName = $this->config->getForeignCollectionName($hasMany, $table->getHasManyRelationships());
            // e.g. WflTicket_Collection_ByBillingAddressId
            $localCollectionClassName = $this->config->getStarterCollectionClassName($hasMany->getRefTable());
            // e.g. usr_WflTicket_Collection
            // Some debug....
            // echo 'Generating ' . $baseObjectClassName . "<br />\n";
            // echo 'Ref Table Name: ' . $hasMany->getRefTable()->getTableName() . "<br />\n";
            // echo 'Local Table Name: ' . $hasMany->getLocalTable()->getTableName() . "<br />\n";
            // echo 'Ref Keys: ';
            // foreach ($hasMany->getRefKey() as $column) {
            // 	echo $column->getColumnName() . ',';
            // }
            // echo "<br />\n";
            // echo 'Local Keys: ';
            // foreach ($hasMany->getLocalKey() as $column) {
            // 	echo $column->getColumnName() . ',';
            // }
            // echo "<br />\n";
            // echo 'Local collection name: ' . $localCollectionName . "<br />\n";
            // echo 'Local collection class name: ' . $localCollectionClassName . "<br />\n";
            // die();
            // 2007-10-24/AWB: TODO: make this better
            $shouldGenerateAddersAndRemovers = true;
            if (strpos($localCollectionName, '_By') !== false) {
                $shouldGenerateAddersAndRemovers = false;
            }
            $refEntityName = $this->config->getEntityName($hasMany->getRefTable());
            // e.g. wfl_ticket
            $refObjectTitleCase = $this->config->getTitleCase($refEntityName);
            // e.g. WflTicket
            $refObjectCamelCase = $this->config->getCamelCase($refEntityName);
            // e.g. wflTicket
            $refObjectClassName = $this->config->getStarterObjectClassName($hasMany->getRefTable());
            // e.g. usr_WflTicket
            $localKey = $hasMany->getLocalKey();
            $refKey = $hasMany->getRefKey();
            $refObjectName = $this->config->getForeignObjectName($hasMany->getHasOneRelationship());
            // e.g. BillingAddress_Object
            $refTableAliasName = $hasMany->getRefTable()->getTableName();
            // $this->config->getForeignTableAliasName($hasMany->getHasOneRelationship()); // e.g. billing_address
            $localVarName = $refObjectCamelCase . 'Collection';
            $notifySql = "\t\tforeach (\$this->get" . $localCollectionName . "() as \$" . $refObjectCamelCase . ") {\n";
            foreach ($refKey as $key => $column) {
                $setter = 'set' . $this->config->getTitleCase($column->getColumnName());
                $notifySql .= "\t\t\t\$" . $refObjectCamelCase . "->" . $setter . "(\$key['" . $localKey[$key]->getColumnName() . "']);\n";
            }
            $notifySql .= "\t\t}";
            $notifyCollections[] = $notifySql;
            // Generate the criteria / WHERE clause information for loading the related object.
            $criteria = array();
            foreach ($refKey as $key => $column) {
                $criteria[] = "`' . \$tableName . '`.`" . $column->getColumnName() . '` = \' . $db->quote($this->get' . $this->config->getTitleCase($localKey[$key]->getColumnName()) . '()) . \'';
            }
            // Build the loadSql for loading the related object.
            list($variables, $loadSql) = $this->generateLoadSql($hasMany->getRefTable(), array($table->getTableName()), "\t\t\t\t");
            if (count($criteria) > 0) {
                $loadSql .= "\n\t\t\t\tWHERE\n\t\t\t\t\t" . implode("\n\t\t\t\t\t", $criteria);
            }
            ?>
	public function load<?php 
            echo $localCollectionName;
            ?>
() {
		
		// Always create the collection
		$collection = new <?php 
            echo $localCollectionClassName;
            ?>
();
		$this->set<?php 
            echo $localCollectionName;
            ?>
($collection);
		
		// But only populate it if we have key ID
		if ($this->hasKeyId()) {
			$db = <?php 
            echo $refObjectClassName;
            ?>
::getDb();
			<?php 
            echo implode("\n\t\t\t", $variables) . "\n";
            ?>
			$sql = '<?php 
            echo "\n" . $loadSql . "\n\t\t\t";
            ?>
';

			// Construct and populate the collection
			$collection->loadBySql($sql);
			foreach ($collection as $element) {
				$element->set<?php 
            echo $refObjectName;
            ?>
($this);
			}
		}
	}
	
	public function get<?php 
            echo $localCollectionName;
            ?>
() {
		if (!isset($this->collections['<?php 
            echo $localCollectionName;
            ?>
'])) {
			$this->load<?php 
            echo $localCollectionName;
            ?>
();
		}
		return $this->collections['<?php 
            echo $localCollectionName;
            ?>
'];
	}
	
	public function set<?php 
            echo $localCollectionName;
            ?>
($<?php 
            echo $localVarName;
            ?>
) {
		$this->collections['<?php 
            echo $localCollectionName;
            ?>
'] = $<?php 
            echo $localVarName;
            ?>
;
	}
	
<?php 
            if ($shouldGenerateAddersAndRemovers) {
                ?>
	public function add<?php 
                echo $refObjectTitleCase;
                ?>
(<?php 
                echo $refObjectClassName;
                ?>
 $object) {
<?php 
                foreach ($hasMany->getRefKey() as $key => $column) {
                    $setReferenceIdMethod = 'set' . $this->config->getTitleCase($column->getColumnName());
                    $getLocalIdMethod = 'get' . $this->config->getTitleCase($localKey[$key]->getColumnName());
                    ?>
		$object-><?php 
                    echo $setReferenceIdMethod;
                    ?>
($this-><?php 
                    echo $getLocalIdMethod;
                    ?>
());
<?php 
                }
                ?>
		$object->set<?php 
                echo $refObjectName;
                ?>
($this);
		$this->get<?php 
                echo $localCollectionName;
                ?>
()->add($object);
		return $object;
	}
	
	public function remove<?php 
                echo $refObjectTitleCase;
                ?>
($objectOrId) {
		$removedObject = $this->get<?php 
                echo $localCollectionName;
                ?>
()->remove($objectOrId);
		if (is_object($removedObject)) {
<?php 
                foreach ($hasMany->getRefKey() as $key => $column) {
                    ?>
			$removedObject->set<?php 
                    echo $this->config->getTitleCase($column->getColumnName());
                    ?>
(<?php 
                    echo $this->getDefaultValueStringForColumn($column);
                    ?>
);
<?php 
                }
                ?>
			$removedObject->set<?php 
                echo $refObjectName;
                ?>
(null);
		}
		return $removedObject;
	}
	
<?php 
            }
        }
        $oneToManyMethods = ob_get_clean();
        // Generate the `notifyChildrenOfKeyChange()` method if it will be non-empty.
        if (count($notifyCollections) > 0) {
            $notifyChildrenOfKeyChangePhp = "\t" . 'public function notifyChildrenOfKeyChange(array $key) {' . "\n" . implode("\n", $notifyCollections) . "\n\t}\n\t\n";
        } else {
            $notifyChildrenOfKeyChangePhp = '';
        }
        // Loop through all related one-to-one relationships and if any require a
        // non-NULL foreign key (i.e. the relationship MUST exist) go ahead and
        // override the default getLoadSqlWithoutWhere method.
        $shouldOverrideLoadSqlWithoutWhere = false;
        foreach ($table->getHasOneRelationships() as $hasOne) {
            if (!$hasOne->isKeyNullable($hasOne->getLocalKey())) {
                $shouldOverrideLoadSqlWithoutWhere = true;
                break;
            }
        }
        // Generate the `getLoadSqlWithoutWhere()` method if needed
        // NOTE: we always generate this in PHP < 5.3 (no "static" keyword => have to generate all static methods)
        if (true || $shouldOverrideLoadSqlWithoutWhere) {
            list($variables, $sql) = $this->generateLoadSql($table, array(), "\t\t\t");
            $getLoadSqlWithoutWherePhp = "\tpublic static function getLoadSql() {" . "\n\t\t" . implode("\n\t\t", $variables) . "\n\t\treturn '\n" . $sql . "\n\t\t';" . "\n\t}\n\t\n";
        } else {
            $getLoadSqlWithoutWherePhp = '';
        }
        // Generate class
        ob_start();
        echo "<?php\n\n";
        ?>
/**
 * This is the base class for <?php 
        echo $starterObjectClassName;
        ?>
.
 * 
 * <?php 
        echo implode("\n * ", $phpdocTags) . "\n";
        ?>
 **/
abstract class <?php 
        echo $baseObjectClassName;
        ?>
 extends <?php 
        echo $extensionClassName;
        ?>
 {
	
	protected static $db = null;
	protected static $dbName = '<?php 
        echo $dbName;
        ?>
';
	protected static $tableName = '<?php 
        echo $tableName;
        ?>
';
	protected static $pkFieldNames = array('<?php 
        echo implode("','", array_keys($table->getPrimaryKey()));
        ?>
');
	
	protected $fields = array(
<?php 
        foreach ($table->getColumns() as $columnName => $column) {
            ?>
		'<?php 
            echo $columnName;
            ?>
' => <?php 
            echo $this->getDefaultValueStringForColumn($column);
            ?>
,
<?php 
        }
        ?>
	);
	
	protected $fieldDefinitions = array(
<?php 
        foreach ($table->getColumns() as $columnName => $column) {
            ?>
		'<?php 
            echo $columnName;
            ?>
' => array(
			'db_column_name' => '<?php 
            echo $columnName;
            ?>
',
			'is_null_allowed' => <?php 
            echo $this->getStringFromPhpValue($column->isNullAllowed());
            ?>
,
			'default_value' => <?php 
            echo $this->getDefaultValueStringForColumn($column) . "\n";
            ?>
		),
<?php 
        }
        ?>
	);
	
<?php 
        echo $objectDefinitionsPhp;
        ?>
	// Static Definition Methods
	
	public static function getDb() {
		if (is_null(<?php 
        echo $starterObjectClassName;
        ?>
::$db)) {
			<?php 
        echo $starterObjectClassName;
        ?>
::$db = CoughDatabaseFactory::getDatabase(<?php 
        echo $starterObjectClassName;
        ?>
::$dbName);
		}
		return <?php 
        echo $starterObjectClassName;
        ?>
::$db;
	}
	
	public static function getDbName() {
		return CoughDatabaseFactory::getDatabaseName(<?php 
        echo $starterObjectClassName;
        ?>
::$dbName);
	}
	
	public static function getTableName() {
		return <?php 
        echo $starterObjectClassName;
        ?>
::$tableName;
	}
	
	public static function getPkFieldNames() {
		return <?php 
        echo $starterObjectClassName;
        ?>
::$pkFieldNames;
	}
	
	// Static Construction (factory) Methods
	
	/**
	 * Constructs a new <?php 
        echo $starterObjectClassName;
        ?>
 object from
	 * a single id (for single key PKs) or a hash of [field_name] => [field_value].
	 * 
	 * The key is used to pull data from the database, and, if no data is found,
	 * null is returned. You can use this function with any unique keys or the
	 * primary key as long as a hash is used. If the primary key is a single
	 * field, you may pass its value in directly without using a hash.
	 * 
	 * @param mixed $idOrHash - id or hash of [field_name] => [field_value]
	 * @return mixed - <?php 
        echo $starterObjectClassName;
        ?>
 or null if no record found.
	 **/
	public static function constructByKey($idOrHash, $forPhp5Strict = '') {
		return CoughObject::constructByKey($idOrHash, '<?php 
        echo $starterObjectClassName;
        ?>
');
	}
	
	/**
	 * Constructs a new <?php 
        echo $starterObjectClassName;
        ?>
 object from custom SQL.
	 * 
	 * @param string $sql
	 * @return mixed - <?php 
        echo $starterObjectClassName;
        ?>
 or null if exactly one record could not be found.
	 **/
	public static function constructBySql($sql, $forPhp5Strict = '') {
		return CoughObject::constructBySql($sql, '<?php 
        echo $starterObjectClassName;
        ?>
');
	}
	
	/**
	 * Constructs a new <?php 
        echo $starterObjectClassName;
        ?>
 object after
	 * checking the fields array to make sure the appropriate subclass is
	 * used.
	 * 
	 * No queries are run against the database.
	 * 
	 * @param array $hash - hash of [field_name] => [field_value] pairs
	 * @return <?php 
        echo $starterObjectClassName . "\n";
        ?>
	 **/
	public static function constructByFields($hash) {
		return new <?php 
        echo $starterObjectClassName;
        ?>
($hash);
	}
	
<?php 
        echo $notifyChildrenOfKeyChangePhp;
        echo $getLoadSqlWithoutWherePhp;
        echo "\t" . '// Generated attribute accessors (getters and setters)' . "\n\t\n";
        echo $attributeMethods;
        echo "\t" . '// Generated one-to-one accessors (loaders, getters, and setters)' . "\n\t\n";
        echo $oneToOneMethods;
        echo "\t" . '// Generated one-to-many collection loaders, getters, setters, adders, and removers' . "\n\t\n";
        echo $oneToManyMethods;
        ?>
}
<?php 
        echo "\n?>";
        // Add the class
        $class = new CoughClass();
        $class->setContents(ob_get_clean());
        $class->setIsStarterClass(false);
        $class->setIsCollectionClass(false);
        $class->setClassName($baseObjectClassName);
        $class->setDatabaseName($dbName);
        $class->setTableName($tableName);
        $this->addGeneratedClass($class);
    }