Permalink
Fetching contributors…
Cannot retrieve contributors at this time
2009 lines (1825 sloc) 73.9 KB
<?php
/**
* 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.
*
* @license MIT License
*/
namespace Propel\Generator\Builder\Om;
use Propel\Generator\Model\Column;
use Propel\Generator\Model\CrossForeignKeys;
use Propel\Generator\Model\ForeignKey;
use Propel\Generator\Model\PropelTypes;
use Propel\Generator\Model\Table;
/**
* Generates a PHP5 base Query class for user object model (OM).
*
* This class produces the base query class (e.g. BaseBookQuery) which contains
* all the custom-built query methods.
*
* @author Francois Zaninotto
*/
class QueryBuilder extends AbstractOMBuilder
{
/**
* Returns the package for the [base] object classes.
*
* @return string
*/
public function getPackage()
{
return parent::getPackage() . '.Base';
}
/**
* Returns the namepace for the query object classes.
*
* @return string
*/
public function getNamespace()
{
if ($namespace = parent::getNamespace()) {
return $namespace . '\\Base';
}
return 'Base';
}
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassName()
{
return $this->getStubQueryBuilder()->getUnprefixedClassName();
}
/**
* Returns parent class name that extends TableQuery Object if is set this class must extends ModelCriteria for be compatible
* @return string
*/
public function getParentClass()
{
$parentClass = $this->getBehaviorContent('parentClass');
return null === $parentClass ? ($this->getTable()->getBaseQueryClass() != "" ? $this->getTable()->getBaseQueryClass() : 'ModelCriteria') : $parentClass;
}
/**
* Adds class phpdoc comment and opening of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$queryClass = $this->getQueryClassName();
$modelClass = $this->getObjectClassName();
$parentClass = $this->getParentClass();
$script .= "
/**
* Base class that represents a query for the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('generator.objectModel.addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('general.version') . " on:
*
* $now
*";
}
// magic orderBy() methods, for IDE completion
foreach ($this->getTable()->getColumns() as $column) {
$script .= "
* @method $queryClass orderBy" . $column->getPhpName() . "(\$order = Criteria::ASC) Order by the " . $column->getName() . " column";
}
$script .= "
*";
// magic groupBy() methods, for IDE completion
foreach ($this->getTable()->getColumns() as $column) {
$script .= "
* @method $queryClass groupBy" . $column->getPhpName() . "() Group by the " . $column->getName() . " column";
}
// override the signature of ModelCriteria::left-, right- and innerJoin to specify the class of the returned object, for IDE completion
$script .= "
*
* @method $queryClass leftJoin(\$relation) Adds a LEFT JOIN clause to the query
* @method $queryClass rightJoin(\$relation) Adds a RIGHT JOIN clause to the query
* @method $queryClass innerJoin(\$relation) Adds a INNER JOIN clause to the query
*";
$script .= "
* @method $queryClass leftJoinWith(\$relation) Adds a LEFT JOIN clause and with to the query
* @method $queryClass rightJoinWith(\$relation) Adds a RIGHT JOIN clause and with to the query
* @method $queryClass innerJoinWith(\$relation) Adds a INNER JOIN clause and with to the query
*";
$relationQueryClasses = [];
// magic XXXjoinYYY() methods, for IDE completion
foreach ($this->getTable()->getForeignKeys() as $fk) {
$relationName = $this->getFKPhpNameAffix($fk);
$script .= "
* @method $queryClass leftJoin" . $relationName . "(\$relationAlias = null) Adds a LEFT JOIN clause to the query using the " . $relationName . " relation
* @method $queryClass rightJoin" . $relationName . "(\$relationAlias = null) Adds a RIGHT JOIN clause to the query using the " . $relationName . " relation
* @method $queryClass innerJoin" . $relationName . "(\$relationAlias = null) Adds a INNER JOIN clause to the query using the " . $relationName . " relation
*";
$script .= "
* @method $queryClass joinWith" . $relationName . "(\$joinType = Criteria::INNER_JOIN) Adds a join clause and with to the query using the " . $relationName . " relation
*";
$script .= "
* @method $queryClass leftJoinWith" . $relationName . "() Adds a LEFT JOIN clause and with to the query using the " . $relationName . " relation
* @method $queryClass rightJoinWith" . $relationName . "() Adds a RIGHT JOIN clause and with to the query using the " . $relationName . " relation
* @method $queryClass innerJoinWith" . $relationName . "() Adds a INNER JOIN clause and with to the query using the " . $relationName . " relation
*";
$relationQueryClasses[$this->getNewStubQueryBuilder($fk->getForeignTable())->getQueryClassName(true)] = true;
}
foreach ($this->getTable()->getReferrers() as $refFK) {
$relationName = $this->getRefFKPhpNameAffix($refFK);
$script .= "
* @method $queryClass leftJoin" . $relationName . "(\$relationAlias = null) Adds a LEFT JOIN clause to the query using the " . $relationName . " relation
* @method $queryClass rightJoin" . $relationName . "(\$relationAlias = null) Adds a RIGHT JOIN clause to the query using the " . $relationName . " relation
* @method $queryClass innerJoin" . $relationName . "(\$relationAlias = null) Adds a INNER JOIN clause to the query using the " . $relationName . " relation
*";
$script .= "
* @method $queryClass joinWith" . $relationName . "(\$joinType = Criteria::INNER_JOIN) Adds a join clause and with to the query using the " . $relationName . " relation
*";
$script .= "
* @method $queryClass leftJoinWith" . $relationName . "() Adds a LEFT JOIN clause and with to the query using the " . $relationName . " relation
* @method $queryClass rightJoinWith" . $relationName . "() Adds a RIGHT JOIN clause and with to the query using the " . $relationName . " relation
* @method $queryClass innerJoinWith" . $relationName . "() Adds a INNER JOIN clause and with to the query using the " . $relationName . " relation
*";
$relationQueryClasses[$this->getNewStubQueryBuilder($refFK->getTable())->getQueryClassName(true)] = true;
}
if (!empty($relationQueryClasses)) {
$relationQueryClasses = implode('|', array_keys($relationQueryClasses));
$script .= "
* @method $relationQueryClasses endUse() Finalizes a secondary criteria and merges it with its primary Criteria
*";
}
// override the signature of ModelCriteria::findOne() to specify the class of the returned object, for IDE completion
$script .= "
* @method $modelClass findOne(ConnectionInterface \$con = null) Return the first $modelClass matching the query
* @method $modelClass findOneOrCreate(ConnectionInterface \$con = null) Return the first $modelClass matching the query, or a new $modelClass object populated from the query conditions when no match is found
*";
// magic findBy() methods, for IDE completion
foreach ($this->getTable()->getColumns() as $column) {
$script .= "
* @method $modelClass findOneBy" . $column->getPhpName() . "(" . $column->getPhpType() . " \$" . $column->getName() . ") Return the first $modelClass filtered by the " . $column->getName() . " column";
}
$script .= " * \n";
// override the signature of ModelCriteria::require*() to specify the class of the returned object, for IDE completion
$script .= "
* @method $modelClass requirePk(\$key, ConnectionInterface \$con = null) Return the $modelClass by primary key and throws {$this->getEntityNotFoundExceptionClass()} when not found
* @method $modelClass requireOne(ConnectionInterface \$con = null) Return the first $modelClass matching the query and throws {$this->getEntityNotFoundExceptionClass()} when not found
*";
// magic requireOneBy() methods, for IDE completion
foreach ($this->getTable()->getColumns() as $column) {
$script .= "
* @method $modelClass requireOneBy" . $column->getPhpName() . "(" . $column->getPhpType() . " \$" . $column->getName() . ") Return the first $modelClass filtered by the " . $column->getName() . " column and throws {$this->getEntityNotFoundExceptionClass()} when not found";
}
$script .= "
*
* @method {$modelClass}[]|ObjectCollection find(ConnectionInterface \$con = null) Return $modelClass objects based on current ModelCriteria";
foreach ($this->getTable()->getColumns() as $column) {
$script .= "
* @method {$modelClass}[]|ObjectCollection findBy" . $column->getPhpName() . "(" . $column->getPhpType() . " \$" . $column->getName() . ") Return $modelClass objects filtered by the " . $column->getName() . " column";
}
$script .= "
* @method {$modelClass}[]|\\Propel\\Runtime\\Util\\PropelModelPager paginate(\$page = 1, \$maxPerPage = 10, ConnectionInterface \$con = null) Issue a SELECT query based on the current ModelCriteria and uses a page and a maximum number of results per page to compute an offset and a limit
*
*/
abstract class ".$this->getUnqualifiedClassName()." extends " . $parentClass . "
{
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
$table = $this->getTable();
// namespaces
$this->declareClasses(
'\Propel\Runtime\Propel',
'\Propel\Runtime\ActiveQuery\ModelCriteria',
'\Propel\Runtime\ActiveQuery\Criteria',
'\Propel\Runtime\ActiveQuery\ModelJoin',
'\Exception',
'\Propel\Runtime\Exception\PropelException'
);
$this->declareClassFromBuilder($this->getStubQueryBuilder(), 'Child');
$this->declareClassFromBuilder($this->getTableMapBuilder());
// apply behaviors
$this->applyBehaviorModifier('queryAttributes', $script, " ");
$this->addEntityNotFoundExceptionClass($script);
$this->addConstructor($script);
$this->addFactory($script);
$this->addFindPk($script);
$this->addFindPkSimple($script);
$this->addFindPkComplex($script);
$this->addFindPks($script);
$this->addFilterByPrimaryKey($script);
$this->addFilterByPrimaryKeys($script);
foreach ($this->getTable()->getColumns() as $col) {
$this->addFilterByCol($script, $col);
if ($col->isNamePlural()) {
if ($col->getType() === PropelTypes::PHP_ARRAY) {
$this->addFilterByArrayCol($script, $col);
} elseif ($col->isSetType()) {
$this->addFilterBySetCol($script, $col);
}
}
}
foreach ($this->getTable()->getForeignKeys() as $fk) {
$this->addFilterByFK($script, $fk);
$this->addJoinFk($script, $fk);
$this->addUseFKQuery($script, $fk);
}
foreach ($this->getTable()->getReferrers() as $refFK) {
$this->addFilterByRefFK($script, $refFK);
$this->addJoinRefFk($script, $refFK);
$this->addUseRefFKQuery($script, $refFK);
}
foreach ($this->getTable()->getCrossFks() as $crossFKs) {
$this->addFilterByCrossFK($script, $crossFKs);
}
$this->addPrune($script);
$this->addBasePreSelect($script);
$this->addBasePreDelete($script);
$this->addBasePostDelete($script);
$this->addBasePreUpdate($script);
$this->addBasePostUpdate($script);
// add the insert, update, delete, etc. methods
if (!$table->isAlias() && !$table->isReadOnly()) {
$this->addDeleteMethods($script);
}
// apply behaviors
$this->applyBehaviorModifier('staticConstants', $script, " ");
$this->applyBehaviorModifier('staticAttributes', $script, " ");
$this->applyBehaviorModifier('staticMethods', $script, " ");
$this->applyBehaviorModifier('queryMethods', $script, " ");
}
/**
* Adds the entityNotFoundExceptionClass property which is necessary for the `requireOne` method
* of the `ModelCriteria`
*/
protected function addEntityNotFoundExceptionClass(&$script)
{
$script .= "protected \$entityNotFoundExceptionClass = '" . addslashes($this->getEntityNotFoundExceptionClass()) . "';\n";
}
private function getEntityNotFoundExceptionClass()
{
return $this->getBuildProperty('generator.objectModel.entityNotFoundExceptionClass');
}
/**
* Adds the doDeleteAll(), etc. methods.
* @param string &$script The script will be modified in this method.
*/
protected function addDeleteMethods(&$script)
{
$this->addDoDeleteAll($script);
$this->addDelete($script);
if ($this->isDeleteCascadeEmulationNeeded()) {
$this->addDoOnDeleteCascade($script);
}
if ($this->isDeleteSetNullEmulationNeeded()) {
$this->addDoOnDeleteSetNull($script);
}
}
/**
* Whether the platform in use requires ON DELETE CASCADE emulation and whether there are references to this table.
* @return boolean
*/
protected function isDeleteCascadeEmulationNeeded()
{
$table = $this->getTable();
if ((!$this->getPlatform()->supportsNativeDeleteTrigger() || $this->getBuildProperty('generator.objectModel.emulateForeignKeyConstraints')) && count($table->getReferrers()) > 0) {
foreach ($table->getReferrers() as $fk) {
if ( ForeignKey::CASCADE === $fk->getOnDelete()) {
return true;
}
}
}
return false;
}
/**
* Whether the platform in use requires ON DELETE SETNULL emulation and whether there are references to this table.
* @return boolean
*/
protected function isDeleteSetNullEmulationNeeded()
{
$table = $this->getTable();
if ((!$this->getPlatform()->supportsNativeDeleteTrigger() || $this->getBuildProperty('generator.objectModel.emulateForeignKeyConstraints')) && count($table->getReferrers()) > 0) {
foreach ($table->getReferrers() as $fk) {
if (ForeignKey::SETNULL === $fk->getOnDelete()) {
return true;
}
}
}
return false;
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getUnqualifiedClassName() . "
";
$this->applyBehaviorModifier('queryFilter', $script, "");
}
/**
* Adds the constructor for this object.
* @param string &$script The script will be modified in this method.
* @see addConstructor()
*/
protected function addConstructor(&$script)
{
$this->addConstructorComment($script);
$this->addConstructorOpen($script);
$this->addConstructorBody($script);
$this->addConstructorClose($script);
}
/**
* Adds the comment for the constructor
* @param string &$script The script will be modified in this method.
**/
protected function addConstructorComment(&$script)
{
$script .= "
/**
* Initializes internal state of ".$this->getClassName()." object.
*
* @param string \$dbName The database name
* @param string \$modelName The phpName of a model, e.g. 'Book'
* @param string \$modelAlias The alias for the model in this query, e.g. 'b'
*/";
}
/**
* Adds the function declaration for the constructor
* @param string &$script The script will be modified in this method.
**/
protected function addConstructorOpen(&$script)
{
$table = $this->getTable();
$script .= "
public function __construct(\$dbName = '" . $table->getDatabase()->getName() . "', \$modelName = '" . addslashes($this->getNewStubObjectBuilder($table)->getFullyQualifiedClassName()) . "', \$modelAlias = null)
{";
}
/**
* Adds the function body for the constructor
* @param string &$script The script will be modified in this method.
**/
protected function addConstructorBody(&$script)
{
$script .= "
parent::__construct(\$dbName, \$modelName, \$modelAlias);";
}
/**
* Adds the function close for the constructor
* @param string &$script The script will be modified in this method.
**/
protected function addConstructorClose(&$script)
{
$script .= "
}
";
}
/**
* Adds the factory for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFactory(&$script)
{
$this->addFactoryComment($script);
$this->addFactoryOpen($script);
$this->addFactoryBody($script);
$this->addFactoryClose($script);
}
/**
* Adds the comment for the factory
* @param string &$script The script will be modified in this method.
**/
protected function addFactoryComment(&$script)
{
$classname = $this->getClassNameFromBuilder($this->getNewStubQueryBuilder($this->getTable()));
$script .= "
/**
* Returns a new " . $classname . " object.
*
* @param string \$modelAlias The alias of a model in the query
* @param Criteria \$criteria Optional Criteria to build the query from
*
* @return " . $classname . "
*/";
}
/**
* Adds the function declaration for the factory
* @param string &$script The script will be modified in this method.
**/
protected function addFactoryOpen(&$script)
{
$script .= "
public static function create(\$modelAlias = null, Criteria \$criteria = null)
{";
}
/**
* Adds the function body for the factory
* @param string &$script The script will be modified in this method.
*/
protected function addFactoryBody(&$script)
{
$classname = $this->getClassNameFromBuilder($this->getNewStubQueryBuilder($this->getTable()));
$script .= "
if (\$criteria instanceof " . $classname . ") {
return \$criteria;
}
\$query = new " . $classname . "();
if (null !== \$modelAlias) {
\$query->setModelAlias(\$modelAlias);
}
if (\$criteria instanceof Criteria) {
\$query->mergeWith(\$criteria);
}
return \$query;";
}
/**
* Adds the function close for the factory
* @param string &$script The script will be modified in this method.
*/
protected function addFactoryClose(&$script)
{
$script .= "
}
";
}
protected function addFindPk(&$script)
{
$class = $this->getObjectClassName();
$tableMapClassName = $this->getTableMapClassName();
$table = $this->getTable();
$script .= "
/**
* Find object by primary key.
* Propel uses the instance pool to skip the database if the object exists.
* Go fast if the query is untouched.
*";
if ($table->hasCompositePrimaryKey()) {
$pks = $table->getPrimaryKey();
$examplePk = array_slice([12, 34, 56, 78, 91], 0, count($pks));
$colNames = [];
foreach ($pks as $col) {
$colNames[]= '$' . $col->getName();
}
$pkType = 'array['. join($colNames, ', ') . ']';
$script .= "
* <code>
* \$obj = \$c->findPk(array(" . join($examplePk, ', ') . "), \$con);";
} else {
$pkType = 'mixed';
$script .= "
* <code>
* \$obj = \$c->findPk(12, \$con);";
}
$script .= "
* </code>
*
* @param " . $pkType . " \$key Primary key to use for the query
* @param ConnectionInterface \$con an optional connection object
*
* @return $class|array|mixed the result, formatted by the current formatter
*/
public function findPk(\$key, ConnectionInterface \$con = null)
{";
if (!$table->hasPrimaryKey()) {
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('The {$this->getObjectName()} object has no primary key');
}
";
return $script;
}
$script .= "
if (\$key === null) {
return null;
}";
if ($table->hasCompositePrimaryKey()) {
$pks = [];
foreach ($table->getPrimaryKey() as $index => $column) {
$pks[] = "\$key[$index]";
}
} else {
$pks = '$key';
}
$pkHash = $this->getTableMapBuilder()->getInstancePoolKeySnippet($pks);
$script .= "
if (\$con === null) {
\$con = Propel::getServiceContainer()->getReadConnection({$this->getTableMapClass()}::DATABASE_NAME);
}
\$this->basePreSelect(\$con);
if (
\$this->formatter || \$this->modelAlias || \$this->with || \$this->select
|| \$this->selectColumns || \$this->asColumns || \$this->selectModifiers
|| \$this->map || \$this->having || \$this->joins
) {
return \$this->findPkComplex(\$key, \$con);
}
if ((null !== (\$obj = {$tableMapClassName}::getInstanceFromPool({$pkHash})))) {
// the object is already in the instance pool
return \$obj;
}
return \$this->findPkSimple(\$key, \$con);
}
";
}
protected function addFindPkSimple(&$script)
{
$table = $this->getTable();
// this method is not needed if the table has no primary key
if (!$table->hasPrimaryKey()) {
return '';
}
$platform = $this->getPlatform();
$tableMapClassName = $this->getTableMapClassName();
$ARClassName = $this->getObjectClassName();
$this->declareClassFromBuilder($this->getStubObjectBuilder());
$this->declareClasses('\PDO');
$selectColumns = [];
foreach ($table->getColumns() as $column) {
if (!$column->isLazyLoad()) {
$selectColumns []= $this->quoteIdentifier($column->getName());
}
}
$conditions = [];
foreach ($table->getPrimaryKey() as $index => $column) {
$conditions []= sprintf('%s = :p%d', $this->quoteIdentifier($column->getName()), $index);
}
$query = sprintf(
'SELECT %s FROM %s WHERE %s',
implode(', ', $selectColumns),
$this->quoteIdentifier($table->getName()),
implode(' AND ', $conditions)
);
$pks = [];
if ($table->hasCompositePrimaryKey()) {
foreach ($table->getPrimaryKey() as $index => $column) {
$pks []= "\$key[$index]";
}
} else {
$pks []= "\$key";
}
$pkHashFromRow = $this->getTableMapBuilder()->getInstancePoolKeySnippet($pks);
$script .= "
/**
* Find object by primary key using raw SQL to go fast.
* Bypass doSelect() and the object formatter by using generated code.
*
* @param mixed \$key Primary key to use for the query
* @param ConnectionInterface \$con A connection object
*
* @throws \\Propel\\Runtime\\Exception\\PropelException
*
* @return $ARClassName A model object, or null if the key is not found
*/
protected function findPkSimple(\$key, ConnectionInterface \$con)
{
\$sql = '$query';
try {
\$stmt = \$con->prepare(\$sql);";
if ($table->hasCompositePrimaryKey()) {
foreach ($table->getPrimaryKey() as $index => $column) {
$script .= $platform->getColumnBindingPHP($column, "':p$index'", "\$key[$index]", ' ');
}
} else {
$pk = $table->getPrimaryKey();
$column = $pk[0];
$script .= $platform->getColumnBindingPHP($column, "':p0'", "\$key", ' ');
}
$script .= "
\$stmt->execute();
} catch (Exception \$e) {
Propel::log(\$e->getMessage(), Propel::LOG_ERR);
throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', \$sql), 0, \$e);
}
\$obj = null;
if (\$row = \$stmt->fetch(\PDO::FETCH_NUM)) {";
if ($table->getChildrenColumn()) {
$script .="
\$cls = {$tableMapClassName}::getOMClass(\$row, 0, false);
/** @var $ARClassName \$obj */
\$obj = new \$cls();";
} else {
$script .="
/** @var $ARClassName \$obj */
\$obj = new $ARClassName();";
}
$script .= "
\$obj->hydrate(\$row);
{$tableMapClassName}::addInstanceToPool(\$obj, $pkHashFromRow);
}
\$stmt->closeCursor();
return \$obj;
}
";
}
/**
* Adds the findPk method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFindPkComplex(&$script)
{
$class = $this->getObjectClassName();
$table = $this->getTable();
// this method is not needed if the table has no primary key
if (!$table->hasPrimaryKey()) {
return '';
}
$this->declareClasses('\Propel\Runtime\Connection\ConnectionInterface');
$script .= "
/**
* Find object by primary key.
*
* @param mixed \$key Primary key to use for the query
* @param ConnectionInterface \$con A connection object
*
* @return " . $class . "|array|mixed the result, formatted by the current formatter
*/
protected function findPkComplex(\$key, ConnectionInterface \$con)
{
// As the query uses a PK condition, no limit(1) is necessary.
\$criteria = \$this->isKeepQuery() ? clone \$this : \$this;
\$dataFetcher = \$criteria
->filterByPrimaryKey(\$key)
->doSelect(\$con);
return \$criteria->getFormatter()->init(\$criteria)->formatOne(\$dataFetcher);
}
";
}
/**
* Adds the findPks method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFindPks(&$script)
{
$this->declareClasses(
'\Propel\Runtime\Collection\ObjectCollection',
'\Propel\Runtime\Connection\ConnectionInterface',
'\Propel\Runtime\Propel'
);
$table = $this->getTable();
$pks = $table->getPrimaryKey();
$count = count($pks);
$script .= "
/**
* Find objects by primary key
* <code>";
if (1 === $count) {
$script .= "
* \$objs = \$c->findPks(array(12, 56, 832), \$con);";
} else {
$script .= "
* \$objs = \$c->findPks(array(array(12, 56), array(832, 123), array(123, 456)), \$con);";
}
$script .= "
* </code>
* @param array \$keys Primary keys to use for the query
* @param ConnectionInterface \$con an optional connection object
*
* @return ObjectCollection|array|mixed the list of results, formatted by the current formatter
*/
public function findPks(\$keys, ConnectionInterface \$con = null)
{";
if (!$table->hasPrimaryKey()) {
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('The {$this->getObjectName()} object has no primary key');
}
";
return $script;
}
$script .= "
if (null === \$con) {
\$con = Propel::getServiceContainer()->getReadConnection(\$this->getDbName());
}
\$this->basePreSelect(\$con);
\$criteria = \$this->isKeepQuery() ? clone \$this : \$this;
\$dataFetcher = \$criteria
->filterByPrimaryKeys(\$keys)
->doSelect(\$con);
return \$criteria->getFormatter()->init(\$criteria)->format(\$dataFetcher);
}
";
}
/**
* Adds the filterByPrimaryKey method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFilterByPrimaryKey(&$script)
{
$script .= "
/**
* Filter the query by primary key
*
* @param mixed \$key Primary key to use for the query
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function filterByPrimaryKey(\$key)
{";
$table = $this->getTable();
if (!$table->hasPrimaryKey()) {
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('The {$this->getObjectName()} object has no primary key');
}
";
return $script;
}
$pks = $table->getPrimaryKey();
if (1 === count($pks)) {
// simple primary key
$col = $pks[0];
$const = $this->getColumnConstant($col);
$script .= "
return \$this->addUsingAlias($const, \$key, Criteria::EQUAL);";
} else {
// composite primary key
$i = 0;
foreach ($pks as $col) {
$const = $this->getColumnConstant($col);
$script .= "
\$this->addUsingAlias($const, \$key[$i], Criteria::EQUAL);";
$i++;
}
$script .= "
return \$this;";
}
$script .= "
}
";
}
/**
* Adds the filterByPrimaryKey method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFilterByPrimaryKeys(&$script)
{
$script .= "
/**
* Filter the query by a list of primary keys
*
* @param array \$keys The list of primary key to use for the query
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function filterByPrimaryKeys(\$keys)
{";
$table = $this->getTable();
if (!$table->hasPrimaryKey()) {
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('The {$this->getObjectName()} object has no primary key');
}
";
return $script;
}
$pks = $table->getPrimaryKey();
if (1 === count($pks)) {
// simple primary key
$col = $pks[0];
$const = $this->getColumnConstant($col);
$script .= "
return \$this->addUsingAlias($const, \$keys, Criteria::IN);";
} else {
// composite primary key
$script .= "
if (empty(\$keys)) {
return \$this->add(null, '1<>1', Criteria::CUSTOM);
}
foreach (\$keys as \$key) {";
$i = 0;
foreach ($pks as $col) {
$const = $this->getColumnConstant($col);
$script .= "
\$cton$i = \$this->getNewCriterion($const, \$key[$i], Criteria::EQUAL);";
if ($i > 0) {
$script .= "
\$cton0->addAnd(\$cton$i);";
}
$i++;
}
$script .= "
\$this->addOr(\$cton0);
}";
$script .= "
return \$this;";
}
$script .= "
}
";
}
/**
* Adds the filterByCol method for this object.
* @param string &$script The script will be modified in this method.
* @param Column $col
*/
protected function addFilterByCol(&$script, Column $col)
{
$colPhpName = $col->getPhpName();
$colName = $col->getName();
$variableName = $col->getCamelCaseName();
$qualifiedName = $this->getColumnConstant($col);
$script .= "
/**
* Filter the query on the $colName column
*";
if ($col->isNumericType()) {
$script .= "
* Example usage:
* <code>
* \$query->filterBy$colPhpName(1234); // WHERE $colName = 1234
* \$query->filterBy$colPhpName(array(12, 34)); // WHERE $colName IN (12, 34)
* \$query->filterBy$colPhpName(array('min' => 12)); // WHERE $colName > 12
* </code>";
if ($col->isForeignKey()) {
foreach ($col->getForeignKeys() as $fk) {
$script .= "
*
* @see filterBy" . $this->getFKPhpNameAffix($fk) . "()";
}
}
$script .= "
*
* @param mixed \$$variableName The value to use as filter.
* Use scalar values for equality.
* Use array values for in_array() equivalent.
* Use associative array('min' => \$minValue, 'max' => \$maxValue) for intervals.";
} elseif ($col->isTemporalType()) {
$script .= "
* Example usage:
* <code>
* \$query->filterBy$colPhpName('2011-03-14'); // WHERE $colName = '2011-03-14'
* \$query->filterBy$colPhpName('now'); // WHERE $colName = '2011-03-14'
* \$query->filterBy$colPhpName(array('max' => 'yesterday')); // WHERE $colName > '2011-03-13'
* </code>
*
* @param mixed \$$variableName The value to use as filter.
* Values can be integers (unix timestamps), DateTime objects, or strings.
* Empty strings are treated as NULL.
* Use scalar values for equality.
* Use array values for in_array() equivalent.
* Use associative array('min' => \$minValue, 'max' => \$maxValue) for intervals.";
} elseif ($col->getType() == PropelTypes::PHP_ARRAY) {
$script .= "
* @param array \$$variableName The values to use as filter.";
} elseif ($col->isTextType()) {
$script .= "
* Example usage:
* <code>
* \$query->filterBy$colPhpName('fooValue'); // WHERE $colName = 'fooValue'
* \$query->filterBy$colPhpName('%fooValue%', Criteria::LIKE); // WHERE $colName LIKE '%fooValue%'
* </code>
*
* @param string \$$variableName The value to use as filter.";
} elseif ($col->isBooleanType()) {
$script .= "
* Example usage:
* <code>
* \$query->filterBy$colPhpName(true); // WHERE $colName = true
* \$query->filterBy$colPhpName('yes'); // WHERE $colName = true
* </code>
*
* @param boolean|string \$$variableName The value to use as filter.
* Non-boolean arguments are converted using the following rules:
* * 1, '1', 'true', 'on', and 'yes' are converted to boolean true
* * 0, '0', 'false', 'off', and 'no' are converted to boolean false
* Check on string values is case insensitive (so 'FaLsE' is seen as 'false').";
} else {
$script .= "
* @param mixed \$$variableName The value to use as filter";
}
$script .= "
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function filterBy$colPhpName(\$$variableName = null, \$comparison = null)
{";
if ($col->isNumericType() || $col->isTemporalType()) {
$script .= "
if (is_array(\$$variableName)) {
\$useMinMax = false;
if (isset(\${$variableName}['min'])) {
\$this->addUsingAlias($qualifiedName, \${$variableName}['min'], Criteria::GREATER_EQUAL);
\$useMinMax = true;
}
if (isset(\${$variableName}['max'])) {
\$this->addUsingAlias($qualifiedName, \${$variableName}['max'], Criteria::LESS_EQUAL);
\$useMinMax = true;
}
if (\$useMinMax) {
return \$this;
}
if (null === \$comparison) {
\$comparison = Criteria::IN;
}
}";
} elseif ($col->getType() == PropelTypes::OBJECT) {
$script .= "
if (is_object(\$$variableName)) {
\$$variableName = serialize(\$$variableName);
}";
} elseif ($col->getType() == PropelTypes::PHP_ARRAY) {
$script .= "
\$key = \$this->getAliasedColName($qualifiedName);
if (null === \$comparison || \$comparison == Criteria::CONTAINS_ALL) {
foreach (\$$variableName as \$value) {
\$value = '%| ' . \$value . ' |%';
if (\$this->containsKey(\$key)) {
\$this->addAnd(\$key, \$value, Criteria::LIKE);
} else {
\$this->add(\$key, \$value, Criteria::LIKE);
}
}
return \$this;
} elseif (\$comparison == Criteria::CONTAINS_SOME) {
foreach (\$$variableName as \$value) {
\$value = '%| ' . \$value . ' |%';
if (\$this->containsKey(\$key)) {
\$this->addOr(\$key, \$value, Criteria::LIKE);
} else {
\$this->add(\$key, \$value, Criteria::LIKE);
}
}
return \$this;
} elseif (\$comparison == Criteria::CONTAINS_NONE) {
foreach (\$$variableName as \$value) {
\$value = '%| ' . \$value . ' |%';
if (\$this->containsKey(\$key)) {
\$this->addAnd(\$key, \$value, Criteria::NOT_LIKE);
} else {
\$this->add(\$key, \$value, Criteria::NOT_LIKE);
}
}
\$this->addOr(\$key, null, Criteria::ISNULL);
return \$this;
}";
} elseif ($col->isSetType()) {
$this->declareClasses(
'Propel\Common\Util\SetColumnConverter',
'Propel\Common\Exception\SetColumnConverterException'
);
$script .= "
\$valueSet = " . $this->getTableMapClassName() . "::getValueSet(" . $this->getColumnConstant($col) . ");
try {
\${$variableName} = SetColumnConverter::convertToInt(\${$variableName}, \$valueSet);
} catch (SetColumnConverterException \$e) {
throw new PropelException(sprintf('Value \"%s\" is not accepted in this set column', \$e->getValue()), \$e->getCode(), \$e);
}
if (null === \$comparison || \$comparison == Criteria::CONTAINS_ALL) {
if (\${$variableName} === '0') {
return \$this;
}
\$comparison = Criteria::BINARY_ALL;
} elseif (\$comparison == Criteria::CONTAINS_SOME || \$comparison == Criteria::IN) {
if (\${$variableName} === '0') {
return \$this;
}
\$comparison = Criteria::BINARY_AND;
} elseif (\$comparison == Criteria::CONTAINS_NONE) {
\$key = \$this->getAliasedColName($qualifiedName);
if (\${$variableName} !== '0') {
\$this->add(\$key, \${$variableName}, Criteria::BINARY_NONE);
}
\$this->addOr(\$key, null, Criteria::ISNULL);
return \$this;
}";
} elseif ($col->getType() == PropelTypes::ENUM) {
$script .= "
\$valueSet = " . $this->getTableMapClassName() . "::getValueSet(" . $this->getColumnConstant($col) . ");
if (is_scalar(\$$variableName)) {
if (!in_array(\$$variableName, \$valueSet)) {
throw new PropelException(sprintf('Value \"%s\" is not accepted in this enumerated column', \$$variableName));
}
\$$variableName = array_search(\$$variableName, \$valueSet);
} elseif (is_array(\$$variableName)) {
\$convertedValues = array();
foreach (\$$variableName as \$value) {
if (!in_array(\$value, \$valueSet)) {
throw new PropelException(sprintf('Value \"%s\" is not accepted in this enumerated column', \$value));
}
\$convertedValues []= array_search(\$value, \$valueSet);
}
\$$variableName = \$convertedValues;
if (null === \$comparison) {
\$comparison = Criteria::IN;
}
}";
} elseif ($col->isTextType()) {
$script .= "
if (null === \$comparison) {
if (is_array(\$$variableName)) {
\$comparison = Criteria::IN;
}
}";
} elseif ($col->isBooleanType()) {
$script .= "
if (is_string(\$$variableName)) {
\$$variableName = in_array(strtolower(\$$variableName), array('false', 'off', '-', 'no', 'n', '0', '')) ? false : true;
}";
}
$script .= "
return \$this->addUsingAlias($qualifiedName, \$$variableName, \$comparison);
}
";
}
/**
* Adds the singular filterByCol method for an Array column.
* @param string &$script The script will be modified in this method.
* @param Column $col
*/
protected function addFilterByArrayCol(&$script, Column $col)
{
$colPhpName = $col->getPhpName();
$singularPhpName = $col->getPhpSingularName();
$colName = $col->getName();
$variableName = $col->getCamelCaseName();
$qualifiedName = $this->getColumnConstant($col);
$script .= "
/**
* Filter the query on the $colName column
* @param mixed \$$variableName The value to use as filter
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::CONTAINS_ALL
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function filterBy$singularPhpName(\$$variableName = null, \$comparison = null)
{
if (null === \$comparison || \$comparison == Criteria::CONTAINS_ALL) {
if (is_scalar(\$$variableName)) {
\$$variableName = '%| ' . \$$variableName . ' |%';
\$comparison = Criteria::LIKE;
}
} elseif (\$comparison == Criteria::CONTAINS_NONE) {
\$$variableName = '%| ' . \$$variableName . ' |%';
\$comparison = Criteria::NOT_LIKE;
\$key = \$this->getAliasedColName($qualifiedName);
if (\$this->containsKey(\$key)) {
\$this->addAnd(\$key, \$$variableName, \$comparison);
} else {
\$this->addAnd(\$key, \$$variableName, \$comparison);
}
\$this->addOr(\$key, null, Criteria::ISNULL);
return \$this;
}
return \$this->addUsingAlias($qualifiedName, \$$variableName, \$comparison);
}
";
}
/**
* Adds the singular filterByCol method for an Array column.
*
* @param string &$script The script will be modified in this method.
* @param Column $col
*/
protected function addFilterBySetCol(&$script, Column $col)
{
$colPhpName = $col->getPhpName();
$singularPhpName = $col->getPhpSingularName();
$colName = $col->getName();
$variableName = $col->getCamelCaseName();
$script .= "
/**
* Filter the query on the $colName column
* @param mixed \$$variableName The value to use as filter
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::CONTAINS_ALL
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function filterBy$singularPhpName(\$$variableName = null, \$comparison = null)
{
return \$this->filterBy$colPhpName(\$$variableName, \$comparison);
}
";
}
/**
* Adds the filterByFk method for this object.
* @param string &$script The script will be modified in this method.
* @param $fk ForeignKey
*/
protected function addFilterByFk(&$script, $fk)
{
$this->declareClasses(
'\Propel\Runtime\Collection\ObjectCollection',
'\Propel\Runtime\Exception\PropelException'
);
$table = $this->getTable();
$queryClass = $this->getQueryClassName();
$fkTable = $fk->getForeignTable();
$fkStubObjectBuilder = $this->getNewStubObjectBuilder($fkTable);
$this->declareClassFromBuilder($fkStubObjectBuilder);
$fkPhpName = $this->getClassNameFromBuilder($fkStubObjectBuilder, true);
$relationName = $this->getFKPhpNameAffix($fk);
$objectName = '$' . $fkTable->getCamelCaseName();
$script .= "
/**
* Filter the query by a related $fkPhpName object
*";
if ($fk->isComposite()) {
$script .= "
* @param $fkPhpName $objectName The related object to use as filter";
} else {
$script .= "
* @param $fkPhpName|ObjectCollection $objectName The related object(s) to use as filter";
}
$script .= "
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @throws \\Propel\\Runtime\\Exception\\PropelException
*
* @return $queryClass The current query, for fluid interface
*/
public function filterBy$relationName($objectName, \$comparison = null)
{
if ($objectName instanceof $fkPhpName) {
return \$this";
foreach ($fk->getMapping() as $mapping) {
list($localColumn, $rightValueOrColumn) = $mapping;
if ($rightValueOrColumn instanceof Column) {
$script .= "
->addUsingAlias(" . $this->getColumnConstant($localColumn) . ", " . $objectName . "->get" . $rightValueOrColumn->getPhpName() . "(), \$comparison)";
} else {
$value = var_export($rightValueOrColumn, true);
$script .= "
->addUsingAlias(" . $this->getColumnConstant($localColumn) . ", $value, \$comparison)";
}
}
$script .= ";";
if (!$fk->isComposite()) {
$localColumnConstant = $this->getColumnConstant($fk->getLocalColumn());
$foreignColumnName = $fk->getForeignColumn()->getPhpName();
$keyColumn = $fk->getForeignTable()->hasCompositePrimaryKey() ? $foreignColumnName : 'PrimaryKey';
$script .= "
} elseif ($objectName instanceof ObjectCollection) {
if (null === \$comparison) {
\$comparison = Criteria::IN;
}
return \$this
->addUsingAlias($localColumnConstant, {$objectName}->toKeyValue('$keyColumn', '$foreignColumnName'), \$comparison);";
}
$script .= "
} else {";
if ($fk->isComposite()) {
$script .= "
throw new PropelException('filterBy$relationName() only accepts arguments of type $fkPhpName');";
} else {
$script .= "
throw new PropelException('filterBy$relationName() only accepts arguments of type $fkPhpName or Collection');";
}
$script .= "
}
}
";
}
/**
* Adds the filterByRefFk method for this object.
*
* @param string &$script The script will be modified in this method.
* @param ForeignKey $fk
*/
protected function addFilterByRefFk(&$script, ForeignKey $fk)
{
$this->declareClasses(
'\Propel\Runtime\Collection\ObjectCollection',
'\Propel\Runtime\Exception\PropelException'
);
$queryClass = $this->getQueryClassName();
$fkTable = $this->getTable()->getDatabase()->getTable($fk->getTableName());
$fkStubObjectBuilder = $this->getNewStubObjectBuilder($fkTable);
$this->declareClassFromBuilder($fkStubObjectBuilder);
$fkPhpName = $this->getClassNameFromBuilder($fkStubObjectBuilder, true);
$relationName = $this->getRefFKPhpNameAffix($fk);
$objectName = '$' . $fkTable->getCamelCaseName();
$script .= "
/**
* Filter the query by a related $fkPhpName object
*
* @param $fkPhpName|ObjectCollection $objectName the related object to use as filter
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return $queryClass The current query, for fluid interface
*/
public function filterBy$relationName($objectName, \$comparison = null)
{
if ($objectName instanceof $fkPhpName) {
return \$this";
foreach ($fk->getInverseMapping() as $mapping) {
/** @var Column $foreignColumn */
list($localValueOrColumn, $foreignColumn) = $mapping;
$rightValue = "{$objectName}->get" . $foreignColumn->getPhpName() . "()";
if ($localValueOrColumn instanceof Column) {
$script .= "
->addUsingAlias(" . $this->getColumnConstant($localValueOrColumn) . ", $rightValue, \$comparison)";
} else {
$leftValue = var_export($localValueOrColumn, true);
$bindingType = $foreignColumn->getPDOType();
$script .= "
->where(\"$leftValue = ?\", $rightValue, $bindingType)";
}
}
$script .= ";";
if (!$fk->isComposite()) {
$script .= "
} elseif ($objectName instanceof ObjectCollection) {
return \$this
->use{$relationName}Query()
->filterByPrimaryKeys({$objectName}->getPrimaryKeys())
->endUse();";
}
$script .= "
} else {";
if ($fk->isComposite()) {
$script .= "
throw new PropelException('filterBy$relationName() only accepts arguments of type $fkPhpName');";
} else {
$script .= "
throw new PropelException('filterBy$relationName() only accepts arguments of type $fkPhpName or Collection');";
}
$script .= "
}
}
";
}
/**
* Adds the joinFk method for this object.
* @param string &$script The script will be modified in this method.
* @param $fk ForeignKey
*/
protected function addJoinFk(&$script, $fk)
{
$queryClass = $this->getQueryClassName();
$fkTable = $fk->getForeignTable();
$relationName = $this->getFKPhpNameAffix($fk);
$joinType = $this->getJoinType($fk);
$this->addJoinRelated($script, $fkTable, $queryClass, $relationName, $joinType);
}
/**
* Adds the joinRefFk method for this object.
* @param string &$script The script will be modified in this method.
* @param ForeignKey $fk
*/
protected function addJoinRefFk(&$script, ForeignKey $fk)
{
$queryClass = $this->getQueryClassName();
$fkTable = $this->getTable()->getDatabase()->getTable($fk->getTableName());
$relationName = $this->getRefFKPhpNameAffix($fk);
$joinType = $this->getJoinType($fk);
$this->addJoinRelated($script, $fkTable, $queryClass, $relationName, $joinType);
}
/**
* Adds a joinRelated method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addJoinRelated(&$script, $fkTable, $queryClass, $relationName, $joinType)
{
$script .= "
/**
* Adds a JOIN clause to the query using the " . $relationName . " relation
*
* @param string \$relationAlias optional alias for the relation
* @param string \$joinType Accepted values are null, 'left join', 'right join', 'inner join'
*
* @return \$this|". $queryClass . " The current query, for fluid interface
*/
public function join" . $relationName . "(\$relationAlias = null, \$joinType = " . $joinType . ")
{
\$tableMap = \$this->getTableMap();
\$relationMap = \$tableMap->getRelation('" . $relationName . "');
// create a ModelJoin object for this join
\$join = new ModelJoin();
\$join->setJoinType(\$joinType);
\$join->setRelationMap(\$relationMap, \$this->useAliasInSQL ? \$this->getModelAlias() : null, \$relationAlias);
if (\$previousJoin = \$this->getPreviousJoin()) {
\$join->setPreviousJoin(\$previousJoin);
}
// add the ModelJoin to the current object
if (\$relationAlias) {
\$this->addAlias(\$relationAlias, \$relationMap->getRightTable()->getName());
\$this->addJoinObject(\$join, \$relationAlias);
} else {
\$this->addJoinObject(\$join, '" . $relationName . "');
}
return \$this;
}
";
}
/**
* Adds the useFkQuery method for this object.
* @param string &$script The script will be modified in this method.
* @param $fk ForeignKey
*/
protected function addUseFkQuery(&$script, $fk)
{
$fkTable = $fk->getForeignTable();
$fkQueryBuilder = $this->getNewStubQueryBuilder($fkTable);
$queryClass = $this->getClassNameFromBuilder($fkQueryBuilder, true);
$relationName = $this->getFKPhpNameAffix($fk);
$joinType = $this->getJoinType($fk);
$this->addUseRelatedQuery($script, $fkTable, $queryClass, $relationName, $joinType);
}
/**
* Adds the useFkQuery method for this object.
* @param string &$script The script will be modified in this method.
* @param ForeignKey $fk
*/
protected function addUseRefFkQuery(&$script, ForeignKey $fk)
{
$fkTable = $this->getTable()->getDatabase()->getTable($fk->getTableName());
$fkQueryBuilder = $this->getNewStubQueryBuilder($fkTable);
$queryClass = $this->getClassNameFromBuilder($fkQueryBuilder, true);
$relationName = $this->getRefFKPhpNameAffix($fk);
$joinType = $this->getJoinType($fk);
$this->addUseRelatedQuery($script, $fkTable, $queryClass, $relationName, $joinType);
}
/**
* Adds a useRelatedQuery method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addUseRelatedQuery(&$script, Table $fkTable, $queryClass, $relationName, $joinType)
{
$script .= "
/**
* Use the $relationName relation " . $fkTable->getPhpName() . " object
*
* @see useQuery()
*
* @param string \$relationAlias optional alias for the relation,
* to be used as main alias in the secondary query
* @param string \$joinType Accepted values are null, 'left join', 'right join', 'inner join'
*
* @return $queryClass A secondary query class using the current class as primary query
*/
public function use" . $relationName . "Query(\$relationAlias = null, \$joinType = " . $joinType . ")
{
return \$this
->join" . $relationName . "(\$relationAlias, \$joinType)
->useQuery(\$relationAlias ? \$relationAlias : '$relationName', '$queryClass');
}
";
}
protected function addFilterByCrossFK(&$script, CrossForeignKeys $crossFKs)
{
$relationName = $this->getRefFKPhpNameAffix($crossFKs->getIncomingForeignKey(), $plural = false);
foreach ($crossFKs->getCrossForeignKeys() as $crossFK) {
$queryClass = $this->getQueryClassName();
$crossRefTable = $crossFK->getTable();
$foreignTable = $crossFK->getForeignTable();
$fkPhpName = $foreignTable->getPhpName();
$crossTableName = $crossRefTable->getName();
$relName = $this->getFKPhpNameAffix($crossFK, $plural = false);
$objectName = '$' . $foreignTable->getCamelCaseName();
$script .= "
/**
* Filter the query by a related $fkPhpName object
* using the $crossTableName table as cross reference
*
* @param $fkPhpName $objectName the related object to use as filter
* @param string \$comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return $queryClass The current query, for fluid interface
*/
public function filterBy{$relName}($objectName, \$comparison = Criteria::EQUAL)
{
return \$this
->use{$relationName}Query()
->filterBy{$relName}($objectName, \$comparison)
->endUse();
}
";
}
}
/**
* Adds the prune method for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addPrune(&$script)
{
$table = $this->getTable();
$class = $this->getObjectClassName();
$objectName = '$' . $table->getCamelCaseName();
$script .= "
/**
* Exclude object from result
*
* @param $class $objectName Object to remove from the list of results
*
* @return \$this|" . $this->getQueryClassName() . " The current query, for fluid interface
*/
public function prune($objectName = null)
{
if ($objectName) {";
$pks = $table->getPrimaryKey();
if (count($pks) > 1) {
$i = 0;
$conditions = [];
foreach ($pks as $col) {
$const = $this->getColumnConstant($col);
$condName = "'pruneCond" . $i . "'";
$conditions[]= $condName;
$script .= "
\$this->addCond(". $condName . ", \$this->getAliasedColName($const), " . $objectName . "->get" . $col->getPhpName() . "(), Criteria::NOT_EQUAL);";
$i++;
}
$conditionsString = implode(', ', $conditions);
$script .= "
\$this->combine(array(" . $conditionsString . "), Criteria::LOGICAL_OR);";
} elseif ($table->hasPrimaryKey()) {
$col = $pks[0];
$const = $this->getColumnConstant($col);
$script .= "
\$this->addUsingAlias($const, " . $objectName . "->get" . $col->getPhpName() . "(), Criteria::NOT_EQUAL);";
} else {
$this->declareClass('Propel\\Runtime\\Exception\\LogicException');
$script .= "
throw new LogicException('{$this->getObjectName()} object has no primary key');
";
}
$script .= "
}
return \$this;
}
";
}
/**
* Adds the basePreSelect hook for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addBasePreSelect(&$script)
{
$behaviorCode = '';
$this->applyBehaviorModifier('preSelectQuery', $behaviorCode, " ");
if (!$behaviorCode) {
return;
}
$script .= "
/**
* Code to execute before every SELECT statement
*
* @param ConnectionInterface \$con The connection object used by the query
*/
protected function basePreSelect(ConnectionInterface \$con)
{" . $behaviorCode . "
return \$this->preSelect(\$con);
}
";
}
/**
* Adds the basePreDelete hook for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addBasePreDelete(&$script)
{
$behaviorCode = '';
$this->applyBehaviorModifier('preDeleteQuery', $behaviorCode, " ");
if (!$behaviorCode) {
return;
}
$script .= "
/**
* Code to execute before every DELETE statement
*
* @param ConnectionInterface \$con The connection object used by the query
*/
protected function basePreDelete(ConnectionInterface \$con)
{" . $behaviorCode . "
return \$this->preDelete(\$con);
}
";
}
/**
* Adds the basePostDelete hook for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addBasePostDelete(&$script)
{
$behaviorCode = '';
$this->applyBehaviorModifier('postDeleteQuery', $behaviorCode, " ");
if (!$behaviorCode) {
return;
}
$script .= "
/**
* Code to execute after every DELETE statement
*
* @param int \$affectedRows the number of deleted rows
* @param ConnectionInterface \$con The connection object used by the query
*/
protected function basePostDelete(\$affectedRows, ConnectionInterface \$con)
{" . $behaviorCode . "
return \$this->postDelete(\$affectedRows, \$con);
}
";
}
/**
* Adds the basePreUpdate hook for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addBasePreUpdate(&$script)
{
$behaviorCode = '';
$this->applyBehaviorModifier('preUpdateQuery', $behaviorCode, " ");
if (!$behaviorCode) {
return;
}
$script .= "
/**
* Code to execute before every UPDATE statement
*
* @param array \$values The associative array of columns and values for the update
* @param ConnectionInterface \$con The connection object used by the query
* @param boolean \$forceIndividualSaves If false (default), the resulting call is a Criteria::doUpdate(), otherwise it is a series of save() calls on all the found objects
*/
protected function basePreUpdate(&\$values, ConnectionInterface \$con, \$forceIndividualSaves = false)
{" . $behaviorCode . "
return \$this->preUpdate(\$values, \$con, \$forceIndividualSaves);
}
";
}
/**
* Adds the basePostUpdate hook for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addBasePostUpdate(&$script)
{
$behaviorCode = '';
$this->applyBehaviorModifier('postUpdateQuery', $behaviorCode, " ");
if (!$behaviorCode) {
return;
}
$script .= "
/**
* Code to execute after every UPDATE statement
*
* @param int \$affectedRows the number of updated rows
* @param ConnectionInterface \$con The connection object used by the query
*/
protected function basePostUpdate(\$affectedRows, ConnectionInterface \$con)
{" . $behaviorCode . "
return \$this->postUpdate(\$affectedRows, \$con);
}
";
}
/**
* 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"
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier = null)
{
return parent::hasBehaviorModifier($hookName, 'QueryBuilderModifier');
}
/**
* 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.
*/
public function applyBehaviorModifier($hookName, &$script, $tab = " ")
{
return $this->applyBehaviorModifierBase($hookName, 'QueryBuilderModifier', $script, $tab);
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassName"
*/
public function getBehaviorContent($contentName)
{
return $this->getBehaviorContentBase($contentName, 'QueryBuilderModifier');
}
/**
* Adds the doDelete() method.
* @param string &$script The script will be modified in this method.
*/
protected function addDelete(&$script)
{
$script .= "
/**
* Performs a DELETE on the database based on the current ModelCriteria
*
* @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 function delete(ConnectionInterface \$con = null)
{
if (null === \$con) {
\$con = Propel::getServiceContainer()->getWriteConnection(" . $this->getTableMapClass() . "::DATABASE_NAME);
}
\$criteria = \$this;
// Set the correct dbName
\$criteria->setDbName(" . $this->getTableMapClass() . "::DATABASE_NAME);
// use transaction because \$criteria could contain info
// for more than one table or we could emulating ON DELETE CASCADE, etc.
return \$con->transaction(function () use (\$con, \$criteria) {
\$affectedRows = 0; // initialize var to track total num of affected rows
";
if ($this->isDeleteCascadeEmulationNeeded()) {
$script .= "
// cloning the Criteria in case it's modified by doSelect() or doSelectStmt()
\$c = clone \$criteria;
\$affectedRows += \$c->doOnDeleteCascade(\$con);
";
}
if ($this->isDeleteSetNullEmulationNeeded()) {
$script .= "
// cloning the Criteria in case it's modified by doSelect() or doSelectStmt()
\$c = clone \$criteria;
\$c->doOnDeleteSetNull(\$con);
";
}
$script .= "
{$this->getTableMapClassName()}::removeInstanceFromPool(\$criteria);
";
$script .= "
\$affectedRows += ModelCriteria::delete(\$con);
{$this->getTableMapClassName()}::clearRelatedInstancePool();
return \$affectedRows;
});
}
";
}
/**
* 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 Query classes.
*
* This method should be used within a transaction if possible.
*
* @param ConnectionInterface \$con
* @return int The number of affected rows (if supported by underlying database driver).
*/
protected function doOnDeleteCascade(ConnectionInterface \$con)
{
// initialize var to track total num of affected rows
\$affectedRows = 0;
// first find the objects that are implicated by the \$this
\$objects = {$this->getQueryClassName()}::create(null, \$this)->find(\$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();
$joinedTableTableMapBuilder = $this->getNewTableMapBuilder($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 = $joinedTableTableMapBuilder->getObjectClassName();
if (ForeignKey::CASCADE === $fk->getOnDelete()) {
// backwards on purpose
$columnNamesF = $fk->getLocalColumns();
$columnNamesL = $fk->getForeignColumns();
$this->declareClassFromBuilder($joinedTableTableMapBuilder->getTableMapBuilder());
$script .= "
// delete related $fkClassName objects
\$query = new ".$joinedTableTableMapBuilder->getQueryClassName(true).";
";
for ($x = 0, $xlen = count($columnNamesF); $x < $xlen; $x++) {
$columnFK = $tblFK->getColumn($columnNamesF[$x]);
$columnL = $table->getColumn($columnNamesL[$x]);
$script .= "
\$query->add(".$joinedTableTableMapBuilder->getColumnConstant($columnFK) .", \$obj->get".$columnL->getPhpName()."());";
}
$script .= "
\$affectedRows += \$query->delete(\$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 query classes.
*
* This method should be used within a transaction if possible.
*
* @param ConnectionInterface \$con
* @return void
*/
protected function doOnDeleteSetNull(ConnectionInterface \$con)
{
// first find the objects that are implicated by the \$this
\$objects = {$this->getQueryClassName()}::create(null, \$this)->find(\$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 things 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();
$refTableTableMapBuilder = $this->getNewTableMapBuilder($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 = $refTableTableMapBuilder->getObjectClassName();
if (ForeignKey::SETNULL === $fk->getOnDelete()) {
// backwards on purpose
$columnNamesF = $fk->getLocalColumns();
$columnNamesL = $fk->getForeignColumns(); // should be same num as foreign
$this->declareClassFromBuilder($refTableTableMapBuilder);
$script .= "
// set fkey col in related $fkClassName rows to NULL
\$query = new " . $refTableTableMapBuilder->getQueryClassName(true) . "();
\$updateValues = new Criteria();";
for ($x = 0, $xlen = count($columnNamesF); $x < $xlen; $x++) {
$columnFK = $tblFK->getColumn($columnNamesF[$x]);
$columnL = $table->getColumn($columnNamesL[$x]);
$script .= "
\$query->add(".$refTableTableMapBuilder->getColumnConstant($columnFK).", \$obj->get".$columnL->getPhpName()."());
\$updateValues->add(".$refTableTableMapBuilder->getColumnConstant($columnFK).", null);
";
}
$script .= "\$query->update(\$updateValues, \$con);
";
} // if setnull && fkey table name != curr table name
} // if not for ref only
} // foreach foreign keys
$script .= "
}
}
";
}
/**
* Adds the doDeleteAll() method.
* @param string &$script The script will be modified in this method.
*/
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 function doDeleteAll(ConnectionInterface \$con = null)
{
if (null === \$con) {
\$con = Propel::getServiceContainer()->getWriteConnection(" . $this->getTableMapClass() . "::DATABASE_NAME);
}
// use transaction because \$criteria could contain info
// for more than one table or we could emulating ON DELETE CASCADE, etc.
return \$con->transaction(function () use (\$con) {
\$affectedRows = 0; // initialize var to track total num of affected rows
";
if ($this->isDeleteCascadeEmulationNeeded()) {
$script .="\$affectedRows += \$this->doOnDeleteCascade(\$con);
";
}
if ($this->isDeleteSetNullEmulationNeeded()) {
$script .= "\$this->doOnDeleteSetNull(\$con);
";
}
$script .= "\$affectedRows += parent::doDeleteAll(\$con);
// Because this db requires some delete cascade/set null emulation, we have to
// clear the cached instance *after* the emulation has happened (since
// instances get re-added by the select statement contained therein).
{$this->getTableMapClassName()}::clearInstancePool();
{$this->getTableMapClassName()}::clearRelatedInstancePool();
return \$affectedRows;
});
}
";
}
}