Содержание
Чтение записей
В данном разделе описаны методы класса cmsModel, позволяющие извлекать записи из базы данных.
Все примеры кода подразумевают, что действие происходит в контексте модели (т.е. внутри класса вашей модели, унаследованного от cmsModel).
Вы должны иметь представление о работе SQL-запросов для полного понимания описанных здесь методов.
Одна строка
Получить одну строку из таблицы в базе можно несколькими методами, в зависимости от условий, по которым будет происходить поиск строки.
Все методы возвращают массив, содержащий в себе поля полученной записи, либо false, если запись не найдена.
Получение строки по id
getItemById($table_name, $id, $item_callback=false)
$table_name | Название таблицы, без префикса |
$id | Значение поля id искомой строки |
$item_callback | Анонимная функция для обработки результата (см. раздел «Обработка строк» ниже) |
Пример:
$comment = $this->getItemById('comments', $comment_id);
Получение строки по значению поля
getItemByField($table_name, $field_name, $field_value, $item_callback=false)
$table_name | Название таблицы, без префикса |
$field_name | Название поля, по которому происходит поиск строки |
$field_value | Значение поля в искомой строке |
$item_callback | Анонимная функция для обработки результата (см. раздел «Обработка строк» ниже) |
Пример:
$comment = $this->getItemByField('comments', 'is_deleted', 1);
Получение строки по условиям фильтров
getItem($table_name, $item_callback=false)
$table_name | Название таблицы, без префикса |
$item_callback | Анонимная функция для обработки результата (см. раздел «Обработка строк» ниже) |
Условия задаются с помощью фильтров (см. раздел Фильтрация).
Пример:
$comment = $this-> filterEqual('is_deleted', 0)-> filterLike('content', '%текст%')-> getItem('comments');
Набор строк
Получение нескольких строк
Для извлечения нескольких строк из таблицы (или нескольких связанных таблиц) используется метод:
get($table_name, $item_callback=false, $key_field='id')
$table_name | Название таблицы, без префикса |
$item_callback | Анонимная функция для обработки результата (см. раздел «Обработка строк» ниже) |
$key_field | Поле, значения которого будут использовать как ключи для массива с результатами. Если указать false, то массив будет пронумерован простым способом, от нуля |
Пример:
$all_comments = $this->get('comments');
При таком вызове массив $all_comments будет содержать в себе все строки из таблицы comments. Вы можете ограничить результаты по условиям и количеству. См. ниже.
Получение количества строк
Чтобы узнать сколько строк вернет метод get() перед его вызовом можно вызвать метод:
getCount($table_name, $by_field='id')
$table_name | Название таблицы, без префикса |
$by_field | По какому полю считать количество строк |
Метод возвращает число.
Пример:
$comments_count = $this->getCount('comments');
При подсчете учитываются все фильтры, установленные ранее (см. раздел Фильтрация).
Обработка строк
Строки, полученные из базы при помощи любого из методов getItem() и get() могут быть обработаны перед возвратом. Обработчик определяется с помощью анонимной функции, передаваемой как параметр $item_callback:
function($item, $model) { }
На вход функция получает два параметра:
$item | Массив с данными текущей строки |
$model | Экземпляр текущей модели |
Функция может обработать поля в массиве $item или добавить новые. Затем она должна вернуть массив обратно:
$items = $this->get('my_table', function($item, $model){ $item['date'] = date('d.m.Y', strtotime($item['date'])); return $item; });
В этом примере обработчик используется чтобы привести поле date в каждой записи к нужному формату. В реальности, конечно, так делать не нужно, поскольку форматирование даты – задача шаблона.
Чаще всего такой обработчик используется для парсинга сложных полей. Например, если при сохранении записи в базу (об этом в разделе ниже) одно из полей записи будет содержать массив, то он будет автоматически преобразован в формат YAML и сохранен как текст. При извлечении такой записи нужно вручную сделать обратное преобразование.
Пример. Допустим, у нас есть таблица my_table с полями id
(int), title
(varchar), options
(text). Мы добавляем запись в эту таблицу так, чтобы поле options
хранило в себе сразу несколько значений:
$new_item = array( 'title' => 'Новая запись', 'options' => array( 'first' => 1, 'second' => 2 ) ); $new_item_id = $this->insert('my_table', $new_item);
Затем мы извлекаем эту запись обратно:
$loaded_item = $this->getItemById('my_table', $new_item_id);
В этом случае можно ожидать что массивы $new_item и $loaded_item будут одинаковыми. Однако, это не так. В массиве $loaded_item поле options
будет уже текстовым, а не вложенным подмассивом. Поэтому, мы должны преобразовать его обратно в массив. Сделать это можно с помощью обработчика:
$loaded_item = $this->getItemById('my_table', $new_item_id, function($item, $model){ $item['options'] = cmsModel::yamlToArray($item['options']); return $item; });
Метод yamlToArray() преобразует текст в формате YAML обратно в массив. И в этом примере мы получим на выходе точно такой же массив, как и на входе.
Для метода get() обработчик работает точно так же, с той лишь разницей, что обрабатывается не одна строка, а все полученные по-очереди.
Отдельные поля
Поле из строки с известным ID
Для получения значения определенного поля конкретной строки в таблице можно использовать метод:
getField($table_name, $row_id, $field_name)
$table_name | Название таблицы, без префикса |
$row_id | Значение поля id искомой строки |
$field_name | Название поля, значение которого нужно получить |
Пример – получим дату создания комментария с ID=35:
$pub_date = $this->getField('comments', 35, 'pub_date');
Поле из строки по условию
Вместо указания конкретного ID строки можно использовать набор из одного или нескольких фильтров. Для получения значения поля из строки, отобранной фильтрами, используется метод:
getFieldFiltered($table_name, $field_name)
Если примененные фильтры возвращают больше одной строки, то будет возвращено указанное поле из первой строки в наборе результатов.
Пример – получим ID комментария созданного администратором в указанный день:
$id = $this-> filterEqual('user_id', 1)-> filterEqual('pub_date', '2014-12-03')-> getFieldFiltered('comments', 'id');
Фильтрация
При чтении записей модель может применять различные фильтры, подробно описанные здесь.
Сортировка
Перед извлечением строк с помощью метода get() модель может установить порядок их сортировки.
По одному полю
orderBy($field, $direction)
$field | Название поля, по которому сортировать результат |
$direction | Направление сортировки – asc (по возрастанию) или desc (по убыванию) |
Пример – получим список всех пользователей, отсортировав их по убыванию даты регистрации (от новых к старым):
$users = $this->orderBy('date_reg', 'desc')->get('{users}');
Как видно из примера, метод orderBy поддерживает «цепочки вызовов», т.е. сразу после него мы можем вызвать любой другой метод объекта $this.
По нескольким полям
orderByList($list)
$list | Массив условий сортировки. Каждое условие также задается массивом, с полями by (поле) и to (направление) |
Пример – получим все комментарии, отсортировав их по рейтингу и дате:
$ordering = array( array('by' => 'rating', 'to' => 'desc'), array('by' => 'pub_date', 'to' => 'desc'), ); $comments = $this->orderByList($ordering)->get('comments');
Лимиты
Перед извлечением строк с помощью метода get() модель может ограничить количество желаемых результатов.
limit($from, $howmany=15)
$from | Номер строки в результатах запроса, начиная с которой будут отобраны строки попавшие в финальный результат |
$howmany | Максимальное количество строк в финальном результате |
Данный метод работает аналогично условию LIMIT
в SQL-запросах. Рассмотрим на примере. Допустим, мы создаем запрос, в результате которого из базы возвращается 100 строк. Если перед запросом мы укажем лимит:
$this->limit(5, 10);
то в результатах мы будем иметь не все 100 строк, а только 10 (с 5-й по 15-ю).
Для постраничного разбиения списка записей необходимо вычислять номер начальной строки для каждой страницы. Чтобы не делать этого в ручную можно использовать метод:
limitPage($page, $perpage=15);
$page | Номер текущей страницы |
$perpage | Максимальное количество строк на одной странице |
Например, такой лимит:
$this->limitPage(3, 10);
вернет строки с 21-й по 30-ю включительно.
Пример – получим последние 10 комментариев (по дате):
$latest_comments = $this->orderBy('pub_date', 'desc')->limit(10)->get('comments');
Присоединения
При извлечении записей с помощью метода get() модель может обращаться к нескольким таблицам в базе данных одновременно, соединяя их. Это происходит аналогично тому, как работают JOIN-условия в SQL-запросах.
Доступно несколько методов:
join($table_name, $as, $on)
joinLeft($table_name, $as, $on)
joinLeftInner($table_name, $as, $on)
joinLeftOuter($table_name, $as, $on)
joinRight($table_name, $as, $on)
joinRightInner($table_name, $as, $on)
joinRightOuter($table_name, $as, $on)
joinInner($table_name, $as, $on)
joinOuter($table_name, $as, $on)
$table_name | Название таблицы, без префикса |
$as | Псевдоним (alias) присоединяемой таблицы |
$on | Условие присоединения |
Каждый из методов добавляет соответствующий JOIN в генерируемый SQL-запрос. Вызываться эти методы должны перед непосредственным получением результатов, т.е. до вызова метода get().
Параметр $as задает псевдоним (альяс, алиас) присоединяемой таблицы, обычно это просто первая буква (или несколько букв) названия.
Параметр $on описывает условие присоединения (связь таблиц) в SQL-формате. При этом считается, что исходная таблица имеет альяс i
.
После того, как связь таблиц определена, необходимо указать какие поля из присоединенной таблицы вы хотите видеть в результатах запроса. Для этого используется метод:
select($field, $as)
$field | Название поля в присоединяемой таблице. Указывается вместе с альясом, в формате: альяс.поле |
$as | Название поля в результатах запроса |
Рассмотрим пример. В базе есть таблица menu, содержащая список доступных на сайте меню (главное, боковое, нижнее и т.п.). В таблице menu_items хранятся пункты этих меню. У каждого пункта в таблице menu_items есть поле menu_id, содержащее id меню, которому этот пункт принадлежит.
Предположим, мы хотим получить список всех пунктов меню и для каждого пункта нам нужно название меню:
// присоединяем таблицу menu // задаем для нее альяс "m" // исходная таблица имеет альяс "i" $this->join('menu', 'm', 'm.id = i.menu_id'); // мы хотим добавить поле title (название меню) из таблицы menu в результаты // но, поскольку в таблице menu_items тоже есть поле title (название пункта), // мы будем использовать другое имя - menu_title $this->select('m.title', 'menu_title'); // получаем результат - пункты из menu_items $menu_items = $this->get('menu_items'); // теперь мы можем перебрать все пункты меню foreach($menu_items as $item){ // и у каждого из них будет доступно поле menu_title // полученное из присоединенной таблицы echo $item['menu_title']; }
Дальше, к разделу Изменение записей
Дальше, к разделу Фильтрация
Назад, к оглавлению раздела "Модели"