CC-2166: Packaging Improvements. Moved the Zend app into airtime_mvc. It is now installed to /var/www/airtime. Storage is now set to /srv/airtime/stor. Utils are now installed to /usr/lib/airtime/utils/. Added install/airtime-dircheck.php as a simple test to see if everything is install/uninstalled correctly.
This commit is contained in:
parent
514777e8d2
commit
b11cbd8159
4546 changed files with 138 additions and 51 deletions
|
@ -0,0 +1,133 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Changes the coding standard of Propel generated Model classes
|
||||
* - Opening brackets always use newline, e.g.
|
||||
* if ($foo) {
|
||||
* ...
|
||||
* } else {
|
||||
* ...
|
||||
* }
|
||||
* Becomes:
|
||||
* if ($foo)
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
* - closing comments are removed, e.g.
|
||||
* } // save()
|
||||
* Becomes:
|
||||
* }
|
||||
* - tabs are replaced by 2 whitespaces
|
||||
* - comments are stripped (optional)
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.behavior
|
||||
*/
|
||||
class AlternativeCodingStandardsBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'brackets_newline' => 'true',
|
||||
'remove_closing_comments' => 'true',
|
||||
'use_whitespace' => 'true',
|
||||
'tab_size' => 2,
|
||||
'strip_comments' => 'false'
|
||||
);
|
||||
|
||||
public function objectFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function extensionObjectFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function queryFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function extensionQueryFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function peerFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function extensionPeerFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
public function tableMapFilter(&$script)
|
||||
{
|
||||
return $this->filter($script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the coding standards of a PHP sourcecode string
|
||||
*
|
||||
* @param string $script A script string to be filtered, passed as reference
|
||||
*/
|
||||
protected function filter(&$script)
|
||||
{
|
||||
$filter = array();
|
||||
if($this->getParameter('brackets_newline') == 'true') {
|
||||
$filter['#^(\t*)\}\h(else|elseif|catch)(.*)\h\{$#m'] = "$1}
|
||||
$1$2$3
|
||||
$1{";
|
||||
$filter['#^(\t*)(\w.*)\h\{$#m'] = "$1$2
|
||||
$1{";
|
||||
}
|
||||
if ($this->getParameter('remove_closing_comments') == 'true') {
|
||||
$filter['#^(\t*)} //.*$#m'] = "$1}";
|
||||
}
|
||||
if ($this->getParameter('use_whitespace') == 'true') {
|
||||
$filter['#\t#'] = str_repeat(' ', $this->getParameter('tab_size'));
|
||||
}
|
||||
|
||||
$script = preg_replace(array_keys($filter), array_values($filter), $script);
|
||||
|
||||
if ($this->getParameter('strip_comments') == 'true') {
|
||||
$script = self::stripComments($script);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inline and codeblock comments from a PHP code string
|
||||
* @param string $code The input code
|
||||
* @return string The input code, without comments
|
||||
*/
|
||||
public static function stripComments($code)
|
||||
{
|
||||
$output = '';
|
||||
$commentTokens = array(T_COMMENT, T_DOC_COMMENT);
|
||||
foreach (token_get_all($code) as $token) {
|
||||
if (is_array($token)) {
|
||||
if (in_array($token[0], $commentTokens)) continue;
|
||||
$token = $token[1];
|
||||
}
|
||||
$output .= $token;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a primary key to models defined without one
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1745 $
|
||||
* @package propel.generator.behavior
|
||||
*/
|
||||
class AutoAddPkBehavior extends Behavior
|
||||
{
|
||||
protected $isEarly = true;
|
||||
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'name' => 'id',
|
||||
'autoIncrement' => 'true',
|
||||
'type' => 'INTEGER'
|
||||
);
|
||||
|
||||
/**
|
||||
* Copy the behavior to the database tables
|
||||
* Only for tables that have no Pk
|
||||
*/
|
||||
public function modifyDatabase()
|
||||
{
|
||||
foreach ($this->getDatabase()->getTables() as $table) {
|
||||
if(!$table->hasPrimaryKey()) {
|
||||
$b = clone $this;
|
||||
$table->addBehavior($b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the primary key to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
$table = $this->getTable();
|
||||
if (!$table->hasPrimaryKey() && !$table->hasBehavior('concrete_inheritance')) {
|
||||
$columnAttributes = array_merge(array('primaryKey' => 'true'), $this->getParameters());
|
||||
$this->getTable()->addColumn($columnAttributes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gives a model class the ability to remain in database even when the user deletes object
|
||||
* Uses an additional column storing the deletion date
|
||||
* And an additional condition for every read query to only consider rows with no deletion date
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1807 $
|
||||
* @package propel.generator.behavior
|
||||
*/
|
||||
class SoftDeleteBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'deleted_column' => 'deleted_at',
|
||||
);
|
||||
|
||||
/**
|
||||
* Add the deleted_column to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('deleted_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('deleted_column'),
|
||||
'type' => 'TIMESTAMP'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getColumnSetter()
|
||||
{
|
||||
return 'set' . $this->getColumnForParameter('deleted_column')->getPhpName();
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
$script = '';
|
||||
$this->addObjectForceDelete($script);
|
||||
$this->addObjectUndelete($script);
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function addObjectForceDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Bypass the soft_delete behavior and force a hard delete of the current object
|
||||
*/
|
||||
public function forceDelete(PropelPDO \$con = null)
|
||||
{
|
||||
{$this->getTable()->getPhpName()}Peer::disableSoftDelete();
|
||||
\$this->delete(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addObjectUndelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Undelete a row that was soft_deleted
|
||||
*
|
||||
* @return int The number of rows affected by this update and any referring fk objects' save() operations.
|
||||
*/
|
||||
public function unDelete(PropelPDO \$con = null)
|
||||
{
|
||||
\$this->{$this->getColumnSetter()}(null);
|
||||
return \$this->save(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function preDelete($builder)
|
||||
{
|
||||
return <<<EOT
|
||||
if (!empty(\$ret) && {$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled()) {
|
||||
\$this->{$this->getColumnSetter()}(time());
|
||||
\$this->save(\$con);
|
||||
\$con->commit();
|
||||
{$builder->getStubPeerBuilder()->getClassname()}::removeInstanceFromPool(\$this);
|
||||
return;
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
|
||||
public function queryAttributes()
|
||||
{
|
||||
return "protected static \$softDelete = true;
|
||||
protected \$localSoftDelete = true;
|
||||
";
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$script = '';
|
||||
$this->addQueryIncludeDeleted($script);
|
||||
$this->addQuerySoftDelete($script);
|
||||
$this->addQueryForceDelete($script);
|
||||
$this->addQueryForceDeleteAll($script);
|
||||
$this->addQueryUnDelete($script);
|
||||
$this->addQueryEnableSoftDelete($script);
|
||||
$this->addQueryDisableSoftDelete($script);
|
||||
$this->addQueryIsSoftDeleteEnabled($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function addQueryIncludeDeleted(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Temporarily disable the filter on deleted rows
|
||||
* Valid only for the current query
|
||||
*
|
||||
* @see {$this->builder->getStubQueryBuilder()->getClassname()}::disableSoftDelete() to disable the filter for more than one query
|
||||
*
|
||||
* @return {$this->builder->getStubQueryBuilder()->getClassname()} The current query, for fuid interface
|
||||
*/
|
||||
public function includeDeleted()
|
||||
{
|
||||
\$this->localSoftDelete = false;
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQuerySoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Soft delete the selected rows
|
||||
*
|
||||
* @param PropelPDO \$con an optional connection object
|
||||
*
|
||||
* @return int Number of updated rows
|
||||
*/
|
||||
public function softDelete(PropelPDO \$con = null)
|
||||
{
|
||||
return \$this->update(array('{$this->getColumnForParameter('deleted_column')->getPhpName()}' => time()), \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryForceDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Bypass the soft_delete behavior and force a hard delete of the selected rows
|
||||
*
|
||||
* @param PropelPDO \$con an optional connection object
|
||||
*
|
||||
* @return int Number of deleted rows
|
||||
*/
|
||||
public function forceDelete(PropelPDO \$con = null)
|
||||
{
|
||||
return {$this->builder->getPeerClassname()}::doForceDelete(\$this, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryForceDeleteAll(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Bypass the soft_delete behavior and force a hard delete of all the rows
|
||||
*
|
||||
* @param PropelPDO \$con an optional connection object
|
||||
*
|
||||
* @return int Number of deleted rows
|
||||
*/
|
||||
public function forceDeleteAll(PropelPDO \$con = null)
|
||||
{
|
||||
return {$this->builder->getPeerClassname()}::doForceDeleteAll(\$con);}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryUnDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Undelete selected rows
|
||||
*
|
||||
* @param PropelPDO \$con an optional connection object
|
||||
*
|
||||
* @return int The number of rows affected by this update and any referring fk objects' save() operations.
|
||||
*/
|
||||
public function unDelete(PropelPDO \$con = null)
|
||||
{
|
||||
return \$this->update(array('{$this->getColumnForParameter('deleted_column')->getPhpName()}' => null), \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryEnableSoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Enable the soft_delete behavior for this model
|
||||
*/
|
||||
public static function enableSoftDelete()
|
||||
{
|
||||
self::\$softDelete = true;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryDisableSoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Disable the soft_delete behavior for this model
|
||||
*/
|
||||
public static function disableSoftDelete()
|
||||
{
|
||||
self::\$softDelete = false;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addQueryIsSoftDeleteEnabled(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Check the soft_delete behavior for this model
|
||||
*
|
||||
* @return boolean true if the soft_delete behavior is enabled
|
||||
*/
|
||||
public static function isSoftDeleteEnabled()
|
||||
{
|
||||
return self::\$softDelete;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function preSelectQuery($builder)
|
||||
{
|
||||
return <<<EOT
|
||||
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled() && \$this->localSoftDelete) {
|
||||
\$this->addUsingAlias({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
|
||||
} else {
|
||||
{$this->getTable()->getPhpName()}Peer::enableSoftDelete();
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
|
||||
public function preDeleteQuery($builder)
|
||||
{
|
||||
return <<<EOT
|
||||
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled() && \$this->localSoftDelete) {
|
||||
return \$this->softDelete(\$con);
|
||||
} else {
|
||||
return \$this->hasWhereClause() ? \$this->forceDelete(\$con) : \$this->forceDeleteAll(\$con);
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
|
||||
public function staticMethods($builder)
|
||||
{
|
||||
$builder->declareClassFromBuilder($builder->getStubQueryBuilder());
|
||||
$this->builder = $builder;
|
||||
$script = '';
|
||||
$this->addPeerEnableSoftDelete($script);
|
||||
$this->addPeerDisableSoftDelete($script);
|
||||
$this->addPeerIsSoftDeleteEnabled($script);
|
||||
$this->addPeerDoSoftDelete($script);
|
||||
$this->addPeerDoDelete2($script);
|
||||
$this->addPeerDoSoftDeleteAll($script);
|
||||
$this->addPeerDoDeleteAll2($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function addPeerEnableSoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Enable the soft_delete behavior for this model
|
||||
*/
|
||||
public static function enableSoftDelete()
|
||||
{
|
||||
{$this->builder->getStubQueryBuilder()->getClassname()}::enableSoftDelete();
|
||||
// some soft_deleted objects may be in the instance pool
|
||||
{$this->builder->getStubPeerBuilder()->getClassname()}::clearInstancePool();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addPeerDisableSoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Disable the soft_delete behavior for this model
|
||||
*/
|
||||
public static function disableSoftDelete()
|
||||
{
|
||||
{$this->builder->getStubQueryBuilder()->getClassname()}::disableSoftDelete();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addPeerIsSoftDeleteEnabled(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Check the soft_delete behavior for this model
|
||||
* @return boolean true if the soft_delete behavior is enabled
|
||||
*/
|
||||
public static function isSoftDeleteEnabled()
|
||||
{
|
||||
return {$this->builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addPeerDoSoftDelete(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Soft delete records, given a {$this->getTable()->getPhpName()} or Criteria object OR a primary key value.
|
||||
*
|
||||
* @param mixed \$values Criteria or {$this->getTable()->getPhpName()} object or primary key or array of primary keys
|
||||
* which is used to create the DELETE statement
|
||||
* @param PropelPDO \$con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doSoftDelete(\$values, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$values instanceof Criteria) {
|
||||
// rename for clarity
|
||||
\$criteria = clone \$values;
|
||||
} elseif (\$values instanceof {$this->getTable()->getPhpName()}) {
|
||||
// create criteria based on pk values
|
||||
\$criteria = \$values->buildPkeyCriteria();
|
||||
} else {
|
||||
// it must be the primary key
|
||||
\$criteria = new Criteria(self::DATABASE_NAME);";
|
||||
$pks = $this->getTable()->getPrimaryKey();
|
||||
if (count($pks)>1) {
|
||||
$i = 0;
|
||||
foreach ($pks as $col) {
|
||||
$script .= "
|
||||
\$criteria->add({$col->getConstantName()}, \$values[$i], Criteria::EQUAL);";
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
$col = $pks[0];
|
||||
$script .= "
|
||||
\$criteria->add({$col->getConstantName()}, (array) \$values, Criteria::IN);";
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
\$criteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, time());
|
||||
return {$this->getTable()->getPhpName()}Peer::doUpdate(\$criteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addPeerDoDelete2(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Delete or soft delete records, depending on {$this->getTable()->getPhpName()}Peer::\$softDelete
|
||||
*
|
||||
* @param mixed \$values Criteria or {$this->getTable()->getPhpName()} object or primary key or array of primary keys
|
||||
* which is used to create the DELETE statement
|
||||
* @param PropelPDO \$con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doDelete2(\$values, PropelPDO \$con = null)
|
||||
{
|
||||
if ({$this->getTable()->getPhpName()}Peer::isSoftDeleteEnabled()) {
|
||||
return {$this->getTable()->getPhpName()}Peer::doSoftDelete(\$values, \$con);
|
||||
} else {
|
||||
return {$this->getTable()->getPhpName()}Peer::doForceDelete(\$values, \$con);
|
||||
}
|
||||
}";
|
||||
}
|
||||
|
||||
public function addPeerDoSoftDeleteAll(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Method to soft delete all rows from the {$this->getTable()->getName()} table.
|
||||
*
|
||||
* @param PropelPDO \$con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doSoftDeleteAll(PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->getTable()->getPhpName()}Peer::DATABASE_NAME, Propel::CONNECTION_WRITE);
|
||||
}
|
||||
\$selectCriteria = new Criteria();
|
||||
\$selectCriteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
|
||||
\$selectCriteria->setDbName({$this->getTable()->getPhpName()}Peer::DATABASE_NAME);
|
||||
\$modifyCriteria = new Criteria();
|
||||
\$modifyCriteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, time());
|
||||
return BasePeer::doUpdate(\$selectCriteria, \$modifyCriteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addPeerDoDeleteAll2(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Delete or soft delete all records, depending on {$this->getTable()->getPhpName()}Peer::\$softDelete
|
||||
*
|
||||
* @param PropelPDO \$con the connection to use
|
||||
* @return int The number of affected rows (if supported by underlying database driver).
|
||||
* @throws PropelException Any exceptions caught during processing will be
|
||||
* rethrown wrapped into a PropelException.
|
||||
*/
|
||||
public static function doDeleteAll2(PropelPDO \$con = null)
|
||||
{
|
||||
if ({$this->getTable()->getPhpName()}Peer::isSoftDeleteEnabled()) {
|
||||
return {$this->getTable()->getPhpName()}Peer::doSoftDeleteAll(\$con);
|
||||
} else {
|
||||
return {$this->getTable()->getPhpName()}Peer::doForceDeleteAll(\$con);
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function preSelect($builder)
|
||||
{
|
||||
return <<<EOT
|
||||
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled()) {
|
||||
\$criteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
|
||||
} else {
|
||||
{$this->getTable()->getPhpName()}Peer::enableSoftDelete();
|
||||
}
|
||||
EOT;
|
||||
}
|
||||
|
||||
public function peerFilter(&$script)
|
||||
{
|
||||
$script = str_replace(array(
|
||||
'public static function doDelete(',
|
||||
'public static function doDelete2(',
|
||||
'public static function doDeleteAll(',
|
||||
'public static function doDeleteAll2('
|
||||
), array(
|
||||
'public static function doForceDelete(',
|
||||
'public static function doDelete(',
|
||||
'public static function doForceDeleteAll(',
|
||||
'public static function doDeleteAll('
|
||||
), $script);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gives a model class the ability to track creation and last modification dates
|
||||
* Uses two additional columns storing the creation and update date
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1683 $
|
||||
* @package propel.generator.behavior
|
||||
*/
|
||||
class TimestampableBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'create_column' => 'created_at',
|
||||
'update_column' => 'updated_at'
|
||||
);
|
||||
|
||||
/**
|
||||
* Add the create_column and update_columns to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('create_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('create_column'),
|
||||
'type' => 'TIMESTAMP'
|
||||
));
|
||||
}
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('update_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('update_column'),
|
||||
'type' => 'TIMESTAMP'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the setter of one of the columns of the behavior
|
||||
*
|
||||
* @param string $column One of the behavior colums, 'create_column' or 'update_column'
|
||||
* @return string The related setter, 'setCreatedOn' or 'setUpdatedOn'
|
||||
*/
|
||||
protected function getColumnSetter($column)
|
||||
{
|
||||
return 'set' . $this->getColumnForParameter($column)->getPhpName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add code in ObjectBuilder::preUpdate
|
||||
*
|
||||
* @return string The code to put at the hook
|
||||
*/
|
||||
public function preUpdate()
|
||||
{
|
||||
return "if (\$this->isModified() && !\$this->isColumnModified(" . $this->getColumnForParameter('update_column')->getConstantName() . ")) {
|
||||
\$this->" . $this->getColumnSetter('update_column') . "(time());
|
||||
}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add code in ObjectBuilder::preInsert
|
||||
*
|
||||
* @return string The code to put at the hook
|
||||
*/
|
||||
public function preInsert()
|
||||
{
|
||||
return "if (!\$this->isColumnModified(" . $this->getColumnForParameter('create_column')->getConstantName() . ")) {
|
||||
\$this->" . $this->getColumnSetter('create_column') . "(time());
|
||||
}
|
||||
if (!\$this->isColumnModified(" . $this->getColumnForParameter('update_column')->getConstantName() . ")) {
|
||||
\$this->" . $this->getColumnSetter('update_column') . "(time());
|
||||
}";
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
return "
|
||||
/**
|
||||
* Mark the current object so that the update date doesn't get updated during next save
|
||||
*
|
||||
* @return " . $builder->getStubObjectBuilder()->getClassname() . " The current object (for fluent API support)
|
||||
*/
|
||||
public function keepUpdateDateUnchanged()
|
||||
{
|
||||
\$this->modifiedColumns[] = " . $this->getColumnForParameter('update_column')->getConstantName() . ";
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$queryClassName = $builder->getStubQueryBuilder()->getClassname();
|
||||
$updateColumnConstant = $this->getColumnForParameter('update_column')->getConstantName();
|
||||
$createColumnConstant = $this->getColumnForParameter('create_column')->getConstantName();
|
||||
return "
|
||||
/**
|
||||
* Filter by the latest updated
|
||||
*
|
||||
* @param int \$nbDays Maximum age of the latest update in days
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function recentlyUpdated(\$nbDays = 7)
|
||||
{
|
||||
return \$this->addUsingAlias($updateColumnConstant, time() - \$nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by the latest created
|
||||
*
|
||||
* @param int \$nbDays Maximum age of in days
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function recentlyCreated(\$nbDays = 7)
|
||||
{
|
||||
return \$this->addUsingAlias($createColumnConstant, time() - \$nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by update date desc
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function lastUpdatedFirst()
|
||||
{
|
||||
return \$this->addDescendingOrderByColumn($updateColumnConstant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by update date asc
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function firstUpdatedFirst()
|
||||
{
|
||||
return \$this->addAscendingOrderByColumn($updateColumnConstant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by create date desc
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function lastCreatedFirst()
|
||||
{
|
||||
return \$this->addDescendingOrderByColumn($createColumnConstant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by create date asc
|
||||
*
|
||||
* @return $queryClassName The current query, for fuid interface
|
||||
*/
|
||||
public function firstCreatedFirst()
|
||||
{
|
||||
return \$this->addAscendingOrderByColumn($createColumnConstant);
|
||||
}
|
||||
";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
require_once 'AggregateColumnRelationBehavior.php';
|
||||
|
||||
/**
|
||||
* Keeps an aggregate column updated with related table
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1785 $
|
||||
* @package propel.generator.behavior.aggregate_column
|
||||
*/
|
||||
class AggregateColumnBehavior extends Behavior
|
||||
{
|
||||
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'name' => null,
|
||||
'expression' => null,
|
||||
'foreign_table' => null,
|
||||
);
|
||||
|
||||
/**
|
||||
* Add the aggregate key to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
$table = $this->getTable();
|
||||
if (!$columnName = $this->getParameter('name')) {
|
||||
throw new InvalidArgumentException(sprintf('You must define a \'name\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $table->getName()));
|
||||
}
|
||||
|
||||
// add the aggregate column if not present
|
||||
if(!$this->getTable()->containsColumn($columnName)) {
|
||||
$column = $this->getTable()->addColumn(array(
|
||||
'name' => $columnName,
|
||||
'type' => 'INTEGER',
|
||||
));
|
||||
}
|
||||
|
||||
// add a behavior in the foreign table to autoupdate the aggregate column
|
||||
$foreignTable = $this->getForeignTable();
|
||||
if (!$foreignTable->hasBehavior('concrete_inheritance_parent')) {
|
||||
$relationBehavior = new AggregateColumnRelationBehavior();
|
||||
$relationBehavior->setName('aggregate_column_relation');
|
||||
$foreignKey = $this->getForeignKey();
|
||||
$relationBehavior->addParameter(array('name' => 'foreign_table', 'value' => $table->getName()));
|
||||
$relationBehavior->addParameter(array('name' => 'update_method', 'value' => 'update' . $this->getColumn()->getPhpName()));
|
||||
$foreignTable->addBehavior($relationBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
if (!$foreignTableName = $this->getParameter('foreign_table')) {
|
||||
throw new InvalidArgumentException(sprintf('You must define a \'foreign_table\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $this->getTable()->getName()));
|
||||
}
|
||||
$script = '';
|
||||
$script .= $this->addObjectCompute();
|
||||
$script .= $this->addObjectUpdate();
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addObjectCompute()
|
||||
{
|
||||
$conditions = array();
|
||||
$bindings = array();
|
||||
foreach ($this->getForeignKey()->getColumnObjectsMapping() as $index => $columnReference) {
|
||||
$conditions[] = $columnReference['local']->getFullyQualifiedName() . ' = :p' . ($index + 1);
|
||||
$bindings[$index + 1] = $columnReference['foreign']->getPhpName();
|
||||
}
|
||||
$sql = sprintf('SELECT %s FROM %s WHERE %s',
|
||||
$this->getParameter('expression'),
|
||||
$this->getTable()->getDatabase()->getPlatform()->quoteIdentifier($this->getParameter('foreign_table')),
|
||||
implode(' AND ', $conditions)
|
||||
);
|
||||
|
||||
return $this->renderTemplate('objectCompute', array(
|
||||
'column' => $this->getColumn(),
|
||||
'sql' => $sql,
|
||||
'bindings' => $bindings,
|
||||
));
|
||||
}
|
||||
|
||||
protected function addObjectUpdate()
|
||||
{
|
||||
return $this->renderTemplate('objectUpdate', array(
|
||||
'column' => $this->getColumn(),
|
||||
));
|
||||
}
|
||||
|
||||
protected function getForeignTable()
|
||||
{
|
||||
return $this->getTable()->getDatabase()->getTable($this->getParameter('foreign_table'));
|
||||
}
|
||||
|
||||
protected function getForeignKey()
|
||||
{
|
||||
$foreignTable = $this->getForeignTable();
|
||||
// let's infer the relation from the foreign table
|
||||
$fks = $foreignTable->getForeignKeysReferencingTable($this->getTable()->getName());
|
||||
if (!$fks) {
|
||||
throw new InvalidArgumentException(sprintf('You must define a foreign key to the \'%s\' table in the \'%s\' table to enable the \'aggregate_column\' behavior', $this->getTable()->getName(), $foreignTable->getName()));
|
||||
}
|
||||
// FIXME doesn't work when more than one fk to the same table
|
||||
return array_shift($fks);
|
||||
}
|
||||
|
||||
protected function getColumn()
|
||||
{
|
||||
return $this->getTable()->getColumn($this->getParameter('name'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
require_once 'AggregateColumnRelationBehavior.php';
|
||||
|
||||
/**
|
||||
* Keeps an aggregate column updated with related table
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1785 $
|
||||
* @package propel.generator.behavior.aggregate_column
|
||||
*/
|
||||
class AggregateColumnRelationBehavior extends Behavior
|
||||
{
|
||||
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'foreign_table' => '',
|
||||
'update_method' => '',
|
||||
);
|
||||
|
||||
public function postSave($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return "\$this->updateRelated{$relationName}(\$con);";
|
||||
}
|
||||
|
||||
// no need for a postDelete() hook, since delete() uses Query::delete(),
|
||||
// which already has a hook
|
||||
|
||||
public function objectAttributes($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return "protected \$old{$relationName};
|
||||
";
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
return $this->addObjectUpdateRelated($builder);
|
||||
}
|
||||
|
||||
protected function addObjectUpdateRelated($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
$updateMethodName = $this->getParameter('update_method');
|
||||
return $this->renderTemplate('objectUpdateRelated', array(
|
||||
'relationName' => $relationName,
|
||||
'variableName' => self::lcfirst($relationName),
|
||||
'updateMethodName' => $this->getParameter('update_method'),
|
||||
));
|
||||
}
|
||||
|
||||
public function objectFilter(&$script, $builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
$relatedClass = $this->getForeignTable()->getPhpName();
|
||||
$search = " public function set{$relationName}({$relatedClass} \$v = null)
|
||||
{";
|
||||
$replace = $search . "
|
||||
// aggregate_column_relation behavior
|
||||
if (null !== \$this->a{$relationName} && \$v !== \$this->a{$relationName}) {
|
||||
\$this->old{$relationName} = \$this->a{$relationName};
|
||||
}";
|
||||
$script = str_replace($search, $replace, $script);
|
||||
}
|
||||
|
||||
public function preUpdateQuery($builder)
|
||||
{
|
||||
return $this->getFindRelated($builder);
|
||||
}
|
||||
|
||||
public function preDeleteQuery($builder)
|
||||
{
|
||||
return $this->getFindRelated($builder);
|
||||
}
|
||||
|
||||
protected function getFindRelated($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return "\$this->findRelated{$relationName}s(\$con);";
|
||||
}
|
||||
|
||||
public function postUpdateQuery($builder)
|
||||
{
|
||||
return $this->getUpdateRelated($builder);
|
||||
}
|
||||
|
||||
public function postDeleteQuery($builder)
|
||||
{
|
||||
return $this->getUpdateRelated($builder);
|
||||
}
|
||||
|
||||
protected function getUpdateRelated($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return "\$this->updateRelated{$relationName}s(\$con);";
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$script = '';
|
||||
$script .= $this->addQueryFindRelated($builder);
|
||||
$script .= $this->addQueryUpdateRelated($builder);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addQueryFindRelated($builder)
|
||||
{
|
||||
$foreignKey = $this->getForeignKey();
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return $this->renderTemplate('queryFindRelated', array(
|
||||
'foreignTable' => $this->getForeignTable(),
|
||||
'relationName' => $relationName,
|
||||
'variableName' => self::lcfirst($relationName),
|
||||
'foreignQueryName' => $foreignKey->getForeignTable()->getPhpName() . 'Query',
|
||||
'refRelationName' => $builder->getRefFKPhpNameAffix($foreignKey),
|
||||
));
|
||||
}
|
||||
|
||||
protected function addQueryUpdateRelated($builder)
|
||||
{
|
||||
$relationName = $this->getRelationName($builder);
|
||||
return $this->renderTemplate('queryUpdateRelated', array(
|
||||
'relationName' => $relationName,
|
||||
'variableName' => self::lcfirst($relationName),
|
||||
'updateMethodName' => $this->getParameter('update_method'),
|
||||
));
|
||||
}
|
||||
|
||||
protected function getForeignTable()
|
||||
{
|
||||
return $this->getTable()->getDatabase()->getTable($this->getParameter('foreign_table'));
|
||||
}
|
||||
|
||||
protected function getForeignKey()
|
||||
{
|
||||
$foreignTable = $this->getForeignTable();
|
||||
// let's infer the relation from the foreign table
|
||||
$fks = $this->getTable()->getForeignKeysReferencingTable($foreignTable->getName());
|
||||
// FIXME doesn't work when more than one fk to the same table
|
||||
return array_shift($fks);
|
||||
}
|
||||
|
||||
protected function getRelationName($builder)
|
||||
{
|
||||
return $builder->getFKPhpNameAffix($this->getForeignKey());
|
||||
}
|
||||
|
||||
protected static function lcfirst($input)
|
||||
{
|
||||
// no lcfirst in php<5.3...
|
||||
$input[0] = strtolower($input[0]);
|
||||
return $input;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
/**
|
||||
* Computes the value of the aggregate column <?php echo $column->getName() ?>
|
||||
*
|
||||
* @param PropelPDO $con A connection object
|
||||
*
|
||||
* @return mixed The scalar result from the aggregate query
|
||||
*/
|
||||
public function compute<?php echo $column->getPhpName() ?>(PropelPDO $con)
|
||||
{
|
||||
$stmt = $con->prepare('<?php echo $sql ?>');
|
||||
<?php foreach ($bindings as $key => $binding): ?>
|
||||
$stmt->bindValue(':p<?php echo $key ?>', $this->get<?php echo $binding ?>());
|
||||
<?php endforeach; ?>
|
||||
$stmt->execute();
|
||||
return $stmt->fetchColumn();
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
/**
|
||||
* Updates the aggregate column <?php echo $column->getName() ?>
|
||||
*
|
||||
* @param PropelPDO $con A connection object
|
||||
*/
|
||||
public function update<?php echo $column->getPhpName() ?>(PropelPDO $con)
|
||||
{
|
||||
$this->set<?php echo $column->getPhpName() ?>($this->compute<?php echo $column->getPhpName() ?>($con));
|
||||
$this->save($con);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
/**
|
||||
* Update the aggregate column in the related <?php echo $relationName ?> object
|
||||
*
|
||||
* @param PropelPDO $con A connection object
|
||||
*/
|
||||
protected function updateRelated<?php echo $relationName ?>(PropelPDO $con)
|
||||
{
|
||||
if ($<?php echo $variableName ?> = $this->get<?php echo $relationName ?>()) {
|
||||
$<?php echo $variableName ?>-><?php echo $updateMethodName ?>($con);
|
||||
}
|
||||
if ($this->old<?php echo $relationName ?>) {
|
||||
$this->old<?php echo $relationName ?>-><?php echo $updateMethodName ?>($con);
|
||||
$this->old<?php echo $relationName ?> = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/**
|
||||
* Finds the related <?php echo $foreignTable->getPhpName() ?> objects and keep them for later
|
||||
*
|
||||
* @param PropelPDO $con A connection object
|
||||
*/
|
||||
protected function findRelated<?php echo $relationName ?>s($con)
|
||||
{
|
||||
$criteria = clone $this;
|
||||
if ($this->useAliasInSQL) {
|
||||
$alias = $this->getModelAlias();
|
||||
$criteria->removeAlias($alias);
|
||||
} else {
|
||||
$alias = '';
|
||||
}
|
||||
$this-><?php echo $variableName ?>s = <?php echo $foreignQueryName ?>::create()
|
||||
->join<?php echo $refRelationName ?>($alias)
|
||||
->mergeWith($criteria)
|
||||
->find($con);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
protected function updateRelated<?php echo $relationName ?>s($con)
|
||||
{
|
||||
foreach ($this-><?php echo $variableName ?>s as $<?php echo $variableName ?>) {
|
||||
$<?php echo $variableName ?>-><?php echo $updateMethodName ?>($con);
|
||||
}
|
||||
$this-><?php echo $variableName ?>s = array();
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
require_once 'ConcreteInheritanceParentBehavior.php';
|
||||
|
||||
/**
|
||||
* Gives a model class the ability to remain in database even when the user deletes object
|
||||
* Uses an additional column storing the deletion date
|
||||
* And an additional condition for every read query to only consider rows with no deletion date
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1774 $
|
||||
* @package propel.generator.behavior.concrete_inheritance
|
||||
*/
|
||||
class ConcreteInheritanceBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'extends' => '',
|
||||
'descendant_column' => 'descendant_class',
|
||||
'copy_data_to_parent' => 'true'
|
||||
);
|
||||
|
||||
public function modifyTable()
|
||||
{
|
||||
$table = $this->getTable();
|
||||
$parentTable = $this->getParentTable();
|
||||
|
||||
if ($this->isCopyData()) {
|
||||
// tell the parent table that it has a descendant
|
||||
if (!$parentTable->hasBehavior('concrete_inheritance_parent')) {
|
||||
$parentBehavior = new ConcreteInheritanceParentBehavior();
|
||||
$parentBehavior->setName('concrete_inheritance_parent');
|
||||
$parentBehavior->addParameter(array('name' => 'descendant_column', 'value' => $this->getParameter('descendant_column')));
|
||||
$parentTable->addBehavior($parentBehavior);
|
||||
// The parent table's behavior modifyTable() must be executed before this one
|
||||
$parentBehavior->getTableModifier()->modifyTable();
|
||||
$parentBehavior->setTableModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the columns of the parent table
|
||||
foreach ($parentTable->getColumns() as $column) {
|
||||
if ($column->getName() == $this->getParameter('descendant_column')) {
|
||||
continue;
|
||||
}
|
||||
if ($table->containsColumn($column->getName())) {
|
||||
continue;
|
||||
}
|
||||
$copiedColumn = clone $column;
|
||||
if ($column->isAutoIncrement() && $this->isCopyData()) {
|
||||
$copiedColumn->setAutoIncrement(false);
|
||||
}
|
||||
$table->addColumn($copiedColumn);
|
||||
if ($column->isPrimaryKey() && $this->isCopyData()) {
|
||||
$fk = new ForeignKey();
|
||||
$fk->setForeignTableName($column->getTable()->getName());
|
||||
$fk->setOnDelete('CASCADE');
|
||||
$fk->setOnUpdate(null);
|
||||
$fk->addReference($copiedColumn, $column);
|
||||
$fk->isParentChild = true;
|
||||
$table->addForeignKey($fk);
|
||||
}
|
||||
}
|
||||
|
||||
// add the foreign keys of the parent table
|
||||
foreach ($parentTable->getForeignKeys() as $fk) {
|
||||
$copiedFk = clone $fk;
|
||||
$copiedFk->setName('');
|
||||
$copiedFk->setRefPhpName('');
|
||||
$this->getTable()->addForeignKey($copiedFk);
|
||||
}
|
||||
|
||||
// add the validators of the parent table
|
||||
foreach ($parentTable->getValidators() as $validator) {
|
||||
$copiedValidator = clone $validator;
|
||||
$this->getTable()->addValidator($copiedValidator);
|
||||
}
|
||||
|
||||
// add the indices of the parent table
|
||||
foreach ($parentTable->getIndices() as $index) {
|
||||
$copiedIndex = clone $index;
|
||||
$copiedIndex->setName('');
|
||||
$this->getTable()->addIndex($copiedIndex);
|
||||
}
|
||||
|
||||
// add the unique indices of the parent table
|
||||
foreach ($parentTable->getUnices() as $unique) {
|
||||
$copiedUnique = clone $unique;
|
||||
$copiedUnique->setName('');
|
||||
$this->getTable()->addUnique($copiedUnique);
|
||||
}
|
||||
|
||||
// give name to newly added foreign keys and indices
|
||||
// (this is already done for other elements of the current table)
|
||||
$table->doNaming();
|
||||
|
||||
// add the Behaviors of the parent table
|
||||
foreach ($parentTable->getBehaviors() as $behavior) {
|
||||
if ($behavior->getName() == 'concrete_inheritance_parent' || $behavior->getName() == 'concrete_inheritance') {
|
||||
continue;
|
||||
}
|
||||
$copiedBehavior = clone $behavior;
|
||||
$this->getTable()->addBehavior($copiedBehavior);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function getParentTable()
|
||||
{
|
||||
return $this->getTable()->getDatabase()->getTable($this->getParameter('extends'));
|
||||
}
|
||||
|
||||
protected function isCopyData()
|
||||
{
|
||||
return $this->getParameter('copy_data_to_parent') == 'true';
|
||||
}
|
||||
|
||||
public function parentClass($builder)
|
||||
{
|
||||
switch (get_class($builder)) {
|
||||
case 'PHP5ObjectBuilder':
|
||||
return $builder->getNewStubObjectBuilder($this->getParentTable())->getClassname();
|
||||
break;
|
||||
case 'QueryBuilder':
|
||||
return $builder->getNewStubQueryBuilder($this->getParentTable())->getClassname();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function preSave($script)
|
||||
{
|
||||
if ($this->isCopyData()) {
|
||||
return "\$parent = \$this->getSyncParent(\$con);
|
||||
\$parent->save(\$con);
|
||||
\$this->setPrimaryKey(\$parent->getPrimaryKey());
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
public function postDelete($script)
|
||||
{
|
||||
if ($this->isCopyData()) {
|
||||
return "\$this->getParentOrCreate(\$con)->delete(\$con);
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
if (!$this->isCopyData()) {
|
||||
return;
|
||||
}
|
||||
$this->builder = $builder;
|
||||
$script .= '';
|
||||
$this->addObjectGetParentOrCreate($script);
|
||||
$this->addObjectGetSyncParent($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addObjectGetParentOrCreate(&$script)
|
||||
{
|
||||
$parentTable = $this->getParentTable();
|
||||
$parentClass = $this->builder->getNewStubObjectBuilder($parentTable)->getClassname();
|
||||
$script .= "
|
||||
/**
|
||||
* Get or Create the parent " . $parentClass . " object of the current object
|
||||
*
|
||||
* @return " . $parentClass . " The parent object
|
||||
*/
|
||||
public function getParentOrCreate(\$con = null)
|
||||
{
|
||||
if (\$this->isNew()) {
|
||||
\$parent = new " . $parentClass . "();
|
||||
\$parent->set" . $this->getParentTable()->getColumn($this->getParameter('descendant_column'))->getPhpName() . "('" . $this->builder->getStubObjectBuilder()->getClassname() . "');
|
||||
return \$parent;
|
||||
} else {
|
||||
return " . $this->builder->getNewStubQueryBuilder($parentTable)->getClassname() . "::create()->findPk(\$this->getPrimaryKey(), \$con);
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addObjectGetSyncParent(&$script)
|
||||
{
|
||||
$parentTable = $this->getParentTable();
|
||||
$pkeys = $parentTable->getPrimaryKey();
|
||||
$cptype = $pkeys[0]->getPhpType();
|
||||
$script .= "
|
||||
/**
|
||||
* Create or Update the parent " . $parentTable->getPhpName() . " object
|
||||
* And return its primary key
|
||||
*
|
||||
* @return " . $cptype . " The primary key of the parent object
|
||||
*/
|
||||
public function getSyncParent(\$con = null)
|
||||
{
|
||||
\$parent = \$this->getParentOrCreate(\$con);";
|
||||
foreach ($parentTable->getColumns() as $column) {
|
||||
if ($column->isPrimaryKey() || $column->getName() == $this->getParameter('descendant_column')) {
|
||||
continue;
|
||||
}
|
||||
$phpName = $column->getPhpName();
|
||||
$script .= "
|
||||
\$parent->set{$phpName}(\$this->get{$phpName}());";
|
||||
}
|
||||
foreach ($parentTable->getForeignKeys() as $fk) {
|
||||
if (isset($fk->isParentChild) && $fk->isParentChild) {
|
||||
continue;
|
||||
}
|
||||
$refPhpName = $this->builder->getFKPhpNameAffix($fk, $plural = false);
|
||||
$script .= "
|
||||
if (\$this->get" . $refPhpName . "() && \$this->get" . $refPhpName . "()->isNew()) {
|
||||
\$parent->set" . $refPhpName . "(\$this->get" . $refPhpName . "());
|
||||
}";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
return \$parent;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gives a model class the ability to remain in database even when the user deletes object
|
||||
* Uses an additional column storing the deletion date
|
||||
* And an additional condition for every read query to only consider rows with no deletion date
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.behavior.concrete_inheritance
|
||||
*/
|
||||
class ConcreteInheritanceParentBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'descendant_column' => 'descendant_class'
|
||||
);
|
||||
|
||||
public function modifyTable()
|
||||
{
|
||||
$table = $this->getTable();
|
||||
if (!$table->containsColumn($this->getParameter('descendant_column'))) {
|
||||
$table->addColumn(array(
|
||||
'name' => $this->getParameter('descendant_column'),
|
||||
'type' => 'VARCHAR',
|
||||
'size' => 100
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getColumnGetter()
|
||||
{
|
||||
return 'get' . $this->getColumnForParameter('descendant_column')->getPhpName();
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$script .= '';
|
||||
$this->addHasChildObject($script);
|
||||
$this->addGetChildObject($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addHasChildObject(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Whether or not this object is the parent of a child object
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChildObject()
|
||||
{
|
||||
return \$this->" . $this->getColumnGetter() . "() !== null;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetChildObject(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Get the child object of this object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getChildObject()
|
||||
{
|
||||
if (!\$this->hasChildObject()) {
|
||||
return null;
|
||||
}
|
||||
\$childObjectClass = \$this->" . $this->getColumnGetter() . "();
|
||||
\$childObject = PropelQuery::from(\$childObjectClass)->findPk(\$this->getPrimaryKey());
|
||||
return \$childObject->hasChildObject() ? \$childObject->getChildObject() : \$childObject;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/NestedSetBehaviorObjectBuilderModifier.php';
|
||||
require_once dirname(__FILE__) . '/NestedSetBehaviorQueryBuilderModifier.php';
|
||||
require_once dirname(__FILE__) . '/NestedSetBehaviorPeerBuilderModifier.php';
|
||||
|
||||
/**
|
||||
* Behavior to adds nested set tree structure columns and abilities
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @package propel.generator.behavior.nestedset
|
||||
*/
|
||||
class NestedSetBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'left_column' => 'tree_left',
|
||||
'right_column' => 'tree_right',
|
||||
'level_column' => 'tree_level',
|
||||
'use_scope' => 'false',
|
||||
'scope_column' => 'tree_scope',
|
||||
'method_proxies' => 'false'
|
||||
);
|
||||
|
||||
protected $objectBuilderModifier, $queryBuilderModifier, $peerBuilderModifier;
|
||||
|
||||
/**
|
||||
* Add the left, right and scope to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('left_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('left_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('right_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('right_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('level_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('level_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
if ($this->getParameter('use_scope') == 'true' &&
|
||||
!$this->getTable()->containsColumn($this->getParameter('scope_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('scope_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectBuilderModifier()
|
||||
{
|
||||
if (is_null($this->objectBuilderModifier))
|
||||
{
|
||||
$this->objectBuilderModifier = new NestedSetBehaviorObjectBuilderModifier($this);
|
||||
}
|
||||
return $this->objectBuilderModifier;
|
||||
}
|
||||
|
||||
public function getQueryBuilderModifier()
|
||||
{
|
||||
if (is_null($this->queryBuilderModifier))
|
||||
{
|
||||
$this->queryBuilderModifier = new NestedSetBehaviorQueryBuilderModifier($this);
|
||||
}
|
||||
return $this->queryBuilderModifier;
|
||||
}
|
||||
|
||||
public function getPeerBuilderModifier()
|
||||
{
|
||||
if (is_null($this->peerBuilderModifier))
|
||||
{
|
||||
$this->peerBuilderModifier = new NestedSetBehaviorPeerBuilderModifier($this);
|
||||
}
|
||||
return $this->peerBuilderModifier;
|
||||
}
|
||||
|
||||
public function useScope()
|
||||
{
|
||||
return $this->getParameter('use_scope') == 'true';
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,555 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to adds nested set tree structure columns and abilities
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @author heltem <heltem@o2php.com>
|
||||
* @package propel.generator.behavior.nestedset
|
||||
*/
|
||||
class NestedSetBehaviorPeerBuilderModifier
|
||||
{
|
||||
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
|
||||
|
||||
public function __construct($behavior)
|
||||
{
|
||||
$this->behavior = $behavior;
|
||||
$this->table = $behavior->getTable();
|
||||
}
|
||||
|
||||
protected function getParameter($key)
|
||||
{
|
||||
return $this->behavior->getParameter($key);
|
||||
}
|
||||
|
||||
protected function getColumn($name)
|
||||
{
|
||||
return $this->behavior->getColumnForParameter($name);
|
||||
}
|
||||
|
||||
protected function getColumnAttribute($name)
|
||||
{
|
||||
return strtolower($this->getColumn($name)->getName());
|
||||
}
|
||||
|
||||
protected function getColumnConstant($name)
|
||||
{
|
||||
return strtoupper($this->getColumn($name)->getName());
|
||||
}
|
||||
|
||||
protected function getColumnPhpName($name)
|
||||
{
|
||||
return $this->getColumn($name)->getPhpName();
|
||||
}
|
||||
|
||||
protected function setBuilder($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
}
|
||||
|
||||
public function staticAttributes($builder)
|
||||
{
|
||||
$tableName = $this->table->getName();
|
||||
|
||||
$script = "
|
||||
/**
|
||||
* Left column for the set
|
||||
*/
|
||||
const LEFT_COL = '" . $tableName . '.' . $this->getColumnConstant('left_column') . "';
|
||||
|
||||
/**
|
||||
* Right column for the set
|
||||
*/
|
||||
const RIGHT_COL = '" . $tableName . '.' . $this->getColumnConstant('right_column') . "';
|
||||
|
||||
/**
|
||||
* Level column for the set
|
||||
*/
|
||||
const LEVEL_COL = '" . $tableName . '.' . $this->getColumnConstant('level_column') . "';
|
||||
";
|
||||
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
/**
|
||||
* Scope column for the set
|
||||
*/
|
||||
const SCOPE_COL = '" . $tableName . '.' . $this->getColumnConstant('scope_column') . "';
|
||||
";
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function staticMethods($builder)
|
||||
{
|
||||
$this->setBuilder($builder);
|
||||
$script = '';
|
||||
|
||||
if ($this->getParameter('use_scope') == 'true')
|
||||
{
|
||||
$this->addRetrieveRoots($script);
|
||||
}
|
||||
$this->addRetrieveRoot($script);
|
||||
$this->addRetrieveTree($script);
|
||||
$this->addIsValid($script);
|
||||
$this->addDeleteTree($script);
|
||||
$this->addShiftRLValues($script);
|
||||
$this->addShiftLevel($script);
|
||||
$this->addUpdateLoadedNodes($script);
|
||||
$this->addMakeRoomForLeaf($script);
|
||||
$this->addFixLevels($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addRetrieveRoots(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Returns the root nodes for the tree
|
||||
*
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
* @return {$this->objectClassname} Propel object for root node
|
||||
*/
|
||||
public static function retrieveRoots(Criteria \$criteria = null, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$criteria === null) {
|
||||
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
\$criteria->add($peerClassname::LEFT_COL, 1, Criteria::EQUAL);
|
||||
|
||||
return $peerClassname::doSelect(\$criteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRetrieveRoot(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Returns the root node for a given scope
|
||||
*";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which root node to return";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
* @return {$this->objectClassname} Propel object for root node
|
||||
*/
|
||||
public static function retrieveRoot(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
\$c = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$c->add($peerClassname::LEFT_COL, 1, Criteria::EQUAL);";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
return $peerClassname::doSelectOne(\$c, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRetrieveTree(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Returns the whole tree node for a given scope
|
||||
*";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which root node to return";
|
||||
}
|
||||
$script .= "
|
||||
* @param Criteria \$criteria Optional Criteria to filter the query
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
* @return {$this->objectClassname} Propel object for root node
|
||||
*/
|
||||
public static function retrieveTree(" . ($useScope ? "\$scope = null, " : "") . "Criteria \$criteria = null, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$criteria === null) {
|
||||
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
\$criteria->addAscendingOrderByColumn($peerClassname::LEFT_COL);";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
\$criteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
return $peerClassname::doSelect(\$criteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addIsValid(&$script)
|
||||
{
|
||||
$objectClassname = $this->objectClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Tests if node is valid
|
||||
*
|
||||
* @param $objectClassname \$node Propel object for src node
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValid($objectClassname \$node = null)
|
||||
{
|
||||
if (is_object(\$node) && \$node->getRightValue() > \$node->getLeftValue()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addDeleteTree(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Delete an entire tree
|
||||
* ";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which tree to delete";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*
|
||||
* @return int The number of deleted nodes
|
||||
*/
|
||||
public static function deleteTree(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
\$c = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);
|
||||
return $peerClassname::doDelete(\$c, \$con);";
|
||||
} else {
|
||||
$script .= "
|
||||
return $peerClassname::doDeleteAll(\$con);";
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addShiftRLValues(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Adds \$delta to all L and R values that are >= \$first and <= \$last.
|
||||
* '\$delta' can also be negative.
|
||||
*
|
||||
* @param int \$delta Value to be shifted by, can be negative
|
||||
* @param int \$first First node to be shifted
|
||||
* @param int \$last Last node to be shifted (optional)";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to use for the shift";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function shiftRLValues(\$delta, \$first, \$last = null" . ($useScope ? ", \$scope = null" : ""). ", PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
|
||||
}
|
||||
|
||||
// Shift left column values
|
||||
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::LEFT_COL, \$first, Criteria::GREATER_EQUAL);
|
||||
if (null !== \$last) {
|
||||
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::LEFT_COL, \$last, Criteria::LESS_EQUAL));
|
||||
}
|
||||
\$whereCriteria->add(\$criterion);";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$valuesCriteria->add($peerClassname::LEFT_COL, array('raw' => $peerClassname::LEFT_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
|
||||
|
||||
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
|
||||
|
||||
// Shift right column values
|
||||
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::RIGHT_COL, \$first, Criteria::GREATER_EQUAL);
|
||||
if (null !== \$last) {
|
||||
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::RIGHT_COL, \$last, Criteria::LESS_EQUAL));
|
||||
}
|
||||
\$whereCriteria->add(\$criterion);";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$valuesCriteria->add($peerClassname::RIGHT_COL, array('raw' => $peerClassname::RIGHT_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
|
||||
|
||||
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addShiftLevel(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Adds \$delta to level for nodes having left value >= \$first and right value <= \$last.
|
||||
* '\$delta' can also be negative.
|
||||
*
|
||||
* @param int \$delta Value to be shifted by, can be negative
|
||||
* @param int \$first First node to be shifted
|
||||
* @param int \$last Last node to be shifted";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to use for the shift";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function shiftLevel(\$delta, \$first, \$last" . ($useScope ? ", \$scope = null" : ""). ", PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
|
||||
}
|
||||
|
||||
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$whereCriteria->add($peerClassname::LEFT_COL, \$first, Criteria::GREATER_EQUAL);
|
||||
\$whereCriteria->add($peerClassname::RIGHT_COL, \$last, Criteria::LESS_EQUAL);";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$valuesCriteria->add($peerClassname::LEVEL_COL, array('raw' => $peerClassname::LEVEL_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
|
||||
|
||||
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addUpdateLoadedNodes(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Reload all already loaded nodes to sync them with updated db
|
||||
*
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function updateLoadedNodes(PropelPDO \$con = null)
|
||||
{
|
||||
if (Propel::isInstancePoolingEnabled()) {
|
||||
\$keys = array();
|
||||
foreach ($peerClassname::\$instances as \$obj) {
|
||||
\$keys[] = \$obj->getPrimaryKey();
|
||||
}
|
||||
|
||||
if (!empty(\$keys)) {
|
||||
// We don't need to alter the object instance pool; we're just modifying these ones
|
||||
// already in the pool.
|
||||
\$criteria = new Criteria($peerClassname::DATABASE_NAME);";
|
||||
if (count($this->table->getPrimaryKey()) === 1) {
|
||||
$pkey = $this->table->getPrimaryKey();
|
||||
$col = array_shift($pkey);
|
||||
$script .= "
|
||||
\$criteria->add(".$this->builder->getColumnConstant($col).", \$keys, Criteria::IN);
|
||||
";
|
||||
} else {
|
||||
$fields = array();
|
||||
foreach ($this->table->getPrimaryKey() as $k => $col) {
|
||||
$fields[] = $this->builder->getColumnConstant($col);
|
||||
};
|
||||
$script .= "
|
||||
|
||||
// Loop on each instances in pool
|
||||
foreach (\$keys as \$values) {
|
||||
// Create initial Criterion
|
||||
\$cton = \$criteria->getNewCriterion(" . $fields[0] . ", \$values[0]);";
|
||||
unset($fields[0]);
|
||||
foreach ($fields as $k => $col) {
|
||||
$script .= "
|
||||
|
||||
// Create next criterion
|
||||
\$nextcton = \$criteria->getNewCriterion(" . $col . ", \$values[$k]);
|
||||
// And merge it with the first
|
||||
\$cton->addAnd(\$nextcton);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
// Add final Criterion to Criteria
|
||||
\$criteria->addOr(\$cton);
|
||||
}";
|
||||
}
|
||||
|
||||
$script .= "
|
||||
\$stmt = $peerClassname::doSelectStmt(\$criteria, \$con);
|
||||
while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
|
||||
\$key = $peerClassname::getPrimaryKeyHashFromRow(\$row, 0);
|
||||
if (null !== (\$object = $peerClassname::getInstanceFromPool(\$key))) {";
|
||||
$n = 0;
|
||||
foreach ($this->table->getColumns() as $col) {
|
||||
if ($col->getPhpName() == $this->getColumnPhpName('left_column')) {
|
||||
$script .= "
|
||||
\$object->setLeftValue(\$row[$n]);";
|
||||
} else if ($col->getPhpName() == $this->getColumnPhpName('right_column')) {
|
||||
$script .= "
|
||||
\$object->setRightValue(\$row[$n]);";
|
||||
} else if ($col->getPhpName() == $this->getColumnPhpName('level_column')) {
|
||||
$script .= "
|
||||
\$object->setLevel(\$row[$n]);
|
||||
\$object->clearNestedSetChildren();";
|
||||
}
|
||||
$n++;
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
}
|
||||
\$stmt->closeCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMakeRoomForLeaf(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Update the tree to allow insertion of a leaf at the specified position
|
||||
*
|
||||
* @param int \$left left column value";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
* @param integer \$scope scope column value";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function makeRoomForLeaf(\$left" . ($useScope ? ", \$scope" : ""). ", PropelPDO \$con = null)
|
||||
{
|
||||
// Update database nodes
|
||||
$peerClassname::shiftRLValues(2, \$left, null" . ($useScope ? ", \$scope" : "") . ", \$con);
|
||||
|
||||
// Update all loaded nodes
|
||||
$peerClassname::updateLoadedNodes(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFixLevels(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Update the tree to allow insertion of a leaf at the specified position
|
||||
*";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
* @param integer \$scope scope column value";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function fixLevels(" . ($useScope ? "\$scope, " : ""). "PropelPDO \$con = null)
|
||||
{
|
||||
\$c = new Criteria();";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
\$c->addAscendingOrderByColumn($peerClassname::LEFT_COL);
|
||||
\$stmt = $peerClassname::doSelectStmt(\$c, \$con);
|
||||
";
|
||||
if (!$this->table->getChildrenColumn()) {
|
||||
$script .= "
|
||||
// set the class once to avoid overhead in the loop
|
||||
\$cls = $peerClassname::getOMClass(false);";
|
||||
}
|
||||
|
||||
$script .= "
|
||||
\$level = null;
|
||||
// iterate over the statement
|
||||
while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
|
||||
|
||||
// hydrate object
|
||||
\$key = $peerClassname::getPrimaryKeyHashFromRow(\$row, 0);
|
||||
if (null === (\$obj = $peerClassname::getInstanceFromPool(\$key))) {";
|
||||
if ($this->table->getChildrenColumn()) {
|
||||
$script .= "
|
||||
// class must be set each time from the record row
|
||||
\$cls = $peerClassname::getOMClass(\$row, 0);
|
||||
\$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
|
||||
" . $this->builder->buildObjectInstanceCreationCode('$obj', '$cls') . "
|
||||
\$obj->hydrate(\$row);
|
||||
$peerClassname::addInstanceToPool(\$obj, \$key);";
|
||||
} else {
|
||||
$script .= "
|
||||
" . $this->builder->buildObjectInstanceCreationCode('$obj', '$cls') . "
|
||||
\$obj->hydrate(\$row);
|
||||
$peerClassname::addInstanceToPool(\$obj, \$key);";
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
|
||||
// compute level
|
||||
// Algorithm shamelessly stolen from sfPropelActAsNestedSetBehaviorPlugin
|
||||
// Probably authored by Tristan Rivoallan
|
||||
if (\$level === null) {
|
||||
\$level = 0;
|
||||
\$i = 0;
|
||||
\$prev = array(\$obj->getRightValue());
|
||||
} else {
|
||||
while (\$obj->getRightValue() > \$prev[\$i]) {
|
||||
\$i--;
|
||||
}
|
||||
\$level = ++\$i;
|
||||
\$prev[\$i] = \$obj->getRightValue();
|
||||
}
|
||||
|
||||
// update level in node if necessary
|
||||
if (\$obj->getLevel() !== \$level) {
|
||||
\$obj->setLevel(\$level);
|
||||
\$obj->save(\$con);
|
||||
}
|
||||
}
|
||||
\$stmt->closeCursor();
|
||||
}
|
||||
";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to adds nested set tree structure columns and abilities
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @package propel.generator.behavior.nestedset
|
||||
*/
|
||||
class NestedSetBehaviorQueryBuilderModifier
|
||||
{
|
||||
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
|
||||
|
||||
public function __construct($behavior)
|
||||
{
|
||||
$this->behavior = $behavior;
|
||||
$this->table = $behavior->getTable();
|
||||
}
|
||||
|
||||
protected function getParameter($key)
|
||||
{
|
||||
return $this->behavior->getParameter($key);
|
||||
}
|
||||
|
||||
protected function getColumn($name)
|
||||
{
|
||||
return $this->behavior->getColumnForParameter($name);
|
||||
}
|
||||
|
||||
protected function setBuilder($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
|
||||
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$this->setBuilder($builder);
|
||||
$script = '';
|
||||
|
||||
// select filters
|
||||
if ($this->behavior->useScope()) {
|
||||
$this->addTreeRoots($script);
|
||||
$this->addInTree($script);
|
||||
}
|
||||
$this->addDescendantsOf($script);
|
||||
$this->addBranchOf($script);
|
||||
$this->addChildrenOf($script);
|
||||
$this->addSiblingsOf($script);
|
||||
$this->addAncestorsOf($script);
|
||||
$this->addRootsOf($script);
|
||||
// select orders
|
||||
$this->addOrderByBranch($script);
|
||||
$this->addOrderByLevel($script);
|
||||
// select termination methods
|
||||
$this->addFindRoot($script);
|
||||
$this->addFindTree($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addTreeRoots(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to root objects
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function treeRoots()
|
||||
{
|
||||
return \$this->addUsingAlias({$this->peerClassname}::LEFT_COL, 1, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addInTree(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Returns the objects in a certain tree, from the tree scope
|
||||
*
|
||||
* @param int \$scope Scope to determine which objects node to return
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function inTree(\$scope = null)
|
||||
{
|
||||
return \$this->addUsingAlias({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addDescendantsOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to descendants of an object
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for descendant search
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function descendantsOf($objectName)
|
||||
{
|
||||
return \$this";
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
->inTree({$objectName}->getScopeValue())";
|
||||
}
|
||||
$script .= "
|
||||
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::GREATER_THAN)
|
||||
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::LESS_THAN);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addBranchOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to the branch of an object.
|
||||
* Same as descendantsOf(), except that it includes the object passed as parameter in the result
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for branch search
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function branchOf($objectName)
|
||||
{
|
||||
return \$this";
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
->inTree({$objectName}->getScopeValue())";
|
||||
}
|
||||
$script .= "
|
||||
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::GREATER_EQUAL)
|
||||
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::LESS_EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addChildrenOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to children of an object
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for child search
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function childrenOf($objectName)
|
||||
{
|
||||
return \$this
|
||||
->descendantsOf($objectName)
|
||||
->addUsingAlias({$this->peerClassname}::LEVEL_COL, {$objectName}->getLevel() + 1, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addSiblingsOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to siblings of an object.
|
||||
* The result does not include the object passed as parameter.
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for sibling search
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function siblingsOf($objectName, PropelPDO \$con = null)
|
||||
{
|
||||
if ({$objectName}->isRoot()) {
|
||||
return \$this->
|
||||
add({$this->peerClassname}::LEVEL_COL, '1<>1', Criteria::CUSTOM);
|
||||
} else {
|
||||
return \$this
|
||||
->childrenOf({$objectName}->getParent(\$con))
|
||||
->prune($objectName);
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addAncestorsOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to ancestors of an object
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for ancestors search
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function ancestorsOf($objectName)
|
||||
{
|
||||
return \$this";
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
->inTree({$objectName}->getScopeValue())";
|
||||
}
|
||||
$script .= "
|
||||
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::LESS_THAN)
|
||||
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::GREATER_THAN);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRootsOf(&$script)
|
||||
{
|
||||
$objectName = '$' . $this->table->getStudlyPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query to restrict the result to roots of an object.
|
||||
* Same as ancestorsOf(), except that it includes the object passed as parameter in the result
|
||||
*
|
||||
* @param {$this->objectClassname} $objectName The object to use for roots search
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function rootsOf($objectName)
|
||||
{
|
||||
return \$this";
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
->inTree({$objectName}->getScopeValue())";
|
||||
}
|
||||
$script .= "
|
||||
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::LESS_EQUAL)
|
||||
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::GREATER_EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addOrderByBranch(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Order the result by branch, i.e. natural tree order
|
||||
*
|
||||
* @param bool \$reverse if true, reverses the order
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function orderByBranch(\$reverse = false)
|
||||
{
|
||||
if (\$reverse) {
|
||||
return \$this
|
||||
->addDescendingOrderByColumn({$this->peerClassname}::LEFT_COL);
|
||||
} else {
|
||||
return \$this
|
||||
->addAscendingOrderByColumn({$this->peerClassname}::LEFT_COL);
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addOrderByLevel(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Order the result by level, the closer to the root first
|
||||
*
|
||||
* @param bool \$reverse if true, reverses the order
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function orderByLevel(\$reverse = false)
|
||||
{
|
||||
if (\$reverse) {
|
||||
return \$this
|
||||
->addAscendingOrderByColumn({$this->peerClassname}::RIGHT_COL);
|
||||
} else {
|
||||
return \$this
|
||||
->addDescendingOrderByColumn({$this->peerClassname}::RIGHT_COL);
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFindRoot(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Returns " . ($useScope ? 'a' : 'the') ." root node for the tree
|
||||
*";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which root node to return";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*
|
||||
* @return {$this->objectClassname} The tree root object
|
||||
*/
|
||||
public function findRoot(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
|
||||
{
|
||||
return \$this
|
||||
->addUsingAlias({$this->peerClassname}::LEFT_COL, 1, Criteria::EQUAL)";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
->inTree(\$scope)";
|
||||
}
|
||||
$script .= "
|
||||
->findOne(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFindTree(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Returns " . ($useScope ? 'a' : 'the') ." tree of objects
|
||||
*";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which tree node to return";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*
|
||||
* @return mixed the list of results, formatted by the current formatter
|
||||
*/
|
||||
public function findTree(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
|
||||
{
|
||||
return \$this";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
->inTree(\$scope)";
|
||||
}
|
||||
$script .= "
|
||||
->orderByBranch()
|
||||
->find(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Speeds up queries on a model by caching the query
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @version $Revision: 1746 $
|
||||
* @package propel.generator.behavior.cacheable
|
||||
*/
|
||||
class QueryCacheBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'backend' => 'apc',
|
||||
'lifetime' => 3600,
|
||||
);
|
||||
|
||||
public function queryAttributes($builder)
|
||||
{
|
||||
$script = "protected \$queryKey = '';
|
||||
";
|
||||
switch ($this->getParameter('backend')) {
|
||||
case 'backend':
|
||||
$script .= "protected static \$cacheBackend = array();
|
||||
";
|
||||
break;
|
||||
case 'apc':
|
||||
break;
|
||||
case 'custom':
|
||||
default:
|
||||
$script .= "protected static \$cacheBackend;
|
||||
";
|
||||
break;
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
$script = '';
|
||||
$this->addSetQueryKey($script);
|
||||
$this->addGetQueryKey($script);
|
||||
$this->addCacheContains($script);
|
||||
$this->addCacheFetch($script);
|
||||
$this->addCacheStore($script);
|
||||
$this->addGetSelectStatement($script);
|
||||
$this->addGetCountStatement($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addSetQueryKey(&$script)
|
||||
{
|
||||
$script .= "
|
||||
public function setQueryKey(\$key)
|
||||
{
|
||||
\$this->queryKey = \$key;
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetQueryKey(&$script)
|
||||
{
|
||||
$script .= "
|
||||
public function getQueryKey()
|
||||
{
|
||||
return \$this->queryKey;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCacheContains(&$script)
|
||||
{
|
||||
$script .= "
|
||||
public function cacheContains(\$key)
|
||||
{";
|
||||
switch ($this->getParameter('backend')) {
|
||||
case 'apc':
|
||||
$script .= "
|
||||
return apc_fetch(\$key);";
|
||||
break;
|
||||
case 'array':
|
||||
$script .= "
|
||||
return isset(self::\$cacheBackend[\$key]);";
|
||||
break;
|
||||
case 'custom':
|
||||
default:
|
||||
$script .= "
|
||||
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
|
||||
break;
|
||||
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCacheStore(&$script)
|
||||
{
|
||||
$script .= "
|
||||
public function cacheStore(\$key, \$value, \$lifetime = " .$this->getParameter('lifetime') . ")
|
||||
{";
|
||||
switch ($this->getParameter('backend')) {
|
||||
case 'apc':
|
||||
$script .= "
|
||||
apc_store(\$key, \$value, \$lifetime);";
|
||||
break;
|
||||
case 'array':
|
||||
$script .= "
|
||||
self::\$cacheBackend[\$key] = \$value;";
|
||||
break;
|
||||
case 'custom':
|
||||
default:
|
||||
$script .= "
|
||||
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
|
||||
break;
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCacheFetch(&$script)
|
||||
{
|
||||
$script .= "
|
||||
public function cacheFetch(\$key)
|
||||
{";
|
||||
switch ($this->getParameter('backend')) {
|
||||
case 'apc':
|
||||
$script .= "
|
||||
return apc_fetch(\$key);";
|
||||
break;
|
||||
case 'array':
|
||||
$script .= "
|
||||
return isset(self::\$cacheBackend[\$key]) ? self::\$cacheBackend[\$key] : null;";
|
||||
break;
|
||||
case 'custom':
|
||||
default:
|
||||
$script .= "
|
||||
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
|
||||
break;
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetSelectStatement(&$script)
|
||||
{
|
||||
$script .= "
|
||||
protected function getSelectStatement(\$con = null)
|
||||
{
|
||||
\$dbMap = Propel::getDatabaseMap(" . $this->peerClassname ."::DATABASE_NAME);
|
||||
\$db = Propel::getDB(" . $this->peerClassname ."::DATABASE_NAME);
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection(" . $this->peerClassname ."::DATABASE_NAME, Propel::CONNECTION_READ);
|
||||
}
|
||||
|
||||
if (!\$this->hasSelectClause()) {
|
||||
\$this->addSelfSelectColumns();
|
||||
}
|
||||
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$this->basePreSelect(\$con);
|
||||
\$key = \$this->getQueryKey();
|
||||
if (\$key && \$this->cacheContains(\$key)) {
|
||||
\$params = \$this->getParams();
|
||||
\$sql = \$this->cacheFetch(\$key);
|
||||
} else {
|
||||
\$params = array();
|
||||
\$sql = BasePeer::createSelectSql(\$this, \$params);
|
||||
if (\$key) {
|
||||
\$this->cacheStore(\$key, \$sql);
|
||||
}
|
||||
}
|
||||
\$stmt = \$con->prepare(\$sql);
|
||||
BasePeer::populateStmtValues(\$stmt, \$params, \$dbMap, \$db);
|
||||
\$stmt->execute();
|
||||
\$con->commit();
|
||||
} catch (PropelException \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
|
||||
return \$stmt;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetCountStatement(&$script)
|
||||
{
|
||||
$script .= "
|
||||
protected function getCountStatement(\$con = null)
|
||||
{
|
||||
\$dbMap = Propel::getDatabaseMap(\$this->getDbName());
|
||||
\$db = Propel::getDB(\$this->getDbName());
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection(\$this->getDbName(), Propel::CONNECTION_READ);
|
||||
}
|
||||
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$this->basePreSelect(\$con);
|
||||
\$key = \$this->getQueryKey();
|
||||
if (\$key && \$this->cacheContains(\$key)) {
|
||||
\$params = \$this->getParams();
|
||||
\$sql = \$this->cacheFetch(\$key);
|
||||
} else {
|
||||
if (!\$this->hasSelectClause() && !\$this->getPrimaryCriteria()) {
|
||||
\$this->addSelfSelectColumns();
|
||||
}
|
||||
\$params = array();
|
||||
\$needsComplexCount = \$this->getGroupByColumns()
|
||||
|| \$this->getOffset()
|
||||
|| \$this->getLimit()
|
||||
|| \$this->getHaving()
|
||||
|| in_array(Criteria::DISTINCT, \$this->getSelectModifiers());
|
||||
if (\$needsComplexCount) {
|
||||
if (BasePeer::needsSelectAliases(\$this)) {
|
||||
if (\$this->getHaving()) {
|
||||
throw new PropelException('Propel cannot create a COUNT query when using HAVING and duplicate column names in the SELECT part');
|
||||
}
|
||||
BasePeer::turnSelectColumnsToAliases(\$this);
|
||||
}
|
||||
\$selectSql = BasePeer::createSelectSql(\$this, \$params);
|
||||
\$sql = 'SELECT COUNT(*) FROM (' . \$selectSql . ') propelmatch4cnt';
|
||||
} else {
|
||||
// Replace SELECT columns with COUNT(*)
|
||||
\$this->clearSelectColumns()->addSelectColumn('COUNT(*)');
|
||||
\$sql = BasePeer::createSelectSql(\$this, \$params);
|
||||
}
|
||||
if (\$key) {
|
||||
\$this->cacheStore(\$key, \$sql);
|
||||
}
|
||||
}
|
||||
\$stmt = \$con->prepare(\$sql);
|
||||
BasePeer::populateStmtValues(\$stmt, \$params, \$dbMap, \$db);
|
||||
\$stmt->execute();
|
||||
\$con->commit();
|
||||
} catch (PropelException \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
|
||||
return \$stmt;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a slug column
|
||||
*
|
||||
* @author Francois Zaninotto
|
||||
* @author Massimiliano Arione
|
||||
* @version $Revision: 1629 $
|
||||
* @package propel.generator.behavior.sluggable
|
||||
*/
|
||||
class SluggableBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'slug_column' => 'slug',
|
||||
'slug_pattern' => '',
|
||||
'replace_pattern' => '/\W+/', // Tip: use '/[^\\pL\\d]+/u' instead if you're in PHP5.3
|
||||
'replacement' => '-',
|
||||
'separator' => '-',
|
||||
'permanent' => 'false'
|
||||
);
|
||||
|
||||
/**
|
||||
* Add the slug_column to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
if(!$this->getTable()->containsColumn($this->getParameter('slug_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('slug_column'),
|
||||
'type' => 'VARCHAR',
|
||||
'size' => 255
|
||||
));
|
||||
// add a unique to column
|
||||
$unique = new Unique($this->getColumnForParameter('slug_column'));
|
||||
$unique->setName($this->getTable()->getName() . '_slug');
|
||||
$unique->addColumn($this->getTable()->getColumn($this->getParameter('slug_column')));
|
||||
$this->getTable()->addUnique($unique);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the getter of the column of the behavior
|
||||
*
|
||||
* @return string The related getter, e.g. 'getSlug'
|
||||
*/
|
||||
protected function getColumnGetter()
|
||||
{
|
||||
return 'get' . $this->getColumnForParameter('slug_column')->getPhpName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the setter of the column of the behavior
|
||||
*
|
||||
* @return string The related setter, e.g. 'setSlug'
|
||||
*/
|
||||
protected function getColumnSetter()
|
||||
{
|
||||
return 'set' . $this->getColumnForParameter('slug_column')->getPhpName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add code in ObjectBuilder::preSave
|
||||
*
|
||||
* @return string The code to put at the hook
|
||||
*/
|
||||
public function preSave($builder)
|
||||
{
|
||||
$const = $builder->getColumnConstant($this->getColumnForParameter('slug_column'), $this->getTable()->getPhpName() . 'Peer');
|
||||
$script = "
|
||||
if (\$this->isColumnModified($const) && \$this->{$this->getColumnGetter()}()) {
|
||||
\$this->{$this->getColumnSetter()}(\$this->makeSlugUnique(\$this->{$this->getColumnGetter()}()));";
|
||||
if ($this->getParameter('permanent') == 'true') {
|
||||
$script .= "
|
||||
} elseif (!\$this->{$this->getColumnGetter()}()) {
|
||||
\$this->{$this->getColumnSetter()}(\$this->createSlug());
|
||||
}";
|
||||
} else {
|
||||
$script .= "
|
||||
} else {
|
||||
\$this->{$this->getColumnSetter()}(\$this->createSlug());
|
||||
}";
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$script = '';
|
||||
if ($this->getParameter('slug_column') != 'slug') {
|
||||
$this->addSlugSetter($script);
|
||||
$this->addSlugGetter($script);
|
||||
}
|
||||
$this->addCreateSlug($script);
|
||||
$this->addCreateRawSlug($script);
|
||||
$this->addCleanupSlugPart($script);
|
||||
$this->addLimitSlugSize($script);
|
||||
$this->addMakeSlugUnique($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addSlugSetter(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Wrap the setter for slug value
|
||||
*
|
||||
* @param string
|
||||
* @return " . $this->getTable()->getPhpName() . "
|
||||
*/
|
||||
public function setSlug(\$v)
|
||||
{
|
||||
return \$this->" . $this->getColumnSetter() . "(\$v);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addSlugGetter(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Wrap the getter for slug value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSlug()
|
||||
{
|
||||
return \$this->" . $this->getColumnGetter() . "();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCreateSlug(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Create a unique slug based on the object
|
||||
*
|
||||
* @return string The object slug
|
||||
*/
|
||||
protected function createSlug()
|
||||
{
|
||||
\$slug = \$this->createRawSlug();
|
||||
\$slug = \$this->limitSlugSize(\$slug);
|
||||
\$slug = \$this->makeSlugUnique(\$slug);
|
||||
|
||||
return \$slug;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCreateRawSlug(&$script)
|
||||
{
|
||||
$pattern = $this->getParameter('slug_pattern');
|
||||
$script .= "
|
||||
/**
|
||||
* Create the slug from the appropriate columns
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function createRawSlug()
|
||||
{
|
||||
";
|
||||
if ($pattern) {
|
||||
$script .= "return '" . str_replace(array('{', '}'), array('\' . $this->cleanupSlugPart($this->get', '()) . \''), $pattern). "';";
|
||||
} else {
|
||||
$script .= "return \$this->cleanupSlugPart(\$this->__toString());";
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
return $script;
|
||||
}
|
||||
|
||||
public function addCleanupSlugPart(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Cleanup a string to make a slug of it
|
||||
* Removes special characters, replaces blanks with a separator, and trim it
|
||||
*
|
||||
* @param string \$text the text to slugify
|
||||
* @param string \$separator the separator used by slug
|
||||
* @return string the slugified text
|
||||
*/
|
||||
protected static function cleanupSlugPart(\$slug, \$replacement = '" . $this->getParameter('replacement') . "')
|
||||
{
|
||||
// transliterate
|
||||
if (function_exists('iconv')) {
|
||||
\$slug = iconv('utf-8', 'us-ascii//TRANSLIT', \$slug);
|
||||
}
|
||||
|
||||
// lowercase
|
||||
if (function_exists('mb_strtolower')) {
|
||||
\$slug = mb_strtolower(\$slug);
|
||||
} else {
|
||||
\$slug = strtolower(\$slug);
|
||||
}
|
||||
|
||||
// remove accents resulting from OSX's iconv
|
||||
\$slug = str_replace(array('\'', '`', '^'), '', \$slug);
|
||||
|
||||
// replace non letter or digits with separator
|
||||
\$slug = preg_replace('" . $this->getParameter('replace_pattern') . "', \$replacement, \$slug);
|
||||
|
||||
// trim
|
||||
\$slug = trim(\$slug, \$replacement);
|
||||
|
||||
if (empty(\$slug)) {
|
||||
return 'n-a';
|
||||
}
|
||||
|
||||
return \$slug;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addLimitSlugSize(&$script)
|
||||
{
|
||||
$size = $this->getColumnForParameter('slug_column')->getSize();
|
||||
$script .= "
|
||||
|
||||
/**
|
||||
* Make sure the slug is short enough to accomodate the column size
|
||||
*
|
||||
* @param string \$slug the slug to check
|
||||
*
|
||||
* @return string the truncated slug
|
||||
*/
|
||||
protected static function limitSlugSize(\$slug, \$incrementReservedSpace = 3)
|
||||
{
|
||||
// check length, as suffix could put it over maximum
|
||||
if (strlen(\$slug) > ($size - \$incrementReservedSpace)) {
|
||||
\$slug = substr(\$slug, 0, $size - \$incrementReservedSpace);
|
||||
}
|
||||
return \$slug;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function addMakeSlugUnique(&$script)
|
||||
{
|
||||
$script .= "
|
||||
|
||||
/**
|
||||
* Get the slug, ensuring its uniqueness
|
||||
*
|
||||
* @param string \$slug the slug to check
|
||||
* @param string \$separator the separator used by slug
|
||||
* @return string the unique slug
|
||||
*/
|
||||
protected function makeSlugUnique(\$slug, \$separator = '" . $this->getParameter('separator') ."', \$increment = 0)
|
||||
{
|
||||
\$slug2 = empty(\$increment) ? \$slug : \$slug . \$separator . \$increment;
|
||||
\$slugAlreadyExists = " . $this->builder->getStubQueryBuilder()->getClassname() . "::create()
|
||||
->filterBySlug(\$slug2)
|
||||
->prune(\$this)";
|
||||
// watch out: some of the columns may be hidden by the soft_delete behavior
|
||||
if ($this->table->hasBehavior('soft_delete')) {
|
||||
$script .= "
|
||||
->includeDeleted()";
|
||||
}
|
||||
$script .= "
|
||||
->count();
|
||||
if (\$slugAlreadyExists) {
|
||||
return \$this->makeSlugUnique(\$slug, \$separator, ++\$increment);
|
||||
} else {
|
||||
return \$slug2;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$script = '';
|
||||
if ($this->getParameter('slug_column') != 'slug') {
|
||||
$this->addFilterBySlug($script);
|
||||
}
|
||||
$this->addFindOneBySlug($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addFilterBySlug(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query on the slug column
|
||||
*
|
||||
* @param string \$slug The value to use as filter.
|
||||
*
|
||||
* @return " . $this->builder->getStubQueryBuilder()->getClassname() . " The current query, for fluid interface
|
||||
*/
|
||||
public function filterBySlug(\$slug)
|
||||
{
|
||||
return \$this->addUsingAlias(" . $this->builder->getColumnConstant($this->getColumnForParameter('slug_column')) . ", \$slug, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFindOneBySlug(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Find one object based on its slug
|
||||
*
|
||||
* @param string \$slug The value to use as filter.
|
||||
* @param PropelPDO \$con The optional connection object
|
||||
*
|
||||
* @return " . $this->builder->getStubObjectBuilder()->getClassname() . " the result, formatted by the current formatter
|
||||
*/
|
||||
public function findOneBySlug(\$slug, \$con = null)
|
||||
{
|
||||
return \$this->filterBySlug(\$slug)->findOne(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/SortableBehaviorObjectBuilderModifier.php';
|
||||
require_once dirname(__FILE__) . '/SortableBehaviorQueryBuilderModifier.php';
|
||||
require_once dirname(__FILE__) . '/SortableBehaviorPeerBuilderModifier.php';
|
||||
|
||||
/**
|
||||
* Gives a model class the ability to be ordered
|
||||
* Uses one additional column storing the rank
|
||||
*
|
||||
* @author Massimiliano Arione
|
||||
* @version $Revision: 1612 $
|
||||
* @package propel.generator.behavior.sortable
|
||||
*/
|
||||
class SortableBehavior extends Behavior
|
||||
{
|
||||
// default parameters value
|
||||
protected $parameters = array(
|
||||
'rank_column' => 'sortable_rank',
|
||||
'use_scope' => 'false',
|
||||
'scope_column' => 'sortable_scope',
|
||||
);
|
||||
|
||||
protected $objectBuilderModifier, $queryBuilderModifier, $peerBuilderModifier;
|
||||
|
||||
/**
|
||||
* Add the rank_column to the current table
|
||||
*/
|
||||
public function modifyTable()
|
||||
{
|
||||
if (!$this->getTable()->containsColumn($this->getParameter('rank_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('rank_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
if ($this->getParameter('use_scope') == 'true' &&
|
||||
!$this->getTable()->containsColumn($this->getParameter('scope_column'))) {
|
||||
$this->getTable()->addColumn(array(
|
||||
'name' => $this->getParameter('scope_column'),
|
||||
'type' => 'INTEGER'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectBuilderModifier()
|
||||
{
|
||||
if (is_null($this->objectBuilderModifier)) {
|
||||
$this->objectBuilderModifier = new SortableBehaviorObjectBuilderModifier($this);
|
||||
}
|
||||
return $this->objectBuilderModifier;
|
||||
}
|
||||
|
||||
public function getQueryBuilderModifier()
|
||||
{
|
||||
if (is_null($this->queryBuilderModifier)) {
|
||||
$this->queryBuilderModifier = new SortableBehaviorQueryBuilderModifier($this);
|
||||
}
|
||||
return $this->queryBuilderModifier;
|
||||
}
|
||||
|
||||
public function getPeerBuilderModifier()
|
||||
{
|
||||
if (is_null($this->peerBuilderModifier)) {
|
||||
$this->peerBuilderModifier = new SortableBehaviorPeerBuilderModifier($this);
|
||||
}
|
||||
return $this->peerBuilderModifier;
|
||||
}
|
||||
|
||||
public function useScope()
|
||||
{
|
||||
return $this->getParameter('use_scope') == 'true';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,636 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to add sortable columns and abilities
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @author heltem <heltem@o2php.com>
|
||||
* @package propel.generator.behavior.sortable
|
||||
*/
|
||||
class SortableBehaviorObjectBuilderModifier
|
||||
{
|
||||
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
|
||||
|
||||
public function __construct($behavior)
|
||||
{
|
||||
$this->behavior = $behavior;
|
||||
$this->table = $behavior->getTable();
|
||||
}
|
||||
|
||||
protected function getParameter($key)
|
||||
{
|
||||
return $this->behavior->getParameter($key);
|
||||
}
|
||||
|
||||
protected function getColumnAttribute($name)
|
||||
{
|
||||
return strtolower($this->behavior->getColumnForParameter($name)->getName());
|
||||
}
|
||||
|
||||
protected function getColumnPhpName($name)
|
||||
{
|
||||
return $this->behavior->getColumnForParameter($name)->getPhpName();
|
||||
}
|
||||
|
||||
protected function setBuilder($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
|
||||
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the getter of the column of the behavior
|
||||
*
|
||||
* @return string The related getter, e.g. 'getRank'
|
||||
*/
|
||||
protected function getColumnGetter($columnName = 'rank_column')
|
||||
{
|
||||
return 'get' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the setter of the column of the behavior
|
||||
*
|
||||
* @return string The related setter, e.g. 'setRank'
|
||||
*/
|
||||
protected function getColumnSetter($columnName = 'rank_column')
|
||||
{
|
||||
return 'set' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
|
||||
}
|
||||
|
||||
public function preSave($builder)
|
||||
{
|
||||
return "\$this->processSortableQueries(\$con);";
|
||||
}
|
||||
|
||||
public function preInsert($builder)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$this->setBuilder($builder);
|
||||
return "if (!\$this->isColumnModified({$this->peerClassname}::RANK_COL)) {
|
||||
\$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
public function preDelete($builder)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$this->setBuilder($builder);
|
||||
return "
|
||||
{$this->peerClassname}::shiftRank(-1, \$this->{$this->getColumnGetter()}() + 1, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
|
||||
{$this->peerClassname}::clearInstancePool();
|
||||
";
|
||||
}
|
||||
|
||||
public function objectAttributes($builder)
|
||||
{
|
||||
return "
|
||||
/**
|
||||
* Queries to be executed in the save transaction
|
||||
* @var array
|
||||
*/
|
||||
protected \$sortableQueries = array();
|
||||
";
|
||||
}
|
||||
|
||||
public function objectMethods($builder)
|
||||
{
|
||||
$this->setBuilder($builder);
|
||||
$script = '';
|
||||
if ($this->getParameter('rank_column') != 'rank') {
|
||||
$this->addRankAccessors($script);
|
||||
}
|
||||
if ($this->behavior->useScope() &&
|
||||
$this->getParameter('scope_column') != 'scope_value') {
|
||||
$this->addScopeAccessors($script);
|
||||
}
|
||||
$this->addIsFirst($script);
|
||||
$this->addIsLast($script);
|
||||
$this->addGetNext($script);
|
||||
$this->addGetPrevious($script);
|
||||
$this->addInsertAtRank($script);
|
||||
$this->addInsertAtBottom($script);
|
||||
$this->addInsertAtTop($script);
|
||||
$this->addMoveToRank($script);
|
||||
$this->addSwapWith($script);
|
||||
$this->addMoveUp($script);
|
||||
$this->addMoveDown($script);
|
||||
$this->addMoveToTop($script);
|
||||
$this->addMoveToBottom($script);
|
||||
$this->addRemoveFromList($script);
|
||||
$this->addProcessSortableQueries($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wraps for getter/setter, if the rank column has not the default name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function addRankAccessors(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Wrap the getter for rank value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getRank()
|
||||
{
|
||||
return \$this->{$this->getColumnAttribute('rank_column')};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the setter for rank value
|
||||
*
|
||||
* @param int
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public function setRank(\$v)
|
||||
{
|
||||
return \$this->{$this->getColumnSetter()}(\$v);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wraps for getter/setter, if the scope column has not the default name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function addScopeAccessors(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Wrap the getter for scope value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getScopeValue()
|
||||
{
|
||||
return \$this->{$this->getColumnAttribute('scope_column')};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the setter for scope value
|
||||
*
|
||||
* @param int
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public function setScopeValue(\$v)
|
||||
{
|
||||
return \$this->{$this->getColumnSetter('scope_column')}(\$v);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addIsFirst(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Check if the object is first in the list, i.e. if it has 1 for rank
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isFirst()
|
||||
{
|
||||
return \$this->{$this->getColumnGetter()}() == 1;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addIsLast(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Check if the object is last in the list, i.e. if its rank is the highest rank
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLast(PropelPDO \$con = null)
|
||||
{
|
||||
return \$this->{$this->getColumnGetter()}() == {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetNext(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Get the next item in the list, i.e. the one for which rank is immediately higher
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public function getNext(PropelPDO \$con = null)
|
||||
{";
|
||||
if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
|
||||
$script .= "
|
||||
return {$this->queryClassname}::create()
|
||||
->filterByRank(\$this->{$this->getColumnGetter()}() + 1)
|
||||
->inList(\$this->{$this->getColumnGetter('scope_column')}())
|
||||
->findOne(\$con);";
|
||||
} else {
|
||||
$script .= "
|
||||
return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() + 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
|
||||
}
|
||||
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetPrevious(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Get the previous item in the list, i.e. the one for which rank is immediately lower
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public function getPrevious(PropelPDO \$con = null)
|
||||
{";
|
||||
if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
|
||||
$script .= "
|
||||
return {$this->queryClassname}::create()
|
||||
->filterByRank(\$this->{$this->getColumnGetter()}() - 1)
|
||||
->inList(\$this->{$this->getColumnGetter('scope_column')}())
|
||||
->findOne(\$con);";
|
||||
} else {
|
||||
$script .= "
|
||||
return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() - 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
|
||||
}
|
||||
$script .= "
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addInsertAtRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Insert at specified rank
|
||||
* The modifications are not persisted until the object is saved.
|
||||
*
|
||||
* @param integer \$rank rank value
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function insertAtRank(\$rank, PropelPDO \$con = null)
|
||||
{";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
|
||||
throw new PropelException('The scope must be defined before inserting an object in a suite');
|
||||
}";
|
||||
}
|
||||
$script .= "
|
||||
\$maxRank = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
|
||||
if (\$rank < 1 || \$rank > \$maxRank + 1) {
|
||||
throw new PropelException('Invalid rank ' . \$rank);
|
||||
}
|
||||
// move the object in the list, at the given rank
|
||||
\$this->{$this->getColumnSetter()}(\$rank);
|
||||
if (\$rank != \$maxRank + 1) {
|
||||
// Keep the list modification query for the save() transaction
|
||||
\$this->sortableQueries []= array(
|
||||
'callable' => array('$peerClassname', 'shiftRank'),
|
||||
'arguments' => array(1, \$rank, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
|
||||
);
|
||||
}
|
||||
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addInsertAtBottom(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Insert in the last rank
|
||||
* The modifications are not persisted until the object is saved.
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function insertAtBottom(PropelPDO \$con = null)
|
||||
{";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
|
||||
throw new PropelException('The scope must be defined before inserting an object in a suite');
|
||||
}";
|
||||
}
|
||||
$script .= "
|
||||
\$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
|
||||
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addInsertAtTop(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Insert in the first rank
|
||||
* The modifications are not persisted until the object is saved.
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*/
|
||||
public function insertAtTop()
|
||||
{
|
||||
return \$this->insertAtRank(1);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMoveToRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Move the object to a new rank, and shifts the rank
|
||||
* Of the objects inbetween the old and new rank accordingly
|
||||
*
|
||||
* @param integer \$newRank rank value
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function moveToRank(\$newRank, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$this->isNew()) {
|
||||
throw new PropelException('New objects cannot be moved. Please use insertAtRank() instead');
|
||||
}
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
if (\$newRank < 1 || \$newRank > {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con)) {
|
||||
throw new PropelException('Invalid rank ' . \$newRank);
|
||||
}
|
||||
|
||||
\$oldRank = \$this->{$this->getColumnGetter()}();
|
||||
if (\$oldRank == \$newRank) {
|
||||
return \$this;
|
||||
}
|
||||
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
// shift the objects between the old and the new rank
|
||||
\$delta = (\$oldRank < \$newRank) ? -1 : 1;
|
||||
$peerClassname::shiftRank(\$delta, min(\$oldRank, \$newRank), max(\$oldRank, \$newRank), " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
|
||||
|
||||
// move the object to its new rank
|
||||
\$this->{$this->getColumnSetter()}(\$newRank);
|
||||
\$this->save(\$con);
|
||||
|
||||
\$con->commit();
|
||||
return \$this;
|
||||
} catch (Exception \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addSwapWith(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Exchange the rank of the object with the one passed as argument, and saves both objects
|
||||
*
|
||||
* @param {$this->objectClassname} \$object
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*
|
||||
* @throws Exception if the database cannot execute the two updates
|
||||
*/
|
||||
public function swapWith(\$object, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$oldRank = \$this->{$this->getColumnGetter()}();
|
||||
\$newRank = \$object->{$this->getColumnGetter()}();
|
||||
\$this->{$this->getColumnSetter()}(\$newRank);
|
||||
\$this->save(\$con);
|
||||
\$object->{$this->getColumnSetter()}(\$oldRank);
|
||||
\$object->save(\$con);
|
||||
\$con->commit();
|
||||
|
||||
return \$this;
|
||||
} catch (Exception \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMoveUp(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Move the object higher in the list, i.e. exchanges its rank with the one of the previous object
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*/
|
||||
public function moveUp(PropelPDO \$con = null)
|
||||
{
|
||||
if (\$this->isFirst()) {
|
||||
return \$this;
|
||||
}
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$prev = \$this->getPrevious(\$con);
|
||||
\$this->swapWith(\$prev, \$con);
|
||||
\$con->commit();
|
||||
|
||||
return \$this;
|
||||
} catch (Exception \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMoveDown(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Move the object higher in the list, i.e. exchanges its rank with the one of the next object
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*/
|
||||
public function moveDown(PropelPDO \$con = null)
|
||||
{
|
||||
if (\$this->isLast(\$con)) {
|
||||
return \$this;
|
||||
}
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$next = \$this->getNext(\$con);
|
||||
\$this->swapWith(\$next, \$con);
|
||||
\$con->commit();
|
||||
|
||||
return \$this;
|
||||
} catch (Exception \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMoveToTop(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Move the object to the top of the list
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*/
|
||||
public function moveToTop(PropelPDO \$con = null)
|
||||
{
|
||||
if (\$this->isFirst()) {
|
||||
return \$this;
|
||||
}
|
||||
return \$this->moveToRank(1, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addMoveToBottom(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Move the object to the bottom of the list
|
||||
*
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return integer the old object's rank
|
||||
*/
|
||||
public function moveToBottom(PropelPDO \$con = null)
|
||||
{
|
||||
if (\$this->isLast(\$con)) {
|
||||
return false;
|
||||
}
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$bottom = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
|
||||
\$res = \$this->moveToRank(\$bottom, \$con);
|
||||
\$con->commit();
|
||||
|
||||
return \$res;
|
||||
} catch (Exception \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRemoveFromList(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Removes the current object from the list.
|
||||
* The modifications are not persisted until the object is saved.
|
||||
*
|
||||
* @return {$this->objectClassname} the current object
|
||||
*/
|
||||
public function removeFromList()
|
||||
{
|
||||
// Keep the list modification query for the save() transaction
|
||||
\$this->sortableQueries []= array(
|
||||
'callable' => array('$peerClassname', 'shiftRank'),
|
||||
'arguments' => array(-1, \$this->{$this->getColumnGetter()}() + 1, null" . ($useScope ? ", \$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
|
||||
);
|
||||
// remove the object from the list
|
||||
\$this->{$this->getColumnSetter('rank_column')}(null);";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$this->{$this->getColumnSetter('scope_column')}(null);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
return \$this;
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addProcessSortableQueries(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Execute queries that were saved to be run inside the save transaction
|
||||
*/
|
||||
protected function processSortableQueries(\$con)
|
||||
{
|
||||
foreach (\$this->sortableQueries as \$query) {
|
||||
\$query['arguments'][]= \$con;
|
||||
call_user_func_array(\$query['callable'], \$query['arguments']);
|
||||
}
|
||||
\$this->sortableQueries = array();
|
||||
}
|
||||
";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,367 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to add sortable peer methods
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @author heltem <heltem@o2php.com>
|
||||
* @package propel.generator.behavior.sortable
|
||||
*/
|
||||
class SortableBehaviorPeerBuilderModifier
|
||||
{
|
||||
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
|
||||
|
||||
public function __construct($behavior)
|
||||
{
|
||||
$this->behavior = $behavior;
|
||||
$this->table = $behavior->getTable();
|
||||
}
|
||||
|
||||
protected function getParameter($key)
|
||||
{
|
||||
return $this->behavior->getParameter($key);
|
||||
}
|
||||
|
||||
protected function getColumnAttribute($name)
|
||||
{
|
||||
return strtolower($this->behavior->getColumnForParameter($name)->getName());
|
||||
}
|
||||
|
||||
protected function getColumnConstant($name)
|
||||
{
|
||||
return strtoupper($this->behavior->getColumnForParameter($name)->getName());
|
||||
}
|
||||
|
||||
protected function getColumnPhpName($name)
|
||||
{
|
||||
return $this->behavior->getColumnForParameter($name)->getPhpName();
|
||||
}
|
||||
|
||||
protected function setBuilder($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
}
|
||||
|
||||
public function staticAttributes($builder)
|
||||
{
|
||||
$tableName = $this->table->getName();
|
||||
$script = "
|
||||
/**
|
||||
* rank column
|
||||
*/
|
||||
const RANK_COL = '" . $tableName . '.' . $this->getColumnConstant('rank_column') . "';
|
||||
";
|
||||
|
||||
if ($this->behavior->useScope()) {
|
||||
$script .= "
|
||||
/**
|
||||
* Scope column for the set
|
||||
*/
|
||||
const SCOPE_COL = '" . $tableName . '.' . $this->getColumnConstant('scope_column') . "';
|
||||
";
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static methods
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function staticMethods($builder)
|
||||
{
|
||||
$this->setBuilder($builder);
|
||||
$script = '';
|
||||
|
||||
$this->addGetMaxRank($script);
|
||||
$this->addRetrieveByRank($script);
|
||||
$this->addReorder($script);
|
||||
$this->addDoSelectOrderByRank($script);
|
||||
if ($this->behavior->useScope()) {
|
||||
$this->addRetrieveList($script);
|
||||
$this->addCountList($script);
|
||||
$this->addDeleteList($script);
|
||||
}
|
||||
$this->addShiftRank($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addGetMaxRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Get the highest rank
|
||||
* ";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which suite to consider";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO optional connection
|
||||
*
|
||||
* @return integer highest position
|
||||
*/
|
||||
public static function getMaxRank(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
// shift the objects with a position lower than the one of object
|
||||
\$c = new Criteria();
|
||||
\$c->addSelectColumn('MAX(' . {$this->peerClassname}::RANK_COL . ')');";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$c->add({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
\$stmt = {$this->peerClassname}::doSelectStmt(\$c, \$con);
|
||||
|
||||
return \$stmt->fetchColumn();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRetrieveByRank(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Get an item from the list based on its rank
|
||||
*
|
||||
* @param integer \$rank rank";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which suite to consider";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public static function retrieveByRank(\$rank, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
|
||||
\$c = new Criteria;
|
||||
\$c->add($peerClassname::RANK_COL, \$rank);";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
return $peerClassname::doSelectOne(\$c, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addReorder(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$columnGetter = 'get' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
|
||||
$columnSetter = 'set' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Reorder a set of sortable objects based on a list of id/position
|
||||
* Beware that there is no check made on the positions passed
|
||||
* So incoherent positions will result in an incoherent list
|
||||
*
|
||||
* @param array \$order id => rank pairs
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return boolean true if the reordering took place, false if a database problem prevented it
|
||||
*/
|
||||
public static function reorder(array \$order, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$ids = array_keys(\$order);
|
||||
\$objects = $peerClassname::retrieveByPKs(\$ids);
|
||||
foreach (\$objects as \$object) {
|
||||
\$pk = \$object->getPrimaryKey();
|
||||
if (\$object->$columnGetter() != \$order[\$pk]) {
|
||||
\$object->$columnSetter(\$order[\$pk]);
|
||||
\$object->save(\$con);
|
||||
}
|
||||
}
|
||||
\$con->commit();
|
||||
|
||||
return true;
|
||||
} catch (PropelException \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addDoSelectOrderByRank(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Return an array of sortable objects ordered by position
|
||||
*
|
||||
* @param Criteria \$criteria optional criteria object
|
||||
* @param string \$order sorting order, to be chosen between Criteria::ASC (default) and Criteria::DESC
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return array list of sortable objects
|
||||
*/
|
||||
public static function doSelectOrderByRank(Criteria \$criteria = null, \$order = Criteria::ASC, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
|
||||
if (\$criteria === null) {
|
||||
\$criteria = new Criteria();
|
||||
} elseif (\$criteria instanceof Criteria) {
|
||||
\$criteria = clone \$criteria;
|
||||
}
|
||||
|
||||
\$criteria->clearOrderByColumns();
|
||||
|
||||
if (\$order == Criteria::ASC) {
|
||||
\$criteria->addAscendingOrderByColumn($peerClassname::RANK_COL);
|
||||
} else {
|
||||
\$criteria->addDescendingOrderByColumn($peerClassname::RANK_COL);
|
||||
}
|
||||
|
||||
return $peerClassname::doSelect(\$criteria, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addRetrieveList(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Return an array of sortable objects in the given scope ordered by position
|
||||
*
|
||||
* @param int \$scope the scope of the list
|
||||
* @param string \$order sorting order, to be chosen between Criteria::ASC (default) and Criteria::DESC
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return array list of sortable objects
|
||||
*/
|
||||
public static function retrieveList(\$scope, \$order = Criteria::ASC, PropelPDO \$con = null)
|
||||
{
|
||||
\$c = new Criteria();
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope);
|
||||
|
||||
return $peerClassname::doSelectOrderByRank(\$c, \$order, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addCountList(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Return the number of sortable objects in the given scope
|
||||
*
|
||||
* @param int \$scope the scope of the list
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return array list of sortable objects
|
||||
*/
|
||||
public static function countList(\$scope, PropelPDO \$con = null)
|
||||
{
|
||||
\$c = new Criteria();
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope);
|
||||
|
||||
return $peerClassname::doCount(\$c, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addDeleteList(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Deletes the sortable objects in the given scope
|
||||
*
|
||||
* @param int \$scope the scope of the list
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return int number of deleted objects
|
||||
*/
|
||||
public static function deleteList(\$scope, PropelPDO \$con = null)
|
||||
{
|
||||
\$c = new Criteria();
|
||||
\$c->add($peerClassname::SCOPE_COL, \$scope);
|
||||
|
||||
return $peerClassname::doDelete(\$c, \$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
protected function addShiftRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Adds \$delta to all Rank values that are >= \$first and <= \$last.
|
||||
* '\$delta' can also be negative.
|
||||
*
|
||||
* @param int \$delta Value to be shifted by, can be negative
|
||||
* @param int \$first First node to be shifted
|
||||
* @param int \$last Last node to be shifted";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to use for the shift";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*/
|
||||
public static function shiftRank(\$delta, \$first, \$last = null, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
|
||||
}
|
||||
|
||||
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::RANK_COL, \$first, Criteria::GREATER_EQUAL);
|
||||
if (null !== \$last) {
|
||||
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::RANK_COL, \$last, Criteria::LESS_EQUAL));
|
||||
}
|
||||
\$whereCriteria->add(\$criterion);";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
|
||||
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
|
||||
\$valuesCriteria->add($peerClassname::RANK_COL, array('raw' => $peerClassname::RANK_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
|
||||
|
||||
{$this->builder->getPeerBuilder()->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
|
||||
$peerClassname::clearInstancePool();
|
||||
}
|
||||
";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
<?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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Behavior to add sortable query methods
|
||||
*
|
||||
* @author François Zaninotto
|
||||
* @package propel.generator.behavior.sortable
|
||||
*/
|
||||
class SortableBehaviorQueryBuilderModifier
|
||||
{
|
||||
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
|
||||
|
||||
public function __construct($behavior)
|
||||
{
|
||||
$this->behavior = $behavior;
|
||||
$this->table = $behavior->getTable();
|
||||
}
|
||||
|
||||
protected function getParameter($key)
|
||||
{
|
||||
return $this->behavior->getParameter($key);
|
||||
}
|
||||
|
||||
protected function getColumn($name)
|
||||
{
|
||||
return $this->behavior->getColumnForParameter($name);
|
||||
}
|
||||
|
||||
protected function setBuilder($builder)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
|
||||
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
|
||||
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
|
||||
}
|
||||
|
||||
public function queryMethods($builder)
|
||||
{
|
||||
$this->setBuilder($builder);
|
||||
$script = '';
|
||||
|
||||
// select filters
|
||||
if ($this->behavior->useScope()) {
|
||||
$this->addInList($script);
|
||||
}
|
||||
if ($this->getParameter('rank_column') != 'rank') {
|
||||
$this->addFilterByRank($script);
|
||||
$this->addOrderByRank($script);
|
||||
}
|
||||
|
||||
// select termination methods
|
||||
if ($this->getParameter('rank_column') != 'rank') {
|
||||
$this->addFindOneByRank($script);
|
||||
}
|
||||
$this->addFindList($script);
|
||||
|
||||
// utilities
|
||||
$this->addGetMaxRank($script);
|
||||
$this->addReorder($script);
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
protected function addInList(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Returns the objects in a certain list, from the list scope
|
||||
*
|
||||
* @param int \$scope Scope to determine which objects node to return
|
||||
*
|
||||
* @return {$this->queryClassname} The current query, for fuid interface
|
||||
*/
|
||||
public function inList(\$scope = null)
|
||||
{
|
||||
return \$this->addUsingAlias({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFilterByRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Filter the query based on a rank in the list
|
||||
*
|
||||
* @param integer \$rank rank";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which suite to consider";
|
||||
}
|
||||
$script .= "
|
||||
*
|
||||
* @return " . $this->queryClassname . " The current query, for fluid interface
|
||||
*/
|
||||
public function filterByRank(\$rank" . ($useScope ? ", \$scope = null" : "") . ")
|
||||
{
|
||||
return \$this";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
->inList(\$scope)";
|
||||
}
|
||||
$script .= "
|
||||
->addUsingAlias($peerClassname::RANK_COL, \$rank, Criteria::EQUAL);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addOrderByRank(&$script)
|
||||
{
|
||||
$script .= "
|
||||
/**
|
||||
* Order the query based on the rank in the list.
|
||||
* Using the default \$order, returns the item with the lowest rank first
|
||||
*
|
||||
* @param string \$order either Criteria::ASC (default) or Criteria::DESC
|
||||
*
|
||||
* @return " . $this->queryClassname . " The current query, for fluid interface
|
||||
*/
|
||||
public function orderByRank(\$order = Criteria::ASC)
|
||||
{
|
||||
\$order = strtoupper(\$order);
|
||||
switch (\$order) {
|
||||
case Criteria::ASC:
|
||||
return \$this->addAscendingOrderByColumn(\$this->getAliasedColName(" . $this->peerClassname . "::RANK_COL));
|
||||
break;
|
||||
case Criteria::DESC:
|
||||
return \$this->addDescendingOrderByColumn(\$this->getAliasedColName(" . $this->peerClassname . "::RANK_COL));
|
||||
break;
|
||||
default:
|
||||
throw new PropelException('" . $this->queryClassname . "::orderBy() only accepts \"asc\" or \"desc\" as argument');
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFindOneByRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$peerClassname = $this->peerClassname;
|
||||
$script .= "
|
||||
/**
|
||||
* Get an item from the list based on its rank
|
||||
*
|
||||
* @param integer \$rank rank";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which suite to consider";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return {$this->objectClassname}
|
||||
*/
|
||||
public function findOneByRank(\$rank, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
return \$this
|
||||
->filterByRank(\$rank" . ($useScope ? ", \$scope" : "") . ")
|
||||
->findOne(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addFindList(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Returns " . ($useScope ? 'a' : 'the') ." list of objects
|
||||
*";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which list to return";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO \$con Connection to use.
|
||||
*
|
||||
* @return mixed the list of results, formatted by the current formatter
|
||||
*/
|
||||
public function findList(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
|
||||
{
|
||||
return \$this";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
->inList(\$scope)";
|
||||
}
|
||||
$script .= "
|
||||
->orderByRank()
|
||||
->find(\$con);
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addGetMaxRank(&$script)
|
||||
{
|
||||
$useScope = $this->behavior->useScope();
|
||||
$script .= "
|
||||
/**
|
||||
* Get the highest rank
|
||||
* ";
|
||||
if($useScope) {
|
||||
$script .= "
|
||||
* @param int \$scope Scope to determine which suite to consider";
|
||||
}
|
||||
$script .= "
|
||||
* @param PropelPDO optional connection
|
||||
*
|
||||
* @return integer highest position
|
||||
*/
|
||||
public function getMaxRank(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
|
||||
}
|
||||
// shift the objects with a position lower than the one of object
|
||||
\$this->addSelectColumn('MAX(' . {$this->peerClassname}::RANK_COL . ')');";
|
||||
if ($useScope) {
|
||||
$script .= "
|
||||
\$this->add({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);";
|
||||
}
|
||||
$script .= "
|
||||
\$stmt = \$this->getSelectStatement(\$con);
|
||||
|
||||
return \$stmt->fetchColumn();
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
protected function addReorder(&$script)
|
||||
{
|
||||
$peerClassname = $this->peerClassname;
|
||||
$columnGetter = 'get' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
|
||||
$columnSetter = 'set' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
|
||||
$script .= "
|
||||
/**
|
||||
* Reorder a set of sortable objects based on a list of id/position
|
||||
* Beware that there is no check made on the positions passed
|
||||
* So incoherent positions will result in an incoherent list
|
||||
*
|
||||
* @param array \$order id => rank pairs
|
||||
* @param PropelPDO \$con optional connection
|
||||
*
|
||||
* @return boolean true if the reordering took place, false if a database problem prevented it
|
||||
*/
|
||||
public function reorder(array \$order, PropelPDO \$con = null)
|
||||
{
|
||||
if (\$con === null) {
|
||||
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
|
||||
}
|
||||
|
||||
\$con->beginTransaction();
|
||||
try {
|
||||
\$ids = array_keys(\$order);
|
||||
\$objects = \$this->findPks(\$ids, \$con);
|
||||
foreach (\$objects as \$object) {
|
||||
\$pk = \$object->getPrimaryKey();
|
||||
if (\$object->$columnGetter() != \$order[\$pk]) {
|
||||
\$object->$columnSetter(\$order[\$pk]);
|
||||
\$object->save(\$con);
|
||||
}
|
||||
}
|
||||
\$con->commit();
|
||||
|
||||
return true;
|
||||
} catch (PropelException \$e) {
|
||||
\$con->rollback();
|
||||
throw \$e;
|
||||
}
|
||||
}
|
||||
";
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue