====== Поиск и сортировка объектов. find()-методы lmbActiveRecord ======
В разделе [[crud|"Создание, сохранение, загрузка и удаление объектов"]] мы упоминали про загрузку объектов класса lmbActiveRecord через статические find-методы. Познакомимся с ними поближе.
===== Поиск объектов через статические find() методы =====
lmbActiveRecord содержит набор статических методов, которые можно использовать для загрузки объектов из базы данных:
- **find($class_name, $params = array())** - самый общий метод, используется для загрузки группы объектов (в виде списка, или итератора) .
- **findFirst($class_name, $params = array())** - используется для загрузки первого найденного объекта.
- **findOne($class_name, $params = array())** - алиас для findFirst().
- **findById($class_name, $id, $throw_exception = true)** - используется для загрузки только одного объекта с указанным идентификатором.
- **findByIds($class_name, $ids, $params = array())** - используется для загрузки определенных объектов, если известны их идентификаторы.
Методы find() и findByIds() возвращают итераторы, то есть объекты, поддерживающие интерфейс [[limb3:ru:packages:core:lmb_collection_interface|lmbCollectionInterface]], где каждый элемент выборки - объект %%ActiveRecord%% указанного в $class_name класса (или его дочернего, о чем будет рассказано в разделе [[inheritance|"Поддержка наследования"]]).
Для более сложных случаев, можно выполнять свои sql-запросы, получая при этом объекты %%ActiveRecord%%. О том, как это сделать, см. страницу [[sql_exec|Создание новых find()-методов. Выполнение своих sql-запросов.]]
Обратите внимание, что до момента использования итератора для получения данных(до вызова метода rewind()), запрос к базе данных еще не будет произведен, что позволяет производить некоторые модификации с sql-кодом уже после создания итератора, например, указывать параметры сортировти, ограничивать размер выборки и т.д. Об этом будет сказано ниже.
Методы findByid(), findFirst, (а также find() в некоторых случаях, о которых упонянуто ниже) возвращают единичные объекты. findById() имеет одну особенность: если запись с указанным идентификатором не будет найдена, также будет сгенерировано исключение класса lmbARNotFoundException, как и в случае передачи идентификатора в конструктор. Если вы не желаете получать исключения, тогда используейте третий параметр $throw_exception = false, например:
$user = lmbActiveRecord :: findById('User', $user_id, $throw_exception = false);
Если вы заметили, большинство find()-методов имеют в качестве агрумента массив **$params**. Массив $params может содержать различные значения, которые накладывают различные модификации на выборку, например:
* **criteria** - накладывает условие на выборку. В качестве значения может выступать строки или объект Criteria.
* **offset**, **limit** - позволяет ограничить размер выборки из базы данных.
* **sort** - позволяет указать порядок сортировки объектов при выборки из базы данных.
* **first** - позволяет выбрать только один объект.
Мы рассмотрим подробнее применение этих параметров чуть ниже.
===== Наложение условий на выборки =====
Для наложения условий на выборки можно воспользоваться параметром **criteria** в массиве $params:
* **$users = lmbActiveRecord :: find('User', array('criteria' => "salary > 20000"));** - здесь в качестве условия выборки использована обычная строка.
* **$users = lmbActiveRecord :: find('User', array('criteria' => new lmbSqlRawCriteria("name", "Vasa"));** - теперь в качестве criteria - объект из набора [[limb3:ru:packages:dbal:criteria|Criteria]]
Если же кроме criteria никаких параметров использовать не предполагается, можно передать в find() метод только условие на выборку, например:
* **$users = lmbActiveRecord :: find('User', "salary > 20000")** - передается только условие выборки в виде строки без дополнительных параметров
* **$users = lmbActiveRecord :: find('User', array("name=? AND salary > ?", 'Bob', 200))** - передается условие выборки в виде массива, где первым элементом является строка с маркерами "?", которые будут заменены последовательно следующими элементами массива. Этот способ автоматически экранирует аргументы, подставляемые в маркеры.
* **$users = lmbActiveRecord :: find('User', new lmbSqlRawCriteria("name", "Vasa"))** - тоже самое, но теперь условием выборки является объект [[limb3:ru:packages:dbal:criteria|Criteria]]
* **$user = lmbActiveRecord :: find('User', $user_id = 10)** - вернет //одного// пользователя (единичный объект, а не итератор).
===== Ограничение размера выборки =====
При помощи метода **paginate($offset, $limit)** итератора, получаемого из find() метода, можно ограничить размер выборки, например:
$users = lmbActiveRecord :: find('User');
$users->paginate($offset = 0, $limit = 10); // Будет выбрано 10 первых пользователей
Тот же самый эффект можно получить путем передачи параметров **offset** и **limit** в массиве $params, который передается в качестве второго аргумента в метод find(), например:
$users = lmbActiveRecord :: find('User', array('offset' => 0, 'limit' => 10));
Если offset равен нулю, тогда в этом случае это можно опускать, то есть:
$users = lmbActiveRecord :: find('User', array('limit' => 10));
Того же эффекта можно достичь, использя метод paginate() у итератора, получаемого из find()-метода, например эти два куска кода эквивалентны:
$users = lmbActiveRecord :: find('User', array('offset' => 10, 'limit' => 10));
$users = lmbActiveRecord :: find('User');
$users->paginate($offset = 10, $limit = 10);
Для возврата только первого объекта можно использовать параметр **first**, например:
$user = lmbActiveRecord :: find('User', array('first')); // Будет выбран только первый пользователь
Использование параметра first эквивалентно вызову другого статического метода **lmbActiveRecord :: findFirst()**.
===== Сортировка объектов при загрузке =====
В массив $params find()-методов можно передавать параметр **sort**, который позволяет установить порядок сортировки объектов при разрузке. sort - это массив вида ('поле1' => 'тип сортировки1', 'поле2' => 'тип сортировки2'), например:
$user = lmbActiveRecord :: find('User', array('sort' => array('name' => 'DESC', 'last_name' => 'ASC')));
==== Сортировка по-умолчанию ====
Если параметры сортировки в find()-методе не указаны, тогда в выборках применяются параметры сортировки по-умолчанию.
Параметры сортировки по-умолчанию задаются в классе через защищенный атрибут **$_default_sort_params**. В классе lmbActiveRecord он прописан как array(’id’ ⇒ ‘ASC’), то есть при выборках элементы всегда сортируются по идентификатору.
Вы можете указать другие параметры сортировки по-умолчанию:
class User extends lmbActiveRecord
{
protected $_default_sort_params = array('last_name' => 'ASC');
}
==== Сортировка после получения итератора ====
Параметры сортировки можно применять и после создания итератора, для этого можно использовать метод sort($params), например, эти два куска кода эквивалентны:
$users = lmbActiveRecord :: find('User', arary('sort' => array('name' => 'DESC'));
$users = lmbActiveRecord :: find('User');
$users->sort(array('name' => 'DESC'));
При вызове метода sort() ранее установленные параметры сортировки (например, параметры сортировки по-умолчанию) будут изменены на новые.
==== Дополнительные методы при работе с полученными итераторами ====
Возможно накладывать множественные изменения на итераторы до итерации, например:
$rs = lmbActiveRecord :: find(..);
$rs->sort(array('id' => 'desc'))->paginate(1, 2);
Для получения количества элементов в итераторе используется метод **count()**:
$rs->count();
Для получения объекта по определенной позиции в выборке можно использовать метод **at($position)**:
$users = lmbActiveRecord :: find('User');
$user = $users->at($position = 2);
Обратите внимание, что каждый вызор at() приводит к отдельному запросу к базе данных и эквивалентен по сути вызову метода paginate($offset = $position, $limit = 1);