====== Поиск и сортировка объектов. 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);