Permalink
Browse files

ENHANCEMENT Adding List() in the GenericTemplateGlobalProvider so

templates can use <% cached List(Member).max(LastEdited) %> instead
of deprecated "Aggregate" syntax.
  • Loading branch information...
1 parent d7a8fa9 commit 792c89e10382bf84b44487a3baf96aae879bb462 @halkyon halkyon committed May 19, 2012
@@ -193,6 +193,17 @@ The abstract `RelationList` class and its implementations `ManyManyList` and `Ha
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).
+### Aggregate changes for partial caching in templates ###
+
+`DataObject::Aggregate()` and `DataObject::RelationshipAggregate()` are now deprecated. To replace your deprecated aggregate calls
+in PHP code, you should query with something like `Member::get()->max('LastEdited')`, that is, calling the aggregate on the `DataList` directly.
+The same concept applies for replacing `RelationshipAggregate()`, just call the aggregate method on the relationship instead,
+so something like `Member::get()->Groups()->max('LastEdited')`.
+
+For partial caching in templates, the syntax `<% cached Aggregate(Page).Max(LastEdited) %>` has been deprecated. The new syntax is similar,
+except you use `List()` instead of `Aggregate()`, and the aggregate call `Max()` is now lowercase, as in `max()`.
+An example of the new syntax is `<% cached List(Page).max(LastEdited) %>`. Check `DataList` class for more aggregate methods to use.
+
### `SQLQuery` changes ###
`SQLQuery` has been changed so direct access to internal properties `$from`, `$select`, `$orderby` is
@@ -61,21 +61,21 @@ For example, if we have a menu, we want that menu to update whenever _any_ page
otherwise. By using aggregates, that's easy
:::ss
- <% cached 'navigation', Aggregate(Page).Max(LastEdited) %>
+ <% cached 'navigation', List(Page).max(LastEdited) %>
If we have a block that shows a list of categories, we can make sure the cache updates every time a category is added or
edited
:::ss
- <% cached 'categorylist', Aggregate(Category).Max(LastEdited) %>
+ <% cached 'categorylist', List(Category).max(LastEdited) %>
We can also calculate aggregates on relationships. A block that shows the current member's favourites needs to update
whenever the relationship Member::$has_many = array('Favourites' => Favourite') changes.
:::ss
- <% cached 'favourites', CurrentMember.ID, CurrentMember.RelationshipAggregate(Favourites).Max(LastEdited) %>
+ <% cached 'favourites', CurrentMember.ID, CurrentMember.Favourites.max(LastEdited) %>
## Cache key calculated in controller
@@ -89,7 +89,7 @@ logic into the controller
return implode('_', array(
'favourites',
$member->ID,
- $member->RelationshipAggregate('Favourites')->Max('LastEdited')
+ $member->Favourites()->max('LastEdited')
));
}
@@ -230,10 +230,10 @@ Can be re-written as:
:::ss
<% cached LastEdited %>
- <% cached RelationshipAggregate(Children).Max(LastEdited) %>
+ <% cached Children.max(LastEdited) %>
<% control Children %>
$Name
<% end_control %>
<% end_cached %>
- <% end_cached %>
+ <% end_cached %>
View
@@ -2659,26 +2659,28 @@ public static function get($callerClass = null, $filter = "", $sort = "", $join
* @deprecated 3.0 Use DataList::create and DataList to do your querying
*/
public function Aggregate($class = null) {
- Deprecation::notice('3.0', 'Use DataList::create and DataList to do your querying instead.');
+ Deprecation::notice('3.0', 'Call aggregate methods on a DataList directly instead. In templates ' .
+ 'an example of the new syntax is &lt% cached List(Member).max(LastEdited) %&gt instead (check partial-caching.md documentation ' .
+ 'for more details.)');
- if($class) {
+ if($class) {
$list = new DataList($class);
$list->setDataModel(DataModel::inst());
} else if(isset($this)) {
$list = new DataList(get_class($this));
$list->setDataModel($this->model);
}
- else throw new InvalidArgumentException("DataObject::aggregate() must be called as an instance method or passed a classname");
+ else throw new InvalidArgumentException("DataObject::aggregate() must be called as an instance method or passed a classname");
return $list;
}
/**
* @deprecated 3.0 Use DataList::create and DataList to do your querying
*/
public function RelationshipAggregate($relationship) {
- Deprecation::notice('3.0', 'Use DataList::create and DataList to do your querying instead.');
+ Deprecation::notice('3.0', 'Call aggregate methods on a relationship directly instead.');
- return $this->$relationship();
+ return $this->$relationship();
}
/**
View
@@ -315,7 +315,7 @@ function sql() {
* Note that this will issue a separate SELECT COUNT() query.
*/
function count() {
- $baseClass = ClassInfo::baseDataClass($this->dataClass);
+ $baseClass = ClassInfo::baseDataClass($this->dataClass);
return $this->getFinalisedQuery()->count("DISTINCT \"$baseClass\".\"ID\"");
}
@@ -324,35 +324,35 @@ function count() {
*
* @param String $field Unquoted database column name (will be escaped automatically)
*/
- function Max($field) {
- return $this->getFinalisedQuery()->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)))->execute()->value();
+ function max($field) {
+ return $this->getFinalisedQuery()->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)))->execute()->value();
}
/**
* Return the minimum value of the given field in this DataList
*
* @param String $field Unquoted database column name (will be escaped automatically)
*/
- function Min($field) {
- return $this->getFinalisedQuery()->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)))->execute()->value();
+ function min($field) {
+ return $this->getFinalisedQuery()->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)))->execute()->value();
}
/**
* Return the average value of the given field in this DataList
*
* @param String $field Unquoted database column name (will be escaped automatically)
*/
- function Avg($field) {
- return $this->getFinalisedQuery()->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)))->execute()->value();
+ function avg($field) {
+ return $this->getFinalisedQuery()->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)))->execute()->value();
}
/**
* Return the sum of the values of the given field in this DataList
*
* @param String $field Unquoted database column name (will be escaped automatically)
*/
- function Sum($field) {
- return $this->getFinalisedQuery()->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)))->execute()->value();
+ function sum($field) {
+ return $this->getFinalisedQuery()->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)))->execute()->value();
}
/**
@@ -1,7 +1,13 @@
<?php
/*
- * A hierarchy of data types, to
+ * A hierarchy of data types, to...
+ *
+ * @deprecated. This is testing`
+ * {@link DataObject::Aggregate()} and {@link DataObject::RelationshipAggregate()}
+ * which are deprecated. Aggregates are handled directly by DataList instead.
+ * This test should be removed or merged into DataListTest once those functions are
+ * removed from DataObject.
*/
class AggregateTest_Foo extends DataObject implements TestOnly {
static $db = array(
@@ -54,7 +54,7 @@ function testRequirements() {
$this->assertFalse((bool)trim($template), "Should be no content in this return.");
}
-
+
function testComments() {
$output = $this->render(<<<SS
This is my template<%-- this is a comment --%>This is some content<%-- this is another comment --%>This is the final content
@@ -3,7 +3,8 @@ class GenericTemplateGlobalProvider implements TemplateGlobalProvider {
public static function get_template_global_variables() {
return array(
- 'ModulePath'
+ 'ModulePath',
+ 'List' => 'getDataList'
);
}
@@ -30,5 +31,24 @@ public static function ModulePath($name) {
}
}
+ /**
+ * This allows templates to create a new `DataList` from a known
+ * DataObject class name, and call methods such as aggregates.
+ *
+ * The common use case is for partial caching:
+ * <code>
+ * <% cached List(Member).max(LastEdited) %>
+ * loop members here
+ * <% end_cached %>
+ * </code>
+ *
+ * @return DataList
+ */
+ public static function getDataList($className) {
+ $list = new DataList($className);
+ $list->setDataModel(DataModel::inst());
+ return $list;
+ }
+
}
View
@@ -51,14 +51,13 @@ function resetLocalScope(){
list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex, $this->currentIndex) = $this->itemStack[$this->localIndex];
array_splice($this->itemStack, $this->localIndex+1);
}
-
+
function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {
$on = $this->itemIterator ? $this->itemIterator->current() : $this->item;
return $on->obj($name, $arguments, $forceReturnedObject, $cache, $cacheName);
}
-
- function obj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null){
-
+
+ function obj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {
switch ($name) {
case 'Up':
if ($this->upIndex === null) user_error('Up called when we\'re already at the top of the scope', E_USER_ERROR);
@@ -72,13 +71,12 @@ function obj($name, $arguments = null, $forceReturnedObject = true, $cache = fal
default:
$this->item = $this->getObj($name, $arguments, $forceReturnedObject, $cache, $cacheName);
-
$this->itemIterator = null;
$this->upIndex = $this->currentIndex ? $this->currentIndex : count($this->itemStack)-1;
$this->currentIndex = count($this->itemStack);
break;
}
-
+
$this->itemStack[] = array($this->item, $this->itemIterator, $this->itemIteratorTotal, null, $this->upIndex, $this->currentIndex);
return $this;
}
@@ -380,7 +378,6 @@ function getInjectedValue($property, $params, $cast = true) {
// Then for iterator-specific overrides
else if (array_key_exists($property, self::$iteratorProperties)) {
$source = self::$iteratorProperties[$property];
-
if ($this->itemIterator) {
// Set the current iterator position and total (the object instance is the first item in the callable array)
$source['implementer']->iteratorProperties($this->itemIterator->key(), $this->itemIteratorTotal);
@@ -423,6 +420,7 @@ function getInjectedValue($property, $params, $cast = true) {
return $res;
}
+
}
function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {

0 comments on commit 792c89e

Please sign in to comment.