Each entity selection is returned as an instance implementing
Nextras\Orm\Collection\ICollection
interface.
ICollection
extends \Traversable
interface and adds
other API to do further operations with the collection.
In Orm, we use coding standard which assumes, that
get*
methods return an IEntity
instance or
a null,find*
methods return a ICollection
instance.Collection itself is immutable, all methods that modify the collection
return a new ICollection
instance. Collection provides the
following methods:
getBy(array $conds): ?IEntity
– applies additional filtering
and returns the first result's entity or a null,findBy(array $conds): ICollection
– applies additional
filtering,orderBy($column, $direction): ICollection
– applies
additional ordering,resetOrderBy(): ICollection
– removes all defined
ordering,limitBy($limit, $offset): ICollection
– limits the
collection, optionally sets the starting offset,fetch(): ?IEntity
– returns the unfetched result's entity,
repeated calls iterate over the whole result set,fetchAll(): IEntity[]
– returns the whole result's entities
as an array,fetchPairs($key, $value): array
– process the whole result
and returns it as an array. The first argument accepts a property name that will
be used as an key. If a null is provided, the result array will be indexed
naturally (from zero). The second argument accepts a property name that will be
used as a value. If a null is provided, the whole entity will be used as
the value.// all book entities indexed by their primary key
$orm->books
->findAll()
->fetchPairs('id', null);
// all books' titles sorted backward and naturally indexed
$orm->books
->findAll()
->orderBy('title', ICollection::DESC)
->fetchPairs(null, 'title');
Each collection can be filtered by an array of conditions. These conditions
are passed as a parameter of the findBy()
method. The array
consists of entity property names and values. Keys can contain an optional
operator. The default operator is equality. Let's see the example:
$books = $orm->books->findBy([
'author' => $author->id,
'publishedAt<=' => new DateTimeImmutable(),
]);
Allowed operators are =
, !=
, <=
,
<
, >=
and >
.
You can filter the collection using conditions using entity relationshpis. To
filter collection by a relationship, use a traversing expression: it
consists of the path delimited by ->
– an arrow. You have to
start the expression by referencing the starting point using this
keyword.
// find all books which were authored by Jon Snow
$orm->books->findBy(['this->author->name' => 'Jon Snow']);
// find all books which were not translated by Jon Snow
$orm->books->findBy(['this->translator->name!=' => 'Jon Snow']);
The described syntax may be expanded to support a OR
logical
conjunction. Unshift the operator ICollection::OR
as a first value
of the query array:
// finds all books which were authored od translated by one specific person
$books = $orm->books->findBy([
ICollection::OR,
'author' => $person->id,
'translator' => $person->id,
]);
You may nest the query array structure; use the same syntax repeatedly:
// find all man older than 10 years and woman younger than 10 years
$books = $orm->author->findBy([
ICollection::OR,
[
ICollection::AND,
'age>=' => 10,
'sex' => 'male',
],
[
ICollection::AND,
'age<=' => 10,
'sex' => 'female',
],
]);
The previous example can be shortened because the AND
operator
is the default logical conjunction.
// find all man older than 10 years and woman younger than 12 years
$books = $orm->author->findBy([
ICollection::OR,
[
'age>=' => 10,
'gender' => 'male',
],
[
'age<=' => 12,
'gender' => 'female',
],
]);
There are few restrictions:
You can easily sort the collection by orderBy()
method, which
accepts the property name and the sorting direction. By default, columns are
sorted in an ascending order. To change the order, use
ICollection::ASC
or ICollection::DESC
constants.
$orm->books->findAll()->orderBy('title', ICollection::DESC);
You can add more ordering rules that will be used if the previously defined
ordering properties will be evaluated as the same. The sorting may be reset by
resetOrderBy()
method.
To limit the data collection, just use limitBy()
method.
// get the last 10 published books
$orm->books->findAll()->orderBy('publishedAt', ICollection::DESC)->limitBy(10);
// get the 10 penultimate published books
$orm->books->findAll()->orderBy('publishedAt', ICollection::DESC)->limitBy(10, 10);
It is easy to count entities returned in a collection. There are two methods:
count()
fetches the entities from the storage and counts them
in PHP,countStored()
asks the storage for the collection count; the
implementation depends on the mapper layer, basically, the
countStored()
method runs an SQL query.The count()
method is quite useful if you know that you will
need the fetched entities in the collection. The countStored()
is
needed if you do a pagination, etc.
public function renderArticles($categoryId)
{
$articles = $this->orm->articles->findBy(['category' => $categoryId]);
$limit = 10;
$offset = $this->page * 10;
$this->paginator->totalCount = $articles->countStored();
$this->template->articles = $articles->limitBy($limit, $offset);
}
{if $articles->count()}
{foreach $articles} ... {/foreach}
{else}
You have no articles.
{/if}