2012-06-23 00:32:43 +02:00
|
|
|
# Grouping lists of records
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-07-03 03:22:12 +02:00
|
|
|
The [SS_List](api:SilverStripe\ORM\SS_List) class is designed to return a flat list of records.
|
2012-06-23 00:32:43 +02:00
|
|
|
These lists can get quite long, and hard to present on a single list.
|
2016-01-14 11:59:53 +01:00
|
|
|
[Pagination](/developer_guides/templates/how_tos/pagination) is one way to solve this problem,
|
2012-06-23 00:32:43 +02:00
|
|
|
by splitting up the list into multiple pages.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
In this howto, we present an alternative to pagination:
|
2017-07-03 03:22:12 +02:00
|
|
|
Grouping a list by various criteria, through the [GroupedList](api:SilverStripe\ORM\GroupedList) class.
|
|
|
|
This class is a [ListDecorator](api:SilverStripe\ORM\ListDecorator), which means it wraps around a list,
|
2012-06-23 00:32:43 +02:00
|
|
|
adding new functionality.
|
|
|
|
|
|
|
|
It provides a `groupBy()` method, which takes a field name, and breaks up the managed list
|
|
|
|
into a number of arrays, where each array contains only objects with the same value of that field.
|
|
|
|
Similarly, the `GroupedBy()` method builds on this and returns the same data in a template-friendly format.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
## Grouping Sets By First Letter
|
|
|
|
|
2017-07-03 03:22:12 +02:00
|
|
|
This example deals with breaking up a [SS_List](api:SilverStripe\ORM\SS_List) into sub-headings by the first letter.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
Let's say you have a set of Module objects, each representing a SilverStripe module, and you want to output a list of
|
|
|
|
these in alphabetical order, with each letter as a heading; something like the following list:
|
|
|
|
|
|
|
|
* B
|
|
|
|
* Blog
|
|
|
|
* C
|
|
|
|
* CMS Workflow
|
|
|
|
* Custom Translations
|
|
|
|
* D
|
|
|
|
* Database Plumber
|
|
|
|
* ...
|
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The first step is to set up the basic data model,
|
|
|
|
along with a method that returns the first letter of the title. This
|
2011-02-07 07:48:44 +01:00
|
|
|
will be used both for grouping and for the title in the template.
|
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```php
|
2017-10-27 04:38:27 +02:00
|
|
|
use SilverStripe\ORM\DataObject;
|
|
|
|
|
|
|
|
class Module extends DataObject
|
|
|
|
{
|
|
|
|
private static $db = [
|
|
|
|
'Title' => 'Text'
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the first letter of the module title, used for grouping.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getTitleFirstLetter()
|
2017-08-07 05:11:17 +02:00
|
|
|
{
|
2017-10-27 04:38:27 +02:00
|
|
|
return $this->Title[0];
|
2017-08-07 05:11:17 +02:00
|
|
|
}
|
2017-10-27 04:38:27 +02:00
|
|
|
}
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The next step is to create a method or variable that will contain/return all the objects,
|
|
|
|
sorted by title. For this example this will be a method on the `Page` class.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```php
|
2017-10-27 04:38:27 +02:00
|
|
|
use SilverStripe\CMS\Model\SiteTree;
|
|
|
|
use SilverStripe\ORM\GroupedList;
|
|
|
|
|
|
|
|
class Page extends SiteTree
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Returns all modules, sorted by their title.
|
|
|
|
* @return GroupedList
|
|
|
|
*/
|
|
|
|
public function getGroupedModules()
|
2017-08-07 05:11:17 +02:00
|
|
|
{
|
2017-10-27 04:38:27 +02:00
|
|
|
return GroupedList::create(Module::get()->sort('Title'));
|
2017-08-07 05:11:17 +02:00
|
|
|
}
|
2017-10-27 04:38:27 +02:00
|
|
|
}
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The final step is to render this into a template. The `GroupedBy()` method breaks up the set into
|
|
|
|
a number of sets, grouped by the field that is passed as the parameter.
|
|
|
|
In this case, the `getTitleFirstLetter()` method defined earlier is used to break them up.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```ss
|
2017-10-27 04:38:27 +02:00
|
|
|
<%-- Modules list grouped by TitleFirstLetter --%>
|
|
|
|
<h2>Modules</h2>
|
|
|
|
<% loop $GroupedModules.GroupedBy(TitleFirstLetter) %>
|
|
|
|
<h3>$TitleFirstLetter</h3>
|
|
|
|
<ul>
|
|
|
|
<% loop $Children %>
|
|
|
|
<li>$Title</li>
|
|
|
|
<% end_loop %>
|
|
|
|
</ul>
|
|
|
|
<% end_loop %>
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2011-02-07 07:48:44 +01:00
|
|
|
|
|
|
|
## Grouping Sets By Month
|
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
Grouping a set by month is a very similar process.
|
|
|
|
The only difference would be to sort the records by month name, and
|
|
|
|
then create a method on the DataObject that returns the month name,
|
2017-07-03 03:22:12 +02:00
|
|
|
and pass that to the [GroupedList::GroupedBy()](api:SilverStripe\ORM\GroupedList::GroupedBy()) call.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
We're reusing our example `Module` object,
|
|
|
|
but grouping by its built-in `Created` property instead,
|
|
|
|
which is automatically set when the record is first written to the database.
|
|
|
|
This will have a method which returns the month it was posted in:
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```php
|
2017-10-27 04:38:27 +02:00
|
|
|
use SilverStripe\ORM\DataObject;
|
|
|
|
|
|
|
|
class Module extends DataObject
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Returns the month name this news item was posted in.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getMonthCreated()
|
2017-08-07 05:11:17 +02:00
|
|
|
{
|
2017-10-27 04:38:27 +02:00
|
|
|
return date('F', strtotime($this->Created));
|
2017-08-07 05:11:17 +02:00
|
|
|
}
|
2017-10-27 04:38:27 +02:00
|
|
|
}
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
The next step is to create a method that will return all records that exist,
|
|
|
|
sorted by month name from January to December. This can be accomplshed by sorting by the `Created` field:
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```php
|
2017-10-27 04:38:27 +02:00
|
|
|
use SilverStripe\CMS\Model\SiteTree;
|
|
|
|
use SilverStripe\ORM\GroupedList;
|
|
|
|
|
|
|
|
class Page extends SiteTree
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Returns all news items, sorted by the month they were posted
|
|
|
|
* @return GroupedList
|
|
|
|
*/
|
|
|
|
public function getGroupedModulesByDate()
|
2017-08-07 05:11:17 +02:00
|
|
|
{
|
2017-10-27 04:38:27 +02:00
|
|
|
return GroupedList::create(Module::get()->sort('Created'));
|
2017-08-07 05:11:17 +02:00
|
|
|
}
|
2017-10-27 04:38:27 +02:00
|
|
|
}
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2017-07-03 03:22:12 +02:00
|
|
|
The final step is the render this into the template using the [GroupedList::GroupedBy()](api:SilverStripe\ORM\GroupedList::GroupedBy()) method.
|
2011-02-07 07:48:44 +01:00
|
|
|
|
2017-08-03 00:46:55 +02:00
|
|
|
```ss
|
2017-10-27 04:38:27 +02:00
|
|
|
// Modules list grouped by the Month Posted
|
|
|
|
<h2>Modules</h2>
|
|
|
|
<% loop $GroupedModulesByDate.GroupedBy(MonthCreated) %>
|
|
|
|
<h3>$MonthCreated</h3>
|
|
|
|
<ul>
|
|
|
|
<% loop $Children %>
|
|
|
|
<li>$Title ($Created.Nice)</li>
|
|
|
|
<% end_loop %>
|
|
|
|
</ul>
|
|
|
|
<% end_loop %>
|
2017-08-03 00:46:55 +02:00
|
|
|
```
|
2017-10-27 04:38:27 +02:00
|
|
|
|
2012-06-23 00:32:43 +02:00
|
|
|
## Related
|
|
|
|
|
2016-01-14 11:59:53 +01:00
|
|
|
* [Howto: "Pagination"](/developer_guides/templates/how_tos/pagination)
|