Collections
Collections (opens new window) come from the Laravel (opens new window) ecosystem, and provide a fluid way of working with array-like data.
You can create a Collection
anywhere:
Collections can be used in most situations that an array would be:
<ul>
{% for color in colors %}
{# `color` is one of our original three strings: #}
<li>{{ color }}</li>
{% endfor %}
</ul>
# Methods
Dozens of convenience methods (opens new window) are available on every collection to simplify cumbersome or error-prone operations.
These methods can be chained together to process data in an elegant way. Take this average review score logic:
{% set recentReviews = craft.entries()
.section('reviews')
.relatedTo({
targetElement: product,
})
.postDate(">= #{now|date_modify('-1 month')}")
.collect() %}
{{ recentReviews.pluck('rating').average() }}
Not all Collection methods return another Collection! In this example, .pluck()
(opens new window) does (containing just the rating
field values), but .average()
(opens new window) doesn’t (instead returning a float (opens new window)). As Collections are intended for working with lists, methods that return scalar values can only be used at the “end” of a chain.
Some common array-manipulation features are already implemented in Craft as Twig filters or functions, but equivalent methods are usually available via Collections. Their supported arguments and signatures may differ slightly, so consult the documentation if you are combining or switching between features.
One common problem, however, is that Twig’s default configuration does not parse anonymous functions or “closures” in every expression context. The nystudio107/craft-closure
package (opens new window) provides a shim to work around this limitation.
# Element Queries
Use the .collect()
query execution method (in place of .all()
) to return elements as a craft\elements\ElementCollection (opens new window). You can also wrap an existing list of elements in a regular Collection
with the same collect()
function we used, earlier:
{# These produce similar results: #}
{% set posts = craft.entries().section('news').collect() %}
{% set posts = collect(craft.entries().section('news').all()) %}
Eager-loaded elements are also wrapped in an ElementCollection
that allows them to behave a bit like an element query, so you can safely call .all()
on any relational field without worrying about whether it was eager-loaded or not—or use .with()
to eager-load another set of nested elements!