Everything a developer changes on a Core dna site lives in its theme repository. This guide covers the repository and its build, printing records in templates, stylesheets and client-side code, and the parts of a site around the main content.
L1–L2
Unit 02 · Records in templates
Relations and collections
Records in templatesPage 12 of 35Updated
A getter that returns several records returns a collection you can loop, filter, sort and slice in the template. What each collection method does, the loose matching and the sorting fault to know about, and why filtering in the template is convenient but expensive.
Who this is for. The theme developer listing related records: a page's children, a blog's posts, a product's categories. Afterwards you can work with a collection in either engine, know which of its methods can surprise you, and decide when to ask the database for the list instead.
What a collection is
A getter that returns several records, such as getChildren() on a page or getCategories() on a product, returns a collection of response models. It loops like an array in both engines, and it has methods of its own. Each method that returns a collection returns a new one; the original is unchanged.
Method
What it returns
count()
The number of records
first(), last()
The first or last record, or nothing
get(2)
The record at that position, counting from 0
find(42)
The record with that id, or nothing
filtered('featured', true)
The records whose property equals the value; a list of values matches any of them; '!NULL' matches any value that is set, an empty string included
{% set featured = page.getChildren().filtered('published', '!NULL').slice(0, 3) %}
{% for child in featured %}
<a href="{{ child.getFullPath() }}">{{ child.getName()|e }}</a>
{% else %}
<p>No pages yet.</p>
{% endfor %}
In Smarty, write the conditions of filteredBy() as an array literal: ['featured' => true, 'category.slug' => 'news'].
Two things that surprise people
Matching is loose.filtered() and filteredBy() compare with PHP's ==, so filtered('parent', null) also matches 0, false, '' and an empty list, and filtered('featured', true) matches any value that is not empty. Filter on the value you mean, or use '!NULL'.
Equal values sort out of place.sorted() keeps its records in a map keyed by the sort value, and when two records have the same value it appends a digit to the second key to keep it unique. The changed key then sorts as a different value: of two posts published in the same second, one moves to the end of an ascending list; a duplicated price of 10 sorts as 100. Sort on a property whose values are unique, or ask for the list already sorted (below).
Convenient, and expensive
Every collection method works in memory, on a list that has already been loaded in full. getPosts() on a blog loads every post before filtered() throws most of them away and slice() keeps three. For anything beyond a short list, ask for exactly what you need with _query, filtered, sorted and limited by the database:
{% for post in _query.findBy('Blogs\\Entities\\Post', {'blog': blog.getId()}, {'published': 'DESC'}, 3) %}
<a href="{{ post.getFullPath() }}">{{ post.getName()|e }}</a>
{% endfor %}
In Twig the backslashes of the class name are doubled inside the string; a single backslash is dropped. The arguments are the entity, the criteria, the order, the limit and an optional offset.