sintonia/airtime_mvc/library/propel/docs/behavior/aggregate_column.txt

131 lines
4.9 KiB
Plaintext

= Aggregate Column Behavior =
The `aggregate_column` behavior keeps a column updated using an aggregate function executed on a related table.
== Basic Usage ==
In the `schema.xml`, use the `<behavior>` tag to add the `aggregate_column` behavior to a table. You must provide parameters for the aggregate column `name`, the foreign table name, and the aggegate `expression`. For instance, to add an aggregate column keeping the comment count in a `post` table:
{{{
#!xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="aggregate_column">
<parameter name="name" value="nb_comments" />
<parameter name="foreign_table" value="comment" />
<parameter name="expression" value="COUNT(id)" />
</behavior>
</table>
<table name="comment">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="post_id" type="INTEGER" />
<foreign-key foreignTable="post" onDelete="cascade">
<reference local="post_id" foreign="id" />
</foreign-key>
</table>
}}}
Rebuild your model, and insert the table creation sql again. The model now has an additional `nb_comments` column, of type `integer` by default. And each time an record from the foreign table is added, modified, or removed, the aggregate column is updated:
{{{
#!php
<?php
$post = new Post();
$post->setTitle('How Is Life On Earth?');
$post->save();
echo $post->getNbComments(); // 0
$comment1 = new Comment();
$comment1->setPost($post);
$comment1->save();
echo $post->getNbComments(); // 1
$comment2 = new Comment();
$comment2->setPost($post);
$comment2->save();
echo $post->getNbComments(); // 2
$comment2->delete();
echo $post->getNbComments(); // 1
}}}
The aggregate column is also kept up to date when related records get modified through a Query object:
{{{
#!php
<?php
CommentQuery::create()
->filterByPost($post)
->delete():
echo $post->getNbComments(); // 0
}}}
== Customizing The Aggregate Calculation ==
Any aggregate function can be used on any of the foreign columns. For instance, you can use the `aggregate_column` behavior to keep the latest update date of the related comments, or the total votes on the comments. You can even keep several aggregate columns in a single table:
{{{
#!xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="aggregate_column">
<parameter name="name" value="nb_comments" />
<parameter name="foreign_table" value="comment" />
<parameter name="expression" value="COUNT(id)" />
</behavior>
<behavior name="aggregate_column">
<parameter name="name" value="last_comment" />
<parameter name="foreign_table" value="comment" />
<parameter name="expression" value="MAX(created_at)" />
</behavior>
<behavior name="aggregate_column">
<parameter name="name" value="total_votes" />
<parameter name="foreign_table" value="comment" />
<parameter name="expression" value="SUM(vote)" />
</behavior>
</table>
<table name="comment">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="post_id" type="INTEGER" />
<foreign-key foreignTable="post" onDelete="cascade">
<reference local="post_id" foreign="id" />
</foreign-key>
<column name="created_at" type="TIMESTAMP" />
<column name="vote" type="INTEGER" />
</table>
}}}
The behavior adds a `computeXXX()` method to the `Post` class to compute the value of the aggregate function. This method, called each time records are modified in the related `comment` table, is the translation of the behavior settings into a SQL query:
{{{
#!php
<?php
// in om/BasePost.php
public function computeNbComments(PropelPDO $con)
{
$stmt = $con->prepare('SELECT COUNT(id) FROM `comment` WHERE comment.POST_ID = :p1');
$stmt->bindValue(':p1', $this->getId());
$stmt->execute();
return $stmt->fetchColumn();
}
}}}
You can override this method in the model class to customize the aggregate column calculation.
== Customizing The Aggregate Column ==
By default, the behavior adds one columns to the model. If this column is already described in the schema, the behavior detects it and doesn't add it a second time. This can be useful if you need to use a custom `type` or `phpName` for the aggregate column:
{{{
#!xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<column name="nb_comments" phpName="CommentCount" type="INTEGER" />
<behavior name="aggregate_column">
<parameter name="name" value="nb_comments" />
<parameter name="foreign_table" value="comment" />
<parameter name="expression" value="COUNT(id)" />
</behavior>
</table>
}}}