Top Banner
7/13/12 ORM — Русская документация Kohana 3 1/12 kohana3.ru/module/orm Поиск ORM Одним из самых важных модулей Kohana является ORM, неотъемлемая часть любого серьезного фреймворка. ORM [http://ru.wikipedia.org/wiki/ORM] позволяет представить работу с базой данных как взаимодействие объектов, выкидывая из кода большинство операций чтения, удаления, создания и изменения данных. ORM в Kohana Реализация ORM в Kohana позволяет представить запись из базы данных в виде экземпляра объекта, который имеет различные методы взаимодействия, такие как изменение, сохранение, удаление и некоторые другие. Помимо того, с помощью незагруженного (пустого) экземпляра объекта может производится поиск (загрузка) одной или нескольких записей. Каждый объект представляется в виде PHP‑ класса, унаследованного от класса ORM и должен располагаться в папке classes/model/ . Конфигурация ORM не имеет общих для себя настроек, и нуждается только в подключении себя из папки модулей, более подробно об этом написано в руководстве по настройке . Также, не забудьте подключить модуль Database, он является обязательным для использования ORM. Стандарты именования Рекомендуется соблюдать следующие стандарты именования таблиц, полей и классов при работе с ORM: Название модели должно быть в единственном числе. Например, Model_Post , Model_Category , Model_User_Token . Однако, существуют некоторые исключения, связанные с особенностью английского языка, например, Model_News . Название таблицы должно быть во множественном числе. К примеру, posts , categories , users_tokens . Название полей, предназначенных для связи с другими таблицами, должны быть в единственном числе и оканчиваться на _id . Например, не post.category , а post.category_id , не token.user , а token.user_id , не product.default_photo , а product.default_photo_id . Базовое использование Базовое использование подразумевает простейшие действия с объектами — чтение, изменение, запись. Определение модели Чтобы определить модель ORM, создайте в папке classes/module класс, унаследованный от ORM : class Model_City extends ORM { } На этом, формально, создание модели можно окончить. Остальные настройки (название таблицы, первичный ключ, названия столбцов и т.д. Kohana сгенерирует сама, исходя из названия модели (в данном случае, это — city ). Тем не менее, мы рассмотрим их далее. Название таблицы Название таблицы хранится во внутреннем параметре объекта _table_name : protected $_table_name = 'custom_table'; Первичный ключ Названия поля первичного ключа находится в параметре _primary_key и по умолчанию оно установлено в id : protected $_primary_key = 'custom_pk'; Первичные ключи, состоящие из нескольких полей, в данный момент не поддерживаются. Их реализация должна появиться с выходом Kohana 3.3 База данных По умолчанию используется стандартная БД, но это можно поменять в параметре _db_group :
12

ORM — Русская документация Kohana 3

Jul 29, 2015

Download

Documents

thang1009

KOHANA Guide in Russian
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

1/12kohana3.ru/module/orm

Поиск

ORM

Одним из самых важных модулей Kohana является ORM, неотъемлемая часть любого серьезного фреймворка. ORM[http://ru.wikipedia.org/wiki/ORM] позволяет представить работу с базой данных как взаимодействие объектов, выкидывая из кодабольшинство операций чтения, удаления, создания и изменения данных.

ORM в Kohana

Реализация ORM в Kohana позволяет представить запись из базы данных в виде экземпляра объекта, который имеет различные методывзаимодействия, такие как изменение, сохранение, удаление и некоторые другие. Помимо того, с помощью незагруженного (пустого)экземпляра объекта может производится поиск (загрузка) одной или нескольких записей. Каждый объект представляется в виде PHP‑класса, унаследованного от класса ORM и должен располагаться в папке classes/model/.

Конфигурация

ORM не имеет общих для себя настроек, и нуждается только в подключении себя из папки модулей, более подробно об этом написанов руководстве по настройке. Также, не забудьте подключить модуль Database, он является обязательным для использования ORM.

Стандарты именования

Рекомендуется соблюдать следующие стандарты именования таблиц, полей и классов при работе с ORM:

Название модели должно быть в единственном числе. Например, Model_Post, Model_Category,Model_User_Token. Однако, существуют некоторые исключения, связанные с особенностью английского языка, например,Model_News.Название таблицы должно быть во множественном числе. К примеру, posts, categories, users_tokens.Название полей, предназначенных для связи с другими таблицами, должны быть в единственном числе и оканчиваться на _id.Например, не post.category, а post.category_id, не token.user, а token.user_id, неproduct.default_photo, а product.default_photo_id.

Базовое использование

Базовое использование подразумевает простейшие действия с объектами — чтение, изменение, запись.

Определение модели

Чтобы определить модель ORM, создайте в папке classes/module класс, унаследованный от ORM:

class Model_City extends ORM { }

На этом, формально, создание модели можно окончить. Остальные настройки (название таблицы, первичный ключ, названия столбцови т.д. Kohana сгенерирует сама, исходя из названия модели (в данном случае, это — city). Тем не менее, мы рассмотрим их далее.

Название таблицы

Название таблицы хранится во внутреннем параметре объекта _table_name:

protected $_table_name = 'custom_table';

Первичный ключ

Названия поля первичного ключа находится в параметре _primary_key и по умолчанию оно установлено в id:

protected $_primary_key = 'custom_pk';

Первичные ключи, состоящие из нескольких полей, в данный момент не поддерживаются. Их реализация должна появиться с выходомKohana 3.3

База данных

По умолчанию используется стандартная БД, но это можно поменять в параметре _db_group:

Page 2: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

2/12kohana3.ru/module/orm

protected $_db_group = 'customdb';

Создание модели

Создание модели происходит с помощью метода ORM::factory($model), где $model — название модели, либо прямымсозданием экземпляра объекта:

$city = ORM::factory('city');$city = new Model_City;

После выполнения кода будет создана пустая модель сity.

Рекомендуется использовать именно первый вариант, т.к. с помощью него можно создавать конструкции вида

ORM::factory('city')->method1()->method2()->...

Доступ к модели

После создания модели, мы можем обратиться к ее публичным параметрам как к столбцам в таблице:

$city = ORM::factory('city');echo $city->name;

Также, мы можем преобразовать объект в массив:

$city = ORM::factory('city')->as_array();echo $city['name'];

Загрузка модели

Чтобы загрузить модель, зная ее первичный ключ, можно использовать тот же ORM::factory($model, $id), где $model —название модели, а $id — значение первичного ключа, либо через стандартный конструктор классов:

$product = ORM::factory('product_photo', 4);$product = new Model_Product_Photo(13);

Если первичный ключ неизвестен, и нужно подобрать запись, соответствующую некоторым условиям, можно использовать методfind():

$city = ORM::factory('city')->find();

В данном случае, условий нет, и будет возвращена первая запись из таблицы. Условия ставятся напрямую к таблице используя KohanaQuery Builder с помощью методов where, having, order_by, join, select, group_by, limit, offset и т.д. Примериспользования:

$city = ORM::factory('category') ->where('name', '=', 'Dresses') ->where('active', '=', TRUE) ->limit(20) ->order_by('posted', 'DESC') ->find();

Также, условия можно передавать в метод ORM::factory или конструктор через массив:

$city = ORM::factory('category', array('name' => 'Dresses', 'active' => TRUE));

В этом случае все переданные условия будут вставлены с помощью AND WHERE.

Если для заданного условия не нашлось ни единой записи, то будет возвращен пустой объект. Когда нужно проверить, загружен лиобъект из базы или нет, нужно использовать метод loaded():

$category = ORM::factory('category', 10); if( ! $category->loaded()){ throw new HTTP_Exception_404('Category not found');}

Всегда проверяйте, загружен ли объект после поиска. Случай, когда объект не загружен, а над ним производятся нерассчитанные наэто действия, может привести к неожиданным результатам.

Загрузка нескольких моделей

Практически всегда требуется загрузить несколько моделей, отвечающим условиям, для этого Kohana предоставляет методfind_all():

$dogs = ORM::factory('dog')

Page 3: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

3/12kohana3.ru/module/orm

->where('name', '=', 'Bob') ->find_all();

В результате мы получим объект класса Database_Result, который будет содержать найденные записи в виде отдельныхобъектов, их можно обходить как массив:

$dogs = ORM::factory('dog') ->where('home', '!=', NULL) ->limit(15) ->find_all(); foreach($dogs as $dog){ echo $dog->name;}

Более подробно об использовании Database_Result можно прочитать в руководстве по базам данных.

Изменение модели

Для изменения модели доступно несколько методов. Первый из них — прямое обращение к публичным параметрам модели:

$city->name = 'Moscow';

Также доступен метод set($column, $value), где $column — имя столбца, а $value — устанавливаемое значение, восновном используется для создания подобных конструкций:

$city = ORM::factory('city') ->set('name', 'Moscow') ->set('popularity', 20000000);

И для массовой загрузки значений доступен метод values($data, $excepted), где $data — массив, индексами которогоявляются названия столбцов, а элементами — их значения, и необязательный параметр $excepted — массив значений, которыебудут взяты из массива, если параметр пустой, то будут взяты все значения:

$city = ORM::factory('country')->values(array( 'name' => 'Russia', 'popularity' => 140000000,));

Второй параметр полезен для случаев, когда данные вставляются в модель сразу от пользователя (например, из $_POST):

$account = ORM::factory('account') ->set('balance', 0); ->values($_POST, array('name', 'country'));

В данном примере, из всех пользовательских данных в модель попадут только name и country, а balance, даже если и будетприсутствовать в $_POST, все равно установится в 0.

Сохранение модели

После изменения модели, чаще всего, требуется ее сохранять. Для этого есть методы update(), который обновляет запись,create(), который создает запись в базе данных, и save(), который обновляет запись, если она уже существует, либо создает ее.Пример использования:

ORM::factory('user', 6) ->set('balance', 60) ->save();

Удаление модели

Для удаления существует единственный метод delete() — который производит удаление записи из базы данных и стираниеобъекта. пример:

$users = ORM::factory('user') ->where('last_activity', '<', time() - Date::YEAR) ->find_all(); foreach($users as $user){ $user->delete();}

Подсчет всех записей

Чтобы подсчитать количество всех записей в базе доступен метод count_all():

$active_users = ORM::factory('user') ->where('last_activity', '>', time() - Date::MONTH) ->count_all();

Page 4: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

4/12kohana3.ru/module/orm

В результате будет сгенерирован следующий запрос:

SELECT COUNT(*) AS records_found FROM users AS user WHERE last_activity > 1323458064

Будьте аккуратны с условиями having, group_by и limit. Они могут неоднозначно повлиять на результат подсчета.

Связи

Связи в ORM позволяют строить связи между таблицами как вложенные параметры объектов. Например, существуют таблицы city(город) и country (страна). При должной настройке ORM‑связей, вы сможете производить действия над моделью countryнапрямую из city:

$city = ORM::factory('city', 8);echo $city->title.', '.$city->country->title;

Результатом может быть строка Mosow, Russia. Чтобы создать связь, необходимо, чтобы все связываемые таблицы имелиобъявление модели ORM.

Kohana предоставляет 4 типа связей для объектов:

1. Один к одному (has one). Данный тип связей используется, когда для одной записи из одной таблицы имеется одна записьиз другой. Пример реализации: у каждого автора из таблицы users есть 1 запись из таблицы passports.

2. Много к одному (belongs to). Этот тип связи используется, когда для многих записей из одной таблицы имеется одназапись из другой. Пример: для каждой записи из таблицы posts имеется одна категория из таблицы categories. Другимисловами, можно сказать, что запись (posts) принадлежит (англ. belongs to) к категории (categories).

3. Один к многим (has many). Тип связи подразумевает, что у одной записи есть много записей из другой таблицы, причемпринадлежащие только ей. Например, у одного города (cities) может быть несколько жителей (users). Тем не менее, одинжитель может принадлежать только к одному городу.

4. Много ко многому (has many through). Связь используется, когда у многих записей из одной таблицы может быть многозаписей из другой. Например, у каждой записи в блоге (posts) существуют теги (tags). Причем, один и тот же тег можетпринадлежать нескольким записям одновременно. Для построения подобной связи используется вспомогательная таблица,название которой составляется из двух соединяемых таблиц. В этом случае, например, название может быть posts_tags.

Настройка связей производится с помощью внутренних (protected) параметров класса _has_one, _belongs_to и_has_many при определении модели. Параметры должны быть заданы в виде массива, где индексы — это названия связей, аэлементами — настройки для связи, которые мы разберем ниже. Таким образом, мы можем настраивать неограниченное количествосвязей разного типа:

class Model_City extends ORM { protected $_belongs_to = array( 'country' => array(...), ); protected $_has_many = array( 'users' => array(...), 'houses' => array(...), );}

Таким образом, приведенная в примере модель города city может принадлежать стране (country) и содержать несколькопользователей (users) и домов (houses). После составления модели, мы сможем обращаться к связям, как к параметрам объекта:

$city = ORM::factory('city')->where('name', '=', 'London')->find();echo $city->country->name;$users_list = $city->users;

Один к одному

Для создания этих типов связей используется параметр _has_one, для каждой связи доступны следующие параметры:

model — имя модели ORM связываемой таблицы.foreign_key — название столбца в связываемой таблице, по которому будет проходить связь с первичным ключом первойтаблицы. По умолчанию, это поле устанавливается в значение «имя первой таблицы в единственном числе + _id». Например,при связи таблицы users с passports, это поле по умолчанию установится в user_id.

Дальнейшая логика происходит следующим образом: при обращении к связываемому объекту, происходит запрос к базе данных исоздается объект. При дальнейших обращениях к объекту, новых обращений к базе данных не происходит, а возвращаетсясохраненный объект.

Пример реализации:

class Model_User extends ORM { protected $_has_one = array( 'passport' => array( 'model' => 'passport', 'foreign_key' => 'user_id', ), );}

Page 5: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

5/12kohana3.ru/module/orm

class Model_Passport extends ORM {}

$user = ORM::factory('user', 63);echo $user->passport->id; // 1echo $user->passport->registration_date; // 2012-01-25

В данном случае, будет сгенерировано два sql запроса:

SELECT user .* FROM users AS user WHERE user . id = 63 LIMIT 1;SELECT passport .* FROM passports AS passport WHERE passport . user_id = '63' LIMIT 1;

Много к одному

Настройки этих связей хранятся в параметре _belongs_to, каждый из элементов также имеет свои настройки:

model — имя модели ORM связываемой таблицы.foreign_key — название столбца в первой таблице, по которому происходит связь с первичным ключом второй таблицы.По умолчанию, также генерируется имя, состоящее из «названия второй таблицы в единственном числе + суффикс _id».Например, для связи posts с categories установится значение category_id.

Дальнейшая логика происходит примерно также, как и в связи «один к одному». Рассмотрим сразу пример реализации:

class Model_Post extends ORM { protected $_belongs_to = array( 'category' => array( 'model' => 'category', 'foreign_key' => 'category_id', ), );}

class Model_Category extends ORM {}

$post = ORM::factory('post', 2);echo $post->category->name; // Autoecho $post->category->id; // 4

После запуска этого примера, будет выполнены следующие sql‑запросы:

SELECT post .* FROM posts AS post WHERE post . id = 2 LIMIT 1SELECT category .* FROM categories AS category WHERE category . id = '4' LIMIT 1

Один ко многим

Для хранения настроек этого типа связи используется параметр _has_many. Доступные настройки при этом следующие:

model — имя модели ORM связываемой таблицы.foreign_key — название столбца во второй таблице, по которому будет идти связь с первичным ключом первого. Поумолчанию, оно устанавливается в «название первой таблицы в единственном числе + суффикс _id». Примером для связиcities с users будет значение city_id.

Последующая логика несколько отличается от логики предыдущих связей. После обращения к связываемому объекту, запроса к базене происходит, а возвращается пустой экземпляр связываемой модели с записанными условиями для выборки. То есть, мы можем либодополнить условия, либо сразу вызвать метод find_all() для нахождения всех связанных моделей. Рассмотрим на примере:

class Model_City extends ORM { protected $_has_many = array( 'users' => array( 'model' => 'user', 'foreign_key' => 'city_id', ), );}

class Model_User extends ORM {}

$city = ORM::factory('city', 1);$users = $city->users->find_all();foreach($users as $user){ echo 'user '.$user->id.' ';} // user 63

После выполнения этого кода, будет сгенерированы следующие sql‑запросы:

SELECT city .* FROM cities AS city WHERE city . id = 1 LIMIT 1SELECT user .* FROM users AS user WHERE user . city_id = '1'

Многие ко многим

Page 6: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

6/12kohana3.ru/module/orm

Для создания данного типа связи используется параметр _has_many, как и для связи «Один ко многим», с единственным отличием,что настроек больше:

model — имя модели ORM связываемой таблицы.through — имя промежуточной таблицы, через которую будет осуществляться связь между первичными ключами двухмоделей. Является обязательной для указания, иначе выполнится связь «Один ко многим». Принято имена таблиц указывать встиле «название первой таблицы во множественном числе _ название второй таблицы во множественном числе». В нашемпримере для связи между posts и tags это будет posts_tags.foreign_key — имя столбца в промежуточной таблице, который будет выполнять связь с первичным ключом первойтаблицы. Если параметр не указать, он будет составлен из «названия первой таблицы в единственном числе + суффикс _id»,например, post_id.far_key — имя столбца в промежуточной таблице, который будет выполнять связь с первичным ключом второй таблицы.Если параметр не указать, он будет составлен из «названия второй таблицы в единственном числе + суффикс _id», например,tag_id.

Логика этой связи строится на выборе из второй таблицы всех записей, для которых существует запись посредством связи ихпервичного ключа и far_key в промежуточной таблице такая, что foreign_key равен первичному ключу найденного объекта.

С помощью языка sql это можно объяснить следующим образом (first — имя первой таблицы, second — имя второй таблицы,through — имя промежуточной таблицы, а 63 — первичый ключ найденного объекта):

SELECT second .* FROM second JOIN through ON ( through . far_key = second . id ) WHERE through . foreign_key = 63

После обращения к связываемому объекту, как и в предыдущем типе связи, запросов к базе данных не происходит, а создается новыйэкземпляр с описанной логикой, после чего вы можете добавить новые условия или сразу произвести поиск.

Например:

class Model_Post extends ORM { protected $_has_many = array( 'tags' => array( 'model' => 'tag', 'through' => 'posts_tags', ), );}

class Model_Tag extends ORM {}

$post = ORM::factory('post', 63);$tags = $post->tags->find_all();foreach($tags as $tag){ echo $tag->id.', ';} // 1, 2, 3,

В данном случае, будет сгенерированы следующие sql‑запросы:

SELECT post .* FROM posts AS post WHERE post . id = 2 LIMIT 1SELECT tag .* FROM tags AS tag JOIN posts_tags ON ( posts_tags . tag_id = tag . id ) WHERE posts_tags . post_id = '2'

Добавление связи

Чтобы добавить к текущему объекту связь с другом объектом, доступен метод add($alias, $far_keys), где $alias — имясвязи, а $far_keys — объект (объекты) для связи. Последний параметр можно указать несколькими способами:

Первичный ключ объектаМассив первичных ключей нескольких объектовСам объект (загруженный)

Пример добавления связи с загруженным объектом:

$post = ORM::factory('post', 63);$tag = ORM::factory('tag') ->where('name', '=', 'Breaking bad') ->find();$post->add('tag', $tag);

После добавления связи сохранять объект не нужно, запрос к базе данных генерируется в момент запуска метода add.

Удаление связи

Чтобы удалить связь с другим объектом, доступен метод remove($alias, $far_keys), где $alias — имя связи и$far_keys — объект или объекты. Пследний параметр также можно задать несколькими способами:

Первичный ключ объектаМассив первичных ключей нескольких объектовСам объект (загруженный)NULL, в этом случае удалятся связи со всеми объектами

Page 7: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

7/12kohana3.ru/module/orm

Пример удаления связей с несколькими объектами:

$post = ORM::factory('post', 63);$post->remove('tag', array(555, 666));

Обратите внимание, что сами связываемые объекты не удаляются, удаляется лишь только связь из промежуточной таблицы.

Проверка наличия связи

Для того, чтобы проверить, существует ли у объекта связь с другим или другими, совершенно необязательно производить поиск.Kohana предоставляет метод has($alias, $far_keys), который позволяет проверить, существует ли у текущего объекта связьс объектами $far_keys через связь $alias. Параметр $far_keys, опять же, можно задать любым удобным способом:

Первичный ключ объектаМассив первичных ключей нескольких объектовСам объект (загруженный)

Метод возвращает TRUE, если существует связь сразу со всеми заданными объектами, и FALSE в другом случае.

Пример реализации проверки связи:

$post = ORM::factory('post', 63);if($post->has('tag', 4)){ // Запись с id = 63 имеет связь с тегом с id = 4}

Подгрузка связей

Подгрузка связей работает только со связями типа «Один к одному» (has one) и «Много к одному» (belongs to).

Генерация еще одного sql запроса при каждом обращении к связям не всегда может устраивать, поэтому kohana предоставляет методwith($target_path), позволяющий подгрузить связь $target_path в одном запросе к базе данных, используя конструкциюsql JOIN. Пример подгрузки связи «много к одному»:

$posts = ORM::factory('post') ->with('category') ->find_all();foreach($posts as $post){ echo $post->category->name; echo $post->category->id;}

В данном случае сгенерируется всего 1 sql‑запрос:

SELECT category . id AS category:id , category . name AS category:name , post .* FROM posts AS postLEFT JOIN categories AS category ON ( category . id = post . category_id )

Иногда требуется, чтобы связь подгружалась всегда автоматически, без вызова метода with. Для этого в определении модели выможете установить внутренний параметр _load_with в массив названий требуемых связей, например:

class Model_Post extends ORM { protected $_load_with = array('category'); ...

После этого, следующий код сгенерирует тот же самый один запрос:

$posts = ORM::factory('post')->find_all();foreach($posts as $post){ echo $post->category->name; echo $post->category->id;}

У связанного объекта тоже могут быть связи. Чтобы подгрузить в одном запросе и их, необходимо указать их методу with() черездвоеточие ::

$posts = ORM::factory('post') ->with('category:country') ->find_all();

Можно комбинировать и подгружать несколько связей вместе:

$cities = ORM::factory('city') ->with('region:country') ->with('category') ->find_all();foreach($cities as $city){ echo $city->region->country; echo $city->category;}

Page 8: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

8/12kohana3.ru/module/orm

Вложенность и количество этих связей ничем не ограничена.

Валидация

Валидация объектов ORM очень схожа с обычной валидацией Kohana, поэтому, предполагается, что вы ознакомлены с ней.

Составление правил

Составление правил происходит в публичном методе rules() при определении модели. Метод должен отдавать массив, индексамикоторого должны являться названия полей объекта, а элементами — массивы правил для них. Приведем пример:

class Model_Post extends ORM { public function rules() { return array( 'title' => array( array('not_empty'), array('max_length', array(':value', 200)), ); ); }}

В этой модели для поля title будут установлены два правила: not_empty(:value) и max_length(:value, 200)(:value — значение поля).

Зачем объявление правил сделано в методе, а не в параметре объекта? Дело в том, что с помощью метода можно реализоватьнаследование правил при наследовании классов. Это бывает очень полезно, например, в реализации класса Model_Account(аккаунт) объявить правила для полей логина и пароля, а в классе Model_Account_User extends Model_Account(аккаунт пользователя) добавить правила для имени и фамилии.

Пример:

class Model_Account { public function rules() { return array( 'password' => array(...), 'username' => array(...), ); }}

class Model_Account_User extends Model_Account { public function rules() { return array_merge(parent::rules(), array( 'firstname' => array(...), 'lastname' => array(...), )); }}

В итоге, в классе Model_Account_User будут правила для полей password, username, firstname и lastname.

Проверка

Проверка запускается автоматически при сохранении объекта (методы save, update, create), а также через отдельный методcheck. Вне зависимости, какие поля были изменены, проверка идет полностью по всем заданным правилам. Пример:

$user = ORM::factory('user') ->set('email', '[email protected]');$user->check();

Если после последней проверки вы не изменяли объект, то при сохранении новой проверки не будет.

Для всех вышеперечисленных методов существует единственный опциональный аргумент $extra_validation — произвольныйобъект валидации, который будет проверен вместе с объектом.

Для чего он нужен? Часто, в самой модели невозможно предусмотреть проверку некоторых полей. Например, таких, как поле спроверочными символами (captcha), чекбокс о принятии пользовательского соглашения и т.д.

Проверка этих полей должна выноситься в отдельный объект валидации (Validation) и передаваться любому из этих методов, и вслучае возникновения ошибки в объекте либо в дополнительной валидации, объект сохранен (проверен) не будет.

Приведем пример:

$extra_validation = Validation::factory($_POST) ->rule('terms_agree', 'not_empty'); // Дополнительная валидация, что поле terms_agree не пустое$user = ORM::factory('user') ->values($_POST, array('username', 'email', 'password')); // достаем из $_POST поля username, email, password$user->save($extra_validation); // Обе валидации запускаются в этом методе

Page 9: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

9/12kohana3.ru/module/orm

В этом примере, помимо валидации данных модели, идет проверка, что пользователь отметил чекбокс terms_agree(пользовательское соглашение). В случае, если чекбокс не отмечен, либо какое‑то другое поле не заполнено (в зависимости отвнутренних правил модели user), будет вызвана ошибка валидации.

Перехват ошибок

При возникновении ошибки Kohana генерирует исключение ORM_Validation_Exception, которое содержит методы дляполучения списка ошибок и работы с ними. Поэтому, метод, содержащий проверку всегда нужно заключать в конструкцию try …catch:

try{ $model->save(); echo 'Модель успешно сохранена';}catch(ORM_Validation_Exception $e){ echo 'Произошла ошибка';}

Перехватываемое исключение содержит метод errors($directory, $translate), с двумя необязательными аргументами$directory — директорию, из которой брать сообщения ошибок (messages) и $translate — флаг, при котором будетпроизведен еще и перевод сообщений.

Пример:

try{ $model->save($some_extra_validation); $this->request->redirect('successpage');}catch(ORM_Validation_Exception $e){ $errors = $e->errors(); // выводим список ошибок $errors в своем представлении}

Проверка нескольких моделей одновременно

Иногда встает задача, которая требует сохранения нескольких моделей, только если все они валидны. Реализацию проверки икрасивый вывод ошибок можно реализовать с помощью использования некоторых функций исключенияORM_Validation_Exception.

Для начала, создадим пустой объект исключения:

$error = new ORM_Validation_Exception('', Validation::factory(array()));

В первом аргументе мы передаем пустое имя валидации, а во втором — пустой объект валидации. Таким образом, у нас естьисключение об ошибке, не содержащее никаких ошибок. Затем, мы создаем сами модели и вставляем в них значения:

$ticket = ORM::factory('support_ticket')->values($_POST, array('subject', 'category_id'));$reply = ORM::factory('support_reply')->values($_POST, array('message'));

Как должно быть понятно из названий объектов и параметров в этом коде, мы создаем тикет (support_ticket) в системуподдержки, и сразу же добавляем к нему одно сообщение (support_reply). Понятно, что данные из формы должныудовлетворять правилам как тикета support_ticket (это поля категории category_id и темы subject), так и первого в немсообщения support_reply (поле сообщения message).

Далее нам потребуется созданное нами исключение. Мы будем проверять обе модели с помощью метода check(), и в случаеперехвата ошибки, объединять ее с нашим пустым исключением с помощью метода исключения merge:

try{ $ticket->check();}catch(ORM_Validation_Exception $e){ $error->merge($e);}try{ $reply->check();}catch(ORM_Validation_Exception $e){ $error->merge($e);}

Чтобы проверить, какие появились ошибки, нужно вызвать метод errors(), который мы разбирали выше. В случае, если ошибок невозникало, этот массив будет пустым, иначе ошибки для каждого объекта будут записаны в отдельном элементе. Поэтому, завершитьэтот код можно следующим образом:

$errors = $error->errors();if( ! $errors)

Page 10: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

10/12kohana3.ru/module/orm

{ $ticket->save(); $reply->set('ticket', $ticket)->save(); // Сохранение прошло успешно}else{ // Массив $errors содержит все допущенные ошибки}

Фильтры

Нередко, перед сохранением записи в базу данных, нужно совершить определенные действия над ее полями. Например,перекодировать строку, сохранить файл на диске сервера, преобразовать произвольную дату в понятный базе данных типtimestamp и т.д. Для этого существует фильтры — функции (методы), которые выполнятся перед сохранением записи, и результатвыполнения которых будет значением определенных полей. Как и правила валидации, фильтры объявляются через специальныйпубличный метод filters(), который должен возвратить массив, индексами которого будут названия полей, а элементами —массивы фильтров для них.

Фильтр задается в виде массива, первый элемент которого — название функции, и, опциональный второй — массив аргументов,передаваемых функции.

Название фильтра можно указать несколькими способами:

Название php функции, например, intval или trim.Статический метод класса через ::, например, Text::randomМассив, первым элементом которого является экземпляр класса, а вторым — строковое название его метода, например,array($this, 'some_method').

По умолчанию, если не задать список аргументов для фильтра, для него передастся только один аргумент ‑ значение поля. Дляавтоматической подстановки доступны следующие выражения:

:field — название поля.:model — текущая модель.:value — значение поля.

Пример задания фильтров:

class Model_Post extends ORM {public function filters() { return array( 'posted' => array( array('strtotime'), ), 'title' => array( array('Custom_Class::clean', array(':model', ':value')), ), );}

В данном случае, поле posted преобразуется из произвольного формата времени в unix timestamp с помощью функцииstrtotime, а поле title обработается статическим методом clean класса Custom_Class.

Если некоторые фильтры нужно применить для всех полей сразу, необходимо поместить их в элемент массива с индексом TRUE:

class Model_Post extends ORM {public function filters() { return array( TRUE => array( array('trim'), ), );}

В данном случае, все поля подвергнутся обработке их функцией trim.

Кеширование

Кеширование запросов к БД — одна из первых задач, возникающих при работе приложения. С помощью Kohana можно реализоватьнесколько способов кеширования.

Кеширование записей полностью. В этом случае в кеше сохраняются записи вместе со значениями полей из базы данных. Прииспользовании этого вида кеширования запросов к БД не происходит.Кеширование только id записей подходит, если вам нужны актуальные значения из базы данных, но существует сложныйалгоритм сортировки или выборки. В этом случае, при запросе кеша происходит несколько запросов к базе данных, которыезапрашивают запись напрямую по ее id.

Полное кеширование

Page 11: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

11/12kohana3.ru/module/orm

Нравится

Упорядочить по популярности

Для реализации полного кеширования, необходимо в определении модели установить внутренний параметр_reload_on_wakeup в FALSE — это означает, что модели не будут подгружаться из базы данных заново после получения изкеша:

class Model_Track extends ORM { protected $_reload_on_wakeup = FALSE;

Реализация непосредственного кеширования выглядит так:

// Проверяем, есть ли эти записи в кеше.if( ! $most_active_users = unserialize(Cache::instance()->get('widget.most_active_users'))){ // Записей нет, поэтому выбираем их из БД $most_active_users = ORM::factory('user') ->limit(5) ->order_by('activity_sum', 'DESC') ->find_all(); // Сохраняем записи в кеш на 10 минут Cache::instance()->set('widget.most_active_users', serialize($most_active_users), Date::MINUTE * 10);}else{ // Записи получены из кеша. В этом блоке можно что-нибудь с ними сделать}// В этом участке кода записи будут загружены в любом случае

После выполнения этого кода нужные данные будут доступны в переменной $most_active_users.

Кеширование по id

Для реализации этого типа кеширования нужно установить тот же самый внутренний параметр _reload_on_wakeup в TRUE.Собственно, так он и стоит по умолчанию:

class Flower extends ORM { protected $_reload_on_wakeup = TRUE;

Ссылки

1. Официальное руководство по ORM [http://kohanaframework.org/guide/database]2. Kohana 3.0. Шпаргалка по ORM [http://blogocms.ru/2011/01/kohana‑3‑0‑shpargalka‑po‑orm/]3. Kohana для чайников. Простейший ORM [http://blogocms.ru/2010/01/kohana‑dlya‑chajnikov‑prostejshij‑orm/]4. ORM в Kohana v3.1 [http://brotkin.ru/2011/02/21/orm‑in‑kohana‑v31/]

Обсуждение

Комментариев: (5)

и 14 others оценили этот комментарий.

ВойтиДобавить комментарий

Текст комментария.

Так же может быть интересно ‑ http://slash7.com/cheats/activ...

Zhirayr Ghazarosyan

Нравится Ответить6 назад 1 Нравится

Подскажите, По связи один ко многим, тут в примере выбирается к записи с заданным id =1 .class Model_City extends ORM {protected $_has_many = array('users' => array(

Lammak

Page 12: ORM — Русская документация Kohana 3

7/13/12 ORM — Русская документация Kohana 3

12/12kohana3.ru/module/orm

M Подписаться по e‑mail S RSS

© 2010—2012 delphist. По всем вопросам: [email protected] Весь текст публикуется на условиях лицензии Creative Commons Attribution/Share‑Alike Используется модифицированный движок DokuWiki.

'model' => 'user','foreign_key' => 'city_id',),);}class Model_User extends ORM {}$city = ORM::factory('city', 1);$users = $city‑>users‑>find_all();foreach($users as $user){echo 'user '.$user‑>id.' ';} // user 63

А если я хочу так: то есть присоеденить все записи без указания id. У меня просто выдает ошибку что Undefined property:class Model_User extends ORM {}$city = ORM::factory('city');$users = $city‑>users‑>find_all();foreach($users as $user){echo 'user '.$user‑>id.' ';} // user 63

Нравится Ответить3 неделя назад

А как обновить данные при связи 1 к 1? Например я сначала выбираю данные из базы: $user = ORM::factory("users",$id)‑>with("centers");Вывожу их в одну форму, а после нажатия на кнопку редактирования мне нужно все новые данные запихнуть в этот объект,провалидировать и обновить. Можно это сделать используя один объект ($user) или нужно так же как с вставкой по‑отдельности валидировать и сохранять?

Павел

Нравится Ответить1 месяц назад

Спасибо очень помогла статья, узнал много нового)

Jack

Нравится Ответить2 месяц назад

Отличная статья! Спасибо. Еще не все прочитал, но уже во многом разобрался.

Hamer

Нравится Ответить2 месяц назад