Skip to content

Commit

Permalink
Restructured aggregate_column behavior to fix issue
Browse files Browse the repository at this point in the history
  • Loading branch information
josedsilva committed May 11, 2012
1 parent 82372dd commit 8c67232
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 59 deletions.
171 changes: 125 additions & 46 deletions generator/lib/behavior/aggregate_column/AggregateColumnBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/**
* Keeps an aggregate column updated with related table
*
* @author François Zaninotto
* @author François Zaninotto, Jose F. D'Silva (jose.dsilva@bombayworks.se)
* @version $Revision$
* @package propel.generator.behavior.aggregate_column
*/
Expand All @@ -34,88 +34,152 @@ class AggregateColumnBehavior extends Behavior
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 columns if not present
$columnNames = $this->getColumnNames();
foreach ($columnNames as $columnName) {
if( ! $table->containsColumn($columnName)) {
$column = $table->addColumn(array(
'name' => $columnName,
'type' => 'INTEGER',
));
}
}

// 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);
// add behavior to foreign tables to autoupdate aggregate columns
$foreignTables = $this->getForeignTables();
$columns = $this->getColumns(); // get aggregate column objects
foreach ($foreignTables as $k => $foreignTable) {
//var_dump($foreignTable); //MARK
if(!$foreignTable->hasBehavior('concrete_inheritance_parent')) {
$relationBehaviorName = 'aggregate_column_relation_to_' . $table->getName() . '_' . $columnNames[$k];
$relationBehavior = new AggregateColumnRelationBehavior();
$relationBehavior->setName($relationBehaviorName);
// FIXME does this really serve any purpose other than check whether a fk is defined?
$foreignKey = $this->getForeignKey($foreignTable);
$relationBehavior->addParameter(array('name' => 'foreign_table', 'value' => $table->getName()));
$relationBehavior->addParameter(array('name' => 'update_method', 'value' => 'update' . $columns[$k]->getPhpName()));
$relationBehavior->addParameter(array('name' => 'foreign_aggregate_column', 'value' => $columns[$k]->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();

$aggregateColumns = $this->getColumns();
$expressions = $this->getExpressions();
$fullyQualifiedForeignTables = $this->getFullyQualifiedForeignTables();
//var_dump(count($fullyQualifiedForeignTables)); //MARK
$index = 0;
foreach ($fullyQualifiedForeignTables as $data) {
$script .= $this->addObjectCompute($data['FullyQualifiedName'], $data['ForeignTableName'], $data['TableObject'], $aggregateColumns[$index], $expressions[$index]);
$script .= $this->addObjectUpdate($aggregateColumns[$index]);
++ $index;
}
return $script;
}

protected function addObjectCompute()
protected function addObjectCompute($fullyQualifiedForeignTableName, $foreignTableName, $foreignTable, $aggregateColumn, $expression)
{
$conditions = array();
$bindings = array();
$database = $this->getTable()->getDatabase();
foreach ($this->getForeignKey()->getColumnObjectsMapping() as $index => $columnReference) {
foreach ($this->getForeignKey($foreignTable)->getColumnObjectsMapping() as $index => $columnReference) {
$conditions[] = $columnReference['local']->getFullyQualifiedName() . ' = :p' . ($index + 1);
$bindings[$index + 1] = $columnReference['foreign']->getPhpName();
}
$tableName = $database->getTablePrefix() . $this->getParameter('foreign_table');
if ($database->getPlatform()->supportsSchemas() && $this->getParameter('foreign_schema')) {
$tableName = $this->getParameter('foreign_schema').'.'.$tableName;
}
$sql = sprintf('SELECT %s FROM %s WHERE %s',
$this->getParameter('expression'),
$database->getPlatform()->quoteIdentifier($tableName),
$expression,
$database->getPlatform()->quoteIdentifier($fullyQualifiedForeignTableName),
implode(' AND ', $conditions)
);

return $this->renderTemplate('objectCompute', array(
'column' => $this->getColumn(),
'column' => $aggregateColumn,
'sql' => $sql,
'bindings' => $bindings,
));
}

protected function addObjectUpdate()
protected function addObjectUpdate($aggregateColumn)
{
return $this->renderTemplate('objectUpdate', array(
'column' => $this->getColumn(),
'column' => $aggregateColumn,
));
}

protected function getForeignTable()
protected function getExpressions() {
if(!($expressionString = $this->getParameter('expression')) )
throw new InvalidArgumentException(sprintf('You must define an \'expression\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $this->getTable()->getName()));

$expressions = explode(',', $expressionString);
return array_map('trim', $expressions);
}

protected function getForeignTableNames() {
if(!($foreignTableString = $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()));
}

$foreignTableNames = explode(',', $foreignTableString);
return array_map('trim', $foreignTableNames);
}

protected function getFullyQualifiedForeignTables() {
$database = $this->getTable()->getDatabase();
$foreignTableNames = $this->getForeignTableNames();
$foreignSchemaString = $this->getParameter('foreign_schema');
$hasForeignSchema = false;
if($foreignSchemaString && $database->getPlatform()->supportsSchemas()) {
$foreignSchemaNames = explode(',', $foreignSchemaString);
$foreignSchemaNames = array_map('trim', $foreignSchemaNames);
$hasForeignSchema = true;
}

$foreignTables = array();
foreach ($foreignTableNames as $k => $foreignTableName) {
$tableName = (($hasForeignSchema && $foreignSchemaNames[$k]) ? $foreignSchemaNames[$k] . '.' : '') . $database->getTablePrefix() . $foreignTableName;
$foreignTables[] = array(
'ForeignTableName' => $foreignTableName,
'FullyQualifiedName' => $tableName,
'TableObject' => $database->getTable($tableName),
);
}
return $foreignTables;
}

protected function getForeignTables()
{
$database = $this->getTable()->getDatabase();
$tableName = $database->getTablePrefix() . $this->getParameter('foreign_table');
if ($database->getPlatform()->supportsSchemas() && $this->getParameter('foreign_schema')) {
$tableName = $this->getParameter('foreign_schema'). '.' . $tableName;
$foreignTableNames = $this->getForeignTableNames();
//var_dump($foreignTableNames); //MARK
$foreignSchemaString = $this->getParameter('foreign_schema');
$hasForeignSchema = false;
if($foreignSchemaString && $database->getPlatform()->supportsSchemas()) {
$foreignSchemaNames = explode(',', $foreignSchemaString);
$hasForeignSchema = true;
}

$foreignTables = array();
foreach ($foreignTableNames as $k => $foreignTableName) {
$tableName = (($hasForeignSchema && $foreignSchemaNames[$k]) ? $foreignSchemaNames[$k] . '.' : '') . $database->getTablePrefix() . $foreignTableName;
$foreignTables[] = $database->getTable($tableName);
}

return $foreignTables;
}

protected function getForeignKeys() {
$foreignKeys = array();
foreach ($this->getForeignTables() as $foreignTable) {
$foreignKeys[] = $this->getForeignKey($foreignTable);
}
return $database->getTable($tableName);
return $foreignKeys;
}

protected function getForeignKey()
protected function getForeignKey($foreignTable)
{
$foreignTable = $this->getForeignTable();
// let's infer the relation from the foreign table
$fks = $foreignTable->getForeignKeysReferencingTable($this->getTable()->getName());
if (!$fks) {
Expand All @@ -125,9 +189,24 @@ protected function getForeignKey()
return array_shift($fks);
}

protected function getColumn()
protected function getColumnNames() {
if ( !($columnNameString = $this->getParameter('name')) ) {
throw new InvalidArgumentException(sprintf('You must define a \'name\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $this->getTable()->getName()));
}

$columnNames = explode(',', $columnNameString);
return array_map('trim', $columnNames);
}

protected function getColumns()
{
return $this->getTable()->getColumn($this->getParameter('name'));
$columnNames = $this->getColumnNames();
$columns = array();
$table = $this->getTable();
foreach($columnNames as $columnName) {
$columns[] = $table->getColumn($columnName);
}
return $columns;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
* @license MIT License
*/

require_once 'AggregateColumnRelationBehavior.php';
//require_once 'AggregateColumnRelationBehaviorBuilder.php';

/**
* Keeps an aggregate column updated with related table
*
* @author François Zaninotto
* @author François Zaninotto, Jose F. D'Silva (jose.dsilva@bombayworks.se)
* @version $Revision$
* @package propel.generator.behavior.aggregate_column
*/
Expand All @@ -24,12 +24,14 @@ class AggregateColumnRelationBehavior extends Behavior
protected $parameters = array(
'foreign_table' => '',
'update_method' => '',
'foreign_aggregate_column' => '',
);

public function postSave($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->updateRelated{$relationName}(\$con);";
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return "\$this->updateRelated{$relationName}For{$aggregateColumn}(\$con);";
}

// no need for a postDelete() hook, since delete() uses Query::delete(),
Expand All @@ -38,7 +40,8 @@ public function postSave($builder)
public function objectAttributes($builder)
{
$relationName = $this->getRelationName($builder);
return "protected \$old{$relationName};
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return "protected \$old{$relationName}For{$aggregateColumn};
";
}

Expand All @@ -50,9 +53,11 @@ public function objectMethods($builder)
protected function addObjectUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
$updateMethodName = $this->getParameter('update_method');
return $this->renderTemplate('objectUpdateRelated', array(
'relationName' => $relationName,
'aggregateColumn' => $aggregateColumn,
'variableName' => self::lcfirst($relationName),
'updateMethodName' => $this->getParameter('update_method'),
));
Expand All @@ -61,13 +66,14 @@ protected function addObjectUpdateRelated($builder)
public function objectFilter(&$script, $builder)
{
$relationName = $this->getRelationName($builder);
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
$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};
\$this->old{$relationName}For{$aggregateColumn} = \$this->a{$relationName};
}";
$script = str_replace($search, $replace, $script);
}
Expand All @@ -85,7 +91,8 @@ public function preDeleteQuery($builder)
protected function getFindRelated($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->findRelated{$relationName}s(\$con);";
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return "\$this->findRelated{$relationName}s{$aggregateColumn}(\$con);";
}

public function postUpdateQuery($builder)
Expand All @@ -101,7 +108,8 @@ public function postDeleteQuery($builder)
protected function getUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->updateRelated{$relationName}s(\$con);";
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return "\$this->updateRelated{$relationName}s{$aggregateColumn}(\$con);";
}

public function queryMethods($builder)
Expand All @@ -119,9 +127,11 @@ protected function addQueryFindRelated($builder)
$foreignQueryBuilder = $builder->getNewStubQueryBuilder($foreignKey->getForeignTable());
$builder->declareClass($foreignQueryBuilder->getFullyQualifiedClassname());
$relationName = $this->getRelationName($builder);
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return $this->renderTemplate('queryFindRelated', array(
'foreignTable' => $this->getForeignTable(),
'relationName' => $relationName,
'aggregateColumn' => $aggregateColumn,
'variableName' => self::lcfirst($relationName),
'foreignQueryName' => $foreignQueryBuilder->getClassname(),
'refRelationName' => $builder->getRefFKPhpNameAffix($foreignKey),
Expand All @@ -131,8 +141,10 @@ protected function addQueryFindRelated($builder)
protected function addQueryUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
$aggregateColumn = $this->getParameter('foreign_aggregate_column');
return $this->renderTemplate('queryUpdateRelated', array(
'relationName' => $relationName,
'aggregateColumn' => $aggregateColumn,
'variableName' => self::lcfirst($relationName),
'updateMethodName' => $this->getParameter('update_method'),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
*
* @param PropelPDO $con A connection object
*/
protected function updateRelated<?php echo $relationName ?>(PropelPDO $con)
protected function updateRelated<?php echo $relationName ?>For<?php echo $aggregateColumn ?>(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;
if ($this->old<?php echo $relationName ?>For<?php echo $aggregateColumn ?>) {
$this->old<?php echo $relationName ?>For<?php echo $aggregateColumn ?>-><?php echo $updateMethodName ?>($con);
$this->old<?php echo $relationName ?>For<?php echo $aggregateColumn ?> = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* @param PropelPDO $con A connection object
*/
protected function findRelated<?php echo $relationName ?>s($con)
protected function findRelated<?php echo $relationName ?>s<?php echo $aggregateColumn ?>($con)
{
$criteria = clone $this;
if ($this->useAliasInSQL) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

protected function updateRelated<?php echo $relationName ?>s($con)
protected function updateRelated<?php echo $relationName ?>s<?php echo $aggregateColumn ?>($con)
{
foreach ($this-><?php echo $variableName ?>s as $<?php echo $variableName ?>) {
$<?php echo $variableName ?>-><?php echo $updateMethodName ?>($con);
Expand Down

0 comments on commit 8c67232

Please sign in to comment.