src/Propel/Generator/Builder/Om/TableMapBuilder.php
<?php
/**
* MIT License. This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Propel\Generator\Builder\Om;
use Propel\Generator\Model\ForeignKey;
use Propel\Generator\Model\IdMethod;
use Propel\Generator\Platform\PlatformInterface;
/**
* Generates the table map class for user object model (OM).
*
* @author Hans Lellelid <hans@xmpl.org>
*/
class TableMapBuilder extends AbstractOMBuilder
{
/**
* Gets the package for the map builder classes.
*
* @return string
*/
public function getPackage()
{
return parent::getPackage() . '.Map';
}
/**
* @return string
*/
public function getNamespace()
{
if (!$namespace = parent::getNamespace()) {
return 'Map';
}
if (
$this->getGeneratorConfig()
&& $omns = $this->getBuildProperty('generator.objectModel.namespaceMap')
) {
return $namespace . '\\' . $omns;
}
return $namespace . 'Map';
}
/**
* @return string
*/
public function getBaseTableMapClassName()
{
return 'TableMap';
}
/**
* Returns the name of the current class being built.
*
* @return string
*/
public function getUnprefixedClassName()
{
return $this->getTable()->getPhpName() . 'TableMap';
}
/**
* Adds class phpdoc comment and opening of class.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$script .= "
/**
* This class defines the structure of the '" . $table->getName() . "' table.
*
*";
if ($this->getBuildProperty('generator.objectModel.addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('general.version') . " on:
*
* $now
*";
}
$script .= "
*
* This map class is used by Propel to do runtime db structure discovery.
* For example, the createSelectSql() method checks the type of a given column used in an
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
* (i.e. if it's a text column type).
*/
class " . $this->getUnqualifiedClassName() . " extends TableMap
{
use InstancePoolTrait;
use TableMapTrait;
";
}
/**
* Specifies the methods that are added as part of the map builder class.
* This can be overridden by subclasses that wish to add more methods.
*
* @see ObjectBuilder::addClassBody()
*
* @param string $script
*
* @return void
*/
protected function addClassBody(&$script)
{
$table = $this->getTable();
$this->declareClasses(
'\Propel\Runtime\ActiveQuery\InstancePoolTrait',
'\Propel\Runtime\Map\TableMap',
'\Propel\Runtime\Map\TableMapTrait',
'\Propel\Runtime\Map\RelationMap',
'\Propel\Runtime\ActiveQuery\Criteria',
'\Propel\Runtime\Connection\ConnectionInterface',
'\Propel\Runtime\Exception\PropelException',
'\Propel\Runtime\DataFetcher\DataFetcherInterface',
'\Propel\Runtime\Propel'
);
$script .= $this->addConstants();
$this->addInheritanceColumnConstants($script);
if ($table->hasValueSetColumns()) {
$this->addValueSetColumnConstants($script);
}
// apply behaviors
$this->applyBehaviorModifier('staticConstants', $script, ' ');
$this->applyBehaviorModifier('staticAttributes', $script, ' ');
$this->applyBehaviorModifier('staticMethods', $script, ' ');
$this->addAttributes($script);
$script .= $this->addFieldsAttributes();
if ($table->hasValueSetColumns()) {
$this->addValueSetColumnAttributes($script);
$this->addGetValueSets($script);
$this->addGetValueSet($script);
}
$this->addInitialize($script);
$this->addBuildRelations($script);
$this->addGetBehaviors($script);
$script .= $this->addInstancePool();
$script .= $this->addClearRelatedInstancePool();
$this->addGetPrimaryKeyHash($script);
$this->addGetPrimaryKeyFromRow($script);
$this->addGetOMClassMethod($script);
$this->addPopulateObject($script);
$this->addPopulateObjects($script);
if (!$table->isAlias()) {
$this->addSelectMethods($script);
$this->addGetTableMap($script);
}
$this->addBuildTableMap($script);
$this->addDoDelete($script);
$this->addDoDeleteAll($script);
$this->addDoInsert($script);
}
/**
* Adds the addSelectColumns(), doCount(), etc. methods.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addSelectMethods(&$script)
{
$this->addAddSelectColumns($script);
}
/**
* Adds any constants needed for this TableMap class.
*
* @return string
*/
protected function addConstants()
{
return $this->renderTemplate('tableMapConstants', [
'className' => $this->getClasspath(),
'dbName' => $this->getDatabase()->getName(),
'tableName' => $this->getTable()->getName(),
'tablePhpName' => $this->getTable()->isAbstract() ? '' : addslashes($this->getStubObjectBuilder()->getFullyQualifiedClassName()),
'classPath' => $this->getStubObjectBuilder()->getClasspath(),
'nbColumns' => $this->getTable()->getNumColumns(),
'nbLazyLoadColumns' => $this->getTable()->getNumLazyLoadColumns(),
'nbHydrateColumns' => $this->getTable()->getNumColumns() - $this->getTable()->getNumLazyLoadColumns(),
'columns' => $this->getTable()->getColumns(),
'stringFormat' => $this->getTable()->getDefaultStringFormat(),
]);
}
/**
* Adds the COLUMN_NAME constant to the class definition.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addColumnNameConstants(&$script)
{
foreach ($this->getTable()->getColumns() as $col) {
$script .= "
/**
* the column name for the " . $col->getName() . " field
*/
const " . $col->getConstantName() . " = '" . $this->getTable()->getName() . '.' . $col->getName() . "';
";
}
}
/**
* Adds the valueSet constants for ENUM and SET columns.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addValueSetColumnConstants(&$script)
{
foreach ($this->getTable()->getColumns() as $col) {
if ($col->isValueSetType()) {
$script .= "
/** The enumerated values for the " . $col->getName() . ' field */';
foreach ($col->getValueSet() as $value) {
$script .= "
const " . $col->getConstantName() . '_' . $this->getValueSetConstant($value) . " = '" . $value . "';";
}
$script .= "
";
}
}
}
/**
* Adds the valueSet attributes for ENUM columns.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addValueSetColumnAttributes(&$script)
{
$script .= "
/** The enumerated values for this table */
protected static \$enumValueSets = array(";
foreach ($this->getTable()->getColumns() as $col) {
if ($col->isValueSetType()) {
$script .= "
{$col->getFQConstantName()} => array(
";
foreach ($col->getValueSet() as $value) {
$script .= ' self::' . $col->getConstantName() . '_' . $this->getValueSetConstant($value) . ",
";
}
$script .= ' ),';
}
}
$script .= "
);
";
}
/**
* Adds the getValueSets() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetValueSets(&$script)
{
$script .= "
/**
* Gets the list of values for all ENUM and SET columns
* @return array
*/
public static function getValueSets()
{
return static::\$enumValueSets;
}
";
}
/**
* Adds the getValueSet() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetValueSet(&$script)
{
$script .= "
/**
* Gets the list of values for an ENUM or SET column
* @param string \$colname
* @return array list of possible values for the column
*/
public static function getValueSet(\$colname)
{
\$valueSets = self::getValueSets();
return \$valueSets[\$colname];
}
";
}
/**
* Adds the CLASSKEY_* and CLASSNAME_* constants used for inheritance.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
public function addInheritanceColumnConstants(&$script)
{
if (!$col = $this->getTable()->getChildrenColumn()) {
return;
}
if (!$col->isEnumeratedClasses()) {
return;
}
foreach ($col->getChildren() as $child) {
$childBuilder = $this->getMultiExtendObjectBuilder();
$childBuilder->setChild($child);
$fqcn = addslashes($childBuilder->getFullyQualifiedClassName());
$script .= "
/** A key representing a particular subclass */
const CLASSKEY_" . $child->getConstantSuffix() . " = '" . $child->getKey() . "';
";
if (strtoupper($child->getClassName()) != $child->getConstantSuffix()) {
$script .= "
/** A key representing a particular subclass */
const CLASSKEY_" . strtoupper($child->getClassname()) . " = '" . $fqcn . "';
";
}
$script .= "
/** A class that can be returned by this tableMap. */
const CLASSNAME_" . $child->getConstantSuffix() . " = '" . $fqcn . "';
";
}
}
/**
* @param string $value
*
* @return string
*/
protected function getValueSetConstant($value)
{
return strtoupper(preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/', '_', $value));
}
/**
* Adds any attributes needed for this TableMap class.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addAttributes(&$script)
{
}
/**
* @return string
*/
protected function addFieldsAttributes()
{
$tableColumns = $this->getTable()->getColumns();
$fieldNamesPhpName = '';
$fieldNamesCamelCaseName = '';
$fieldNamesColname = '';
$fieldNamesRawColname = '';
$fieldNamesFieldName = '';
$fieldNamesNum = '';
$fieldKeysPhpName = '';
$fieldKeysCamelCaseName = '';
$fieldKeysColname = '';
$fieldKeysRawColname = '';
$fieldKeysFieldName = '';
$fieldKeysNum = '';
foreach ($tableColumns as $num => $col) {
$fieldNamesPhpName .= "'" . $col->getPhpName() . "', ";
$fieldNamesCamelCaseName .= "'" . $col->getCamelCaseName() . "', ";
$fieldNamesColname .= $this->getColumnConstant($col, $this->getTableMapClass()) . ', ';
$fieldNamesRawColname .= "'" . $col->getConstantName() . "', ";
$fieldNamesFieldName .= "'" . $col->getName() . "', ";
$fieldNamesNum .= "$num, ";
$fieldKeysPhpName .= "'" . $col->getPhpName() . "' => $num, ";
$fieldKeysCamelCaseName .= "'" . $col->getCamelCaseName() . "' => $num, ";
$fieldKeysColname .= $this->getColumnConstant($col, $this->getTableMapClass()) . " => $num, ";
$fieldKeysRawColname .= "'" . $col->getConstantName() . "' => $num, ";
$fieldKeysFieldName .= "'" . $col->getName() . "' => $num, ";
$fieldKeysNum .= "$num, ";
}
return $this->renderTemplate('tableMapFields', [
'fieldNamesPhpName' => $fieldNamesPhpName,
'fieldNamesCamelCaseName' => $fieldNamesCamelCaseName,
'fieldNamesColname' => $fieldNamesColname,
'fieldNamesRawColname' => $fieldNamesRawColname,
'fieldNamesFieldName' => $fieldNamesFieldName,
'fieldNamesNum' => $fieldNamesNum,
'fieldKeysPhpName' => $fieldKeysPhpName,
'fieldKeysCamelCaseName' => $fieldKeysCamelCaseName,
'fieldKeysColname' => $fieldKeysColname,
'fieldKeysRawColname' => $fieldKeysRawColname,
'fieldKeysFieldName' => $fieldKeysFieldName,
'fieldKeysNum' => $fieldKeysNum,
]);
}
/**
* Closes class.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getUnqualifiedClassName() . "
// This is the static code needed to register the TableMap for this table with the main Propel class.
//
" . $this->getUnqualifiedClassName() . "::buildTableMap();
";
$this->applyBehaviorModifier('tableMapFilter', $script, '');
}
/**
* Adds the buildTableMap() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addBuildTableMap(&$script)
{
$this->declareClassFromBuilder($this->getTableMapBuilder());
$script .= "
/**
* Add a TableMap instance to the database for this tableMap class.
*/
public static function buildTableMap()
{
\$dbMap = Propel::getServiceContainer()->getDatabaseMap(" . $this->getTableMapClass() . "::DATABASE_NAME);
if (!\$dbMap->hasTable(" . $this->getTableMapClass() . "::TABLE_NAME)) {
\$dbMap->addTableObject(new " . $this->getTableMapClass() . "());
}
}
";
}
/**
* Adds the addInitialize() method to the table map class.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addInitialize(&$script)
{
$table = $this->getTable();
/** @var \Propel\Generator\Platform\DefaultPlatform $platform */
$platform = $this->getPlatform();
$script .= "
/**
* Initialize the table attributes and columns
* Relations are not initialized by this method since they are lazy loaded
*
* @return void
* @throws PropelException
*/
public function initialize()
{
// attributes
\$this->setName('" . $table->getName() . "');
\$this->setPhpName('" . $table->getPhpName() . "');
\$this->setIdentifierQuoting(" . ($table->isIdentifierQuotingEnabled() ? 'true' : 'false') . ");
\$this->setClassName('" . addslashes($this->getStubObjectBuilder()->getFullyQualifiedClassName()) . "');
\$this->setPackage('" . parent::getPackage() . "');";
if ($table->getIdMethod() === 'native') {
$script .= "
\$this->setUseIdGenerator(true);";
} else {
$script .= "
\$this->setUseIdGenerator(false);";
}
if ($table->getIdMethodParameters()) {
$params = $table->getIdMethodParameters();
$imp = $params[0];
$script .= "
\$this->setPrimaryKeyMethodInfo('" . $imp->getValue() . "');";
} elseif ($table->getIdMethod() == IdMethod::NATIVE && ($platform->getNativeIdMethod() == PlatformInterface::SEQUENCE || $platform->getNativeIdMethod() == PlatformInterface::SERIAL)) {
$script .= "
\$this->setPrimaryKeyMethodInfo('" . $platform->getSequenceName($table) . "');";
}
if ($this->getTable()->getChildrenColumn()) {
$script .= "
\$this->setSingleTableInheritance(true);";
}
if ($this->getTable()->getIsCrossRef()) {
$script .= "
\$this->setIsCrossRef(true);";
}
// Add columns to map
$script .= "
// columns";
foreach ($table->getColumns() as $col) {
$columnName = $col->getName();
$cfc = $col->getPhpName();
if (!$col->getSize()) {
$size = 'null';
} else {
$size = $col->getSize();
}
$default = $col->getDefaultValueString();
if ($col->isPrimaryKey()) {
if ($col->isForeignKey()) {
foreach ($col->getForeignKeys() as $fk) {
$script .= "
\$this->addForeignPrimaryKey('$columnName', '$cfc', '" . $col->getType() . "' , '" . $fk->getForeignTableName() . "', '" . $fk->getMappedForeignColumn($col->getName()) . "', " . ($col->isNotNull() ? 'true' : 'false') . ', ' . $size . ", $default);";
}
} else {
$script .= "
\$this->addPrimaryKey('$columnName', '$cfc', '" . $col->getType() . "', " . var_export($col->isNotNull(), true) . ', ' . $size . ", $default);";
}
} else {
if ($col->isForeignKey()) {
foreach ($col->getForeignKeys() as $fk) {
$script .= "
\$this->addForeignKey('$columnName', '$cfc', '" . $col->getType() . "', '" . $fk->getForeignTableName() . "', '" . $fk->getMappedForeignColumn($col->getName()) . "', " . ($col->isNotNull() ? 'true' : 'false') . ', ' . $size . ", $default);";
}
} else {
$script .= "
\$this->addColumn('$columnName', '$cfc', '" . $col->getType() . "', " . var_export($col->isNotNull(), true) . ', ' . $size . ", $default);";
}
} // if col-is prim key
if ($col->isValueSetType()) {
$script .= "
\$this->getColumn('$columnName')->setValueSet(" . var_export($col->getValueSet(), true) . ');';
}
if ($col->isPrimaryString()) {
$script .= "
\$this->getColumn('$columnName')->setPrimaryString(true);";
}
}
$script .= "
} // initialize()
";
}
/**
* Adds the method that build the RelationMap objects
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addBuildRelations(&$script)
{
$script .= "
/**
* Build the RelationMap objects for this table relationships
*/
public function buildRelations()
{";
foreach ($this->getTable()->getForeignKeys() as $fkey) {
$joinCondition = var_export($fkey->getNormalizedMap($fkey->getMapping()), true);
$onDelete = $fkey->hasOnDelete() ? "'" . $fkey->getOnDelete() . "'" : 'null';
$onUpdate = $fkey->hasOnUpdate() ? "'" . $fkey->getOnUpdate() . "'" : 'null';
$isPolymorphic = $fkey->isPolymorphic() ? 'true' : 'false';
$script .= "
\$this->addRelation('" . $this->getFKPhpNameAffix($fkey) . "', '" . addslashes($this->getNewStubObjectBuilder($fkey->getForeignTable())->getFullyQualifiedClassName()) . "', RelationMap::MANY_TO_ONE, $joinCondition, $onDelete, $onUpdate, null, $isPolymorphic);";
}
foreach ($this->getTable()->getReferrers() as $fkey) {
$relationName = $this->getRefFKPhpNameAffix($fkey);
$joinCondition = var_export($fkey->getNormalizedMap($fkey->getMapping()), true);
$onDelete = $fkey->hasOnDelete() ? "'" . $fkey->getOnDelete() . "'" : 'null';
$onUpdate = $fkey->hasOnUpdate() ? "'" . $fkey->getOnUpdate() . "'" : 'null';
$isPolymorphic = $fkey->isPolymorphic() ? 'true' : 'false';
$script .= "
\$this->addRelation('$relationName', '" . addslashes($this->getNewStubObjectBuilder($fkey->getTable())->getFullyQualifiedClassName()) . "', RelationMap::ONE_TO_" . ($fkey->isLocalPrimaryKey() ? 'ONE' : 'MANY') . ", $joinCondition, $onDelete, $onUpdate";
if ($fkey->isLocalPrimaryKey()) {
$script .= ', null';
} else {
$script .= ", '" . $this->getRefFKPhpNameAffix($fkey, true) . "'";
}
$script .= ", $isPolymorphic);";
}
foreach ($this->getTable()->getCrossFks() as $crossFKs) {
foreach ($crossFKs->getCrossForeignKeys() as $crossFK) {
$relationName = $this->getFKPhpNameAffix($crossFK);
$pluralName = "'" . $this->getFKPhpNameAffix($crossFK, true) . "'";
$onDelete = $crossFK->hasOnDelete() ? "'" . $crossFK->getOnDelete() . "'" : 'null';
$onUpdate = $crossFK->hasOnUpdate() ? "'" . $crossFK->getOnUpdate() . "'" : 'null';
$script .= "
\$this->addRelation('$relationName', '" . addslashes($this->getNewStubObjectBuilder($crossFK->getForeignTable())->getFullyQualifiedClassName()) . "', RelationMap::MANY_TO_MANY, array(), $onDelete, $onUpdate, $pluralName);";
}
}
$script .= "
} // buildRelations()
";
}
/**
* Adds the behaviors getter
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetBehaviors(&$script)
{
$behaviors = $this->getTable()->getBehaviors();
if ($behaviors) {
$script .= "
/**
*
* Gets the list of behaviors registered for this table
*
* @return array Associative array (name => parameters) of behaviors
*/
public function getBehaviors()
{
return array(";
foreach ($behaviors as $behavior) {
$script .= "
'{$behavior->getId()}' => array(";
foreach ($behavior->getParameters() as $key => $value) {
$script .= "'$key' => ";
if (is_array($value)) {
$string = var_export($value, true);
$string = str_replace("\n", '', $string);
$string = str_replace(' ', '', $string);
$script .= $string . ', ';
} else {
$script .= "'$value', ";
}
}
$script .= '),';
}
$script .= "
);
} // getBehaviors()
";
}
}
/**
* Adds the PHP code to return a instance pool key for the passed-in primary key variable names.
*
* @param string[]|string $pkphp An array of PHP var names / method calls representing complete pk.
*
* @return string
*/
public function getInstancePoolKeySnippet($pkphp)
{
$pkphp = (array)$pkphp; // make it an array if it is not.
$script = '';
if (count($pkphp) > 1) {
$script .= 'serialize([';
$i = 0;
foreach ($pkphp as $pkvar) {
$script .= ($i++ ? ', ' : '') . "(null === {$pkvar} || is_scalar({$pkvar}) || is_callable([{$pkvar}, '__toString']) ? (string) {$pkvar} : {$pkvar})";
}
$script .= '])';
} else {
$script .= "null === {$pkphp[0]} || is_scalar({$pkphp[0]}) || is_callable([{$pkphp[0]}, '__toString']) ? (string) {$pkphp[0]} : {$pkphp[0]}";
}
return $script;
}
/**
* @return string
*/
public function addInstancePool()
{
// No need to override instancePool if the PK is not composite
if (!$this->getTable()->hasCompositePrimaryKey()) {
return '';
}
$pks = $this->getTable()->getPrimaryKey();
if (!count($pks)) {
return '';
}
$add = [];
$removeObjects = [];
foreach ($pks as $pk) {
$add[] = '$obj->get' . $pk->getPhpName() . '()';
$removeObjects[] = '$value->get' . $pk->getPhpName() . '()';
}
$addInstancePoolKeySnippet = $this->getInstancePoolKeySnippet($add);
$removeInstancePoolKeySnippetObjects = $this->getInstancePoolKeySnippet($removeObjects);
$removePks = [];
$nbPks = count($pks);
for ($i = 0; $i < $nbPks; $i++) {
$removePks[] = "\$value[$i]";
}
$removeInstancePoolKeySnippetPks = $this->getInstancePoolKeySnippet($removePks);
return $this->renderTemplate('tableMapInstancePool', [
'objectClassName' => $this->getStubObjectBuilder()->getClassName(),
'addInstancePoolKeySnippet' => $addInstancePoolKeySnippet,
'removeInstancePoolKeySnippetObjects' => $removeInstancePoolKeySnippetObjects,
'removeInstancePoolKeySnippetPks' => $removeInstancePoolKeySnippetPks,
'countPks' => count($pks),
]);
}
/**
* @return string
*/
public function addClearRelatedInstancePool()
{
$table = $this->getTable();
$relatedClassNames = [];
// Handle ON DELETE CASCADE for updating instance pool
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();
$joinedTableTableMapBuilder = $this->getNewTableMapBuilder($tblFK)->getTableMapBuilder();
$tableMapClassName = $this->declareClassFromBuilder($joinedTableTableMapBuilder, true);
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.)
if ($fk->getOnDelete() === ForeignKey::CASCADE || $fk->getOnDelete() === ForeignKey::SETNULL) {
$relatedClassNames[$tableMapClassName] = $tableMapClassName;
}
}
}
if (count($relatedClassNames) == 0) {
return '';
}
return $this->renderTemplate('tableMapClearRelatedInstancePool', [
'tableName' => $table->getName(),
'relatedClassNames' => $relatedClassNames,
]);
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
*
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $modifier
*
* @return bool
*/
public function hasBehaviorModifier($hookName, $modifier = '')
{
return parent::hasBehaviorModifier($hookName, 'TableMapBuilderModifier');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
*
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $script The script will be modified in this method.
* @param string $tab
*
* @return void
*/
public function applyBehaviorModifier($hookName, &$script, $tab = ' ')
{
$this->applyBehaviorModifierBase($hookName, 'TableMapBuilderModifier', $script, $tab);
}
/**
* Adds method to get a version of the primary key that can be used as a unique key for identifier map.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetPrimaryKeyHash(&$script)
{
// We have to iterate through all the columns so that we know the offset of the primary
// key columns.
$n = 0;
$pk = [];
$cond = [];
foreach ($this->getTable()->getColumns() as $col) {
if (!$col->isLazyLoad()) {
if ($col->isPrimaryKey()) {
$part = "\$row[TableMap::TYPE_NUM == \$indexType ? $n + \$offset : static::translateFieldName('{$col->getPhpName()}', TableMap::TYPE_PHPNAME, \$indexType)]";
$cond[] = $part . ' === null';
$pk[] = $part;
}
$n++;
}
}
$script .= "
/**
* Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table.
*
* For tables with a single-column primary key, that simple pkey value will be returned. For tables with
* a multi-column primary key, a serialize()d version of the primary key will be returned.
*
* @param array \$row resultset row.
* @param int \$offset The 0-based offset for reading from the resultset row.
* @param string \$indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM
*
* @return string The primary key hash of the row
*/
public static function getPrimaryKeyHashFromRow(\$row, \$offset = 0, \$indexType = TableMap::TYPE_NUM)
{";
if (count($pk) > 0) {
$script .= "
// If the PK cannot be derived from the row, return NULL.
if (" . implode(' && ', $cond) . ") {
return null;
}
return " . $this->getInstancePoolKeySnippet($pk) . ";
}
";
} else {
$script .= "
return null;
}
";
}
}
/**
* Adds method to get the primary key from a row
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetPrimaryKeyFromRow(&$script)
{
$script .= "
/**
* Retrieves the primary key from the DB resultset row
* For tables with a single-column primary key, that simple pkey value will be returned. For tables with
* a multi-column primary key, an array of the primary key columns will be returned.
*
* @param array \$row resultset row.
* @param int \$offset The 0-based offset for reading from the resultset row.
* @param string \$indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM
*
* @return mixed The primary key of the row
*/
public static function getPrimaryKeyFromRow(\$row, \$offset = 0, \$indexType = TableMap::TYPE_NUM)
{";
// We have to iterate through all the columns so that we
// know the offset of the primary key columns.
$table = $this->getTable();
$n = 0;
if ($table->hasCompositePrimaryKey()) {
$script .= "
\$pks = [];
";
$pks = [];
foreach ($table->getColumns() as $col) {
if (!$col->isLazyLoad()) {
if ($col->isPrimaryKey()) {
$script .= '
$pks[] = ' . ($col->isPhpObjectType() ? 'new ' . $col->getPhpType() . '(' : '(' . $col->getPhpType() . ') ') . "\$row[
\$indexType == TableMap::TYPE_NUM
? $n + \$offset
: self::translateFieldName('{$col->getPhpName()}', TableMap::TYPE_PHPNAME, \$indexType)
]" . ($col->isPhpObjectType() ? ')' : '') . ';';
}
$n++;
}
}
$script .= "
return \$pks;";
} else {
$pk = "''";
foreach ($table->getColumns() as $col) {
if (!$col->isLazyLoad()) {
if ($col->isPrimaryKey()) {
$pk = ($col->isPhpObjectType() ? 'new ' . $col->getPhpType() . '(' : '(' . $col->getPhpType() . ') ') . "\$row[
\$indexType == TableMap::TYPE_NUM
? $n + \$offset
: self::translateFieldName('{$col->getPhpName()}', TableMap::TYPE_PHPNAME, \$indexType)
]" . ($col->isPhpObjectType() ? ')' : '');
}
$n++;
}
}
$script .= "
return " . $pk . ';';
}
$script .= "
}
";
}
/**
* Adds the correct getOMClass() method, depending on whether this table uses inheritance.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetOMClassMethod(&$script)
{
$table = $this->getTable();
if ($table->getChildrenColumn()) {
$this->addGetOMClass_Inheritance($script);
} else {
if ($table->isAbstract()) {
$this->addGetOMClass_NoInheritance_Abstract($script);
} else {
$this->addGetOMClass_NoInheritance($script);
}
}
}
/**
* Adds a getOMClass() for non-abstract tables that have inheritance.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
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 array \$row ConnectionInterface result row.
* @param int \$colnum Column to examine for OM class information (first is 0).
* @param boolean \$withPrefix Whether or not to return the path with the class name
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*
* @return string The OM class
*/
public static function getOMClass(\$row, \$colnum, \$withPrefix = true)
{
try {
";
if ($col->isEnumeratedClasses()) {
$script .= "
\$omClass = null;
\$classKey = \$row[\$colnum + " . ($col->getPosition() - 1) . "];
switch (\$classKey) {
";
foreach ($col->getChildren() as $child) {
$script .= "
case {$this->getTableMapClassName()}::CLASSKEY_" . $child->getConstantSuffix() . ":
\$omClass = {$this->getTableMapClassName()}::CLASSNAME_" . $child->getConstantSuffix() . ";
break;
";
} /* foreach */
$script .= "
default:
\$omClass = {$this->getTableMapClassName()}::CLASS_DEFAULT;
";
$script .= "
} // switch
if (!\$withPrefix) {
\$omClass = preg_replace('#\.#', '\\\\', \$omClass);
}
";
} else { /* if not enumerated */
$script .= "
\$omClass = \$row[\$colnum + " . ($col->getPosition() - 1) . "];
\$omClass = preg_replace('#\.#', '\\\\', '.'.\$omClass);
";
}
$script .= "
} catch (\Exception \$e) {
throw new PropelException('Unable to get OM class.', \$e);
}
return \$omClass;
}
";
}
/**
* Adds a getOMClass() for non-abstract tables that do note use inheritance.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetOMClass_NoInheritance(&$script)
{
$script .= "
/**
* The class that the tableMap will make instances of.
*
* If \$withPrefix is true, the returned path
* uses a dot-path notation which is translated into a path
* relative to a location on the PHP include_path.
* (e.g. path.to.MyClass -> 'path/to/MyClass.php')
*
* @param boolean \$withPrefix Whether or not to return the path with the class name
* @return string path.to.ClassName
*/
public static function getOMClass(\$withPrefix = true)
{
return \$withPrefix ? " . $this->getTableMapClass() . '::CLASS_DEFAULT : ' . $this->getTableMapClass() . "::OM_CLASS;
}
";
}
/**
* Adds a getOMClass() signature for abstract tables that do not have inheritance.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addGetOMClass_NoInheritance_Abstract(&$script)
{
$script .= "
/**
* The class that the tableMap will make instances of.
*
* This method must be overridden by the stub subclass, because
* " . $this->getObjectClassName() . " is declared abstract in the schema.
*
* @param boolean \$withPrefix
*/
abstract public static function getOMClass(\$withPrefix = true);
";
}
/**
* Adds the populateObject() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addPopulateObject(&$script)
{
$table = $this->getTable();
$script .= "
/**
* Populates an object of the default type or an object that inherit from the default.
*
* @param array \$row row returned by DataFetcher->fetch().
* @param int \$offset The 0-based offset for reading from the resultset row.
* @param string \$indexType The index type of \$row. Mostly DataFetcher->getIndexType().
One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME
* TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM.
*
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
* @return array (" . $this->getObjectClassName() . " object, last column rank)
*/
public static function populateObject(\$row, \$offset = 0, \$indexType = TableMap::TYPE_NUM)
{
\$key = {$this->getTableMapClassName()}::getPrimaryKeyHashFromRow(\$row, \$offset, \$indexType);
if (null !== (\$obj = {$this->getTableMapClassName()}::getInstanceFromPool(\$key))) {
// We no longer rehydrate the object, since this can cause data loss.
// See http://www.propelorm.org/ticket/509
// \$obj->hydrate(\$row, \$offset, true); // rehydrate
\$col = \$offset + " . $this->getTableMapClass() . '::NUM_HYDRATE_COLUMNS;';
if ($table->isAbstract()) {
$script .= "
} elseif (null == \$key) {
// empty resultset, probably from a left join
// since this table is abstract, we can't hydrate an empty object
\$obj = null;
\$col = \$offset + " . $this->getTableMapClass() . '::NUM_HYDRATE_COLUMNS;';
}
$script .= "
} else {";
if (!$table->getChildrenColumn()) {
$script .= "
\$cls = " . $this->getTableMapClass() . '::OM_CLASS;';
} else {
$script .= "
\$cls = static::getOMClass(\$row, \$offset, false);";
}
$script .= "
/** @var {$this->getObjectClassName()} \$obj */
\$obj = new \$cls();
\$col = \$obj->hydrate(\$row, \$offset, false, \$indexType);
{$this->getTableMapClassName()}::addInstanceToPool(\$obj, \$key);
}
return array(\$obj, \$col);
}
";
}
/**
* Adds the populateObjects() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
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.
*
* @param DataFetcherInterface \$dataFetcher
* @return array
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function populateObjects(DataFetcherInterface \$dataFetcher)
{
\$results = array();
";
if (!$table->getChildrenColumn()) {
$script .= "
// set the class once to avoid overhead in the loop
\$cls = static::getOMClass(false);";
}
$script .= "
// populate the object(s)
while (\$row = \$dataFetcher->fetch()) {
\$key = {$this->getTableMapClassName()}::getPrimaryKeyHashFromRow(\$row, 0, \$dataFetcher->getIndexType());
if (null !== (\$obj = {$this->getTableMapClassName()}::getInstanceFromPool(\$key))) {
// We no longer rehydrate the object, since this can cause data loss.
// See http://www.propelorm.org/ticket/509
// \$obj->hydrate(\$row, 0, true); // rehydrate
\$results[] = \$obj;
} else {";
if ($table->getChildrenColumn()) {
$script .= "
// class must be set each time from the record row
\$cls = static::getOMClass(\$row, 0);
\$cls = preg_replace('#\.#', '\\\\', \$cls);
/** @var {$this->getObjectClassName()} \$obj */
" . $this->buildObjectInstanceCreationCode('$obj', '$cls') . "
\$obj->hydrate(\$row);
\$results[] = \$obj;
{$this->getTableMapClassName()}::addInstanceToPool(\$obj, \$key);";
} else {
$script .= "
/** @var {$this->getObjectClassName()} \$obj */
" . $this->buildObjectInstanceCreationCode('$obj', '$cls') . "
\$obj->hydrate(\$row);
\$results[] = \$obj;
{$this->getTableMapClassName()}::addInstanceToPool(\$obj, \$key);";
}
$script .= "
} // if key exists
}
return \$results;
}";
}
/**
* Adds the addSelectColumns() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
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 \$criteria object containing the columns to add.
* @param string \$alias optional table alias
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function addSelectColumns(Criteria \$criteria, \$alias = null)
{
if (null === \$alias) {";
foreach ($this->getTable()->getColumns() as $col) {
if (!$col->isLazyLoad()) {
$script .= "
\$criteria->addSelectColumn({$col->getFQConstantName()});";
} // if !col->isLazyLoad
}
$script .= "
} else {";
foreach ($this->getTable()->getColumns() as $col) {
if (!$col->isLazyLoad()) {
$script .= "
\$criteria->addSelectColumn(\$alias . '." . $col->getName() . "');";
} // if !col->isLazyLoad
}
$script .= "
}";
$script .= "
}
";
}
// addAddSelectColumns()
/**
* 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.
*
* @return void
*/
protected function addGetTableMap(&$script)
{
$script .= "
/**
* Returns the TableMap related to this object.
* 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::getServiceContainer()->getDatabaseMap(" . $this->getTableMapClass() . '::DATABASE_NAME)->getTable(' . $this->getTableMapClass() . "::TABLE_NAME);
}
";
}
/**
* Adds the doDeleteAll() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addDoDeleteAll(&$script)
{
$table = $this->getTable();
$script .= "
/**
* Deletes all rows from the " . $table->getName() . " table.
*
* @param ConnectionInterface \$con the connection to use
* @return int The number of affected rows (if supported by underlying database driver).
*/
public static function doDeleteAll(ConnectionInterface \$con = null)
{
return " . $this->getQueryClassName() . "::create()->doDeleteAll(\$con);
}
";
}
/**
* Adds the doDelete() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addDoDelete(&$script)
{
$table = $this->getTable();
$script .= "
/**
* Performs a DELETE on the database, given a " . $this->getObjectClassName() . " or Criteria object OR a primary key value.
*
* @param mixed \$values Criteria or " . $this->getObjectClassName() . " object or primary key or array of primary keys
* which is used to create the DELETE statement
* @param ConnectionInterface \$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, ConnectionInterface \$con = null)
{
if (null === \$con) {
\$con = Propel::getServiceContainer()->getWriteConnection(" . $this->getTableMapClass() . "::DATABASE_NAME);
}
if (\$values instanceof Criteria) {";
$script .= "
// rename for clarity
\$criteria = \$values;
} elseif (\$values instanceof \\" . $this->getStubObjectBuilder()->getQualifiedClassName() . ") { // it's a model object";
if (count($table->getPrimaryKey()) > 0) {
$script .= "
// create criteria based on pk values
\$criteria = \$values->buildPkeyCriteria();";
} else {
$script .= "
// create criteria based on pk value
\$criteria = \$values->buildCriteria();";
}
$script .= "
} else { // it's a primary key, or an array of pks";
if (!$table->getPrimaryKey()) {
$class = $this->getObjectName();
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('The $class object has no primary key');";
} else {
$script .= "
\$criteria = new Criteria(" . $this->getTableMapClass() . '::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);
}
foreach (\$values as \$value) {";
$i = 0;
foreach ($table->getPrimaryKey() as $col) {
if ($i === 0) {
$script .= "
\$criterion = \$criteria->getNewCriterion(" . $this->getColumnConstant($col) . ", \$value[$i]);";
} else {
$script .= "
\$criterion->addAnd(\$criteria->getNewCriterion(" . $this->getColumnConstant($col) . ", \$value[$i]));";
}
$i++;
}
$script .= "
\$criteria->addOr(\$criterion);";
$script .= "
}";
} /* if count(table->getPrimaryKeys()) */
}
$script .= "
}
\$query = " . $this->getQueryClassName() . "::create()->mergeWith(\$criteria);
if (\$values instanceof Criteria) {
{$this->getTableMapClassName()}::clearInstancePool();
} elseif (!is_object(\$values)) { // it's a primary key, or an array of pks
foreach ((array) \$values as \$singleval) {
{$this->getTableMapClassName()}::removeInstanceFromPool(\$singleval);
}
}
return \$query->delete(\$con);
}
";
}
/**
* Adds the doInsert() method.
*
* @param string $script The script will be modified in this method.
*
* @return void
*/
protected function addDoInsert(&$script)
{
$table = $this->getTable();
$tableMapClass = $this->getTableMapClass();
$script .= "
/**
* Performs an INSERT on the database, given a " . $this->getObjectClassName() . " or Criteria object.
*
* @param mixed \$criteria Criteria or " . $this->getObjectClassName() . " object containing data that is used to create the INSERT statement.
* @param ConnectionInterface \$con the ConnectionInterface 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(\$criteria, ConnectionInterface \$con = null)
{
if (null === \$con) {
\$con = Propel::getServiceContainer()->getWriteConnection(" . $tableMapClass . "::DATABASE_NAME);
}
if (\$criteria instanceof Criteria) {
\$criteria = clone \$criteria; // rename for clarity
} else {
\$criteria = \$criteria->buildCriteria(); // build Criteria from " . $this->getObjectClassName() . " object
}
";
foreach ($table->getColumns() as $col) {
if (
$col->isPrimaryKey()
&& $col->isAutoIncrement()
&& $table->getIdMethod() !== 'none'
&& !$table->isAllowPkInsert()
) {
$script .= "
if (\$criteria->containsKey(" . $this->getColumnConstant($col) . ') && $criteria->keyContainsValue(' . $this->getColumnConstant($col) . ") ) {
throw new PropelException('Cannot insert a value for auto-increment primary key ('." . $this->getColumnConstant($col) . ".')');
}
";
if (!$this->getPlatform()->supportsInsertNullPk()) {
$script .= "
// remove pkey col since this table uses auto-increment and passing a null value for it is not valid
\$criteria->remove(" . $this->getColumnConstant($col) . ");
";
}
} elseif (
$col->isPrimaryKey()
&& $col->isAutoIncrement()
&& $table->getIdMethod() !== 'none'
&& $table->isAllowPkInsert()
&& !$this->getPlatform()->supportsInsertNullPk()
) {
$script .= "
// remove pkey col if it is null since this table does not accept that
if (\$criteria->containsKey(" . $this->getColumnConstant($col) . ') && !$criteria->keyContainsValue(' . $this->getColumnConstant($col) . ") ) {
\$criteria->remove(" . $this->getColumnConstant($col) . ");
}
";
}
}
$script .= "
// Set the correct dbName
\$query = " . $this->getQueryClassName() . "::create()->mergeWith(\$criteria);
// use transaction because \$criteria could contain info
// for more than one table (I guess, conceivably)
return \$con->transaction(function () use (\$con, \$query) {
return \$query->doInsert(\$con);
});
}
";
}
}