This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
khosb/includes/kohana/modules/userguide/guide/ru-ru/tutorials.orm.md
2011-05-03 09:49:01 +10:00

16 KiB
Raw Blame History

ORM

Kohana 3.0 включает мощный модуль ORM, который использует паттерн Active Record и автоопределение информации о списке полей БД модели.

Модуль ORM включен в дистрибутив Kohana 3.0, но нуждается в подключении перед его использованием. В файле application/bootstrap.php отредактируйте вызов [Kohana::modules] и добавьте модуль ORM:

Kohana::modules(array(
	...
	'orm' => MODPATH.'orm',
	...
));

Настройка

ORM требует небольшую настройку перед использованием. Наследуйте Вашу модуль от ORM:

class Model_User extends ORM
{
	...
}

В примере выше, модель будет искать таблицу users в БД по умолчанию.

Свойства модели, отвечающие за конфигурацию

Следующие свойства используются для настройки каждой модели:

Тип Название Описание Значение по умолчанию
string _table_name Используемая таблица БД имя модели в единственном числе
string _db Название БД default
string _primary_key Поле - первичный ключ id
string _primary_val Титульное поле name
bool _table_names_plural Имя таблицы во множественном числе TRUE
array _sorting Сортировка (столбец => направление) primary key => ASC
string _foreign_key_suffix Суффикс внешнего ключа _id

Использование ORM

Загрузка записи

Для создания экземпляра модели используйте метод [ORM::factory] или конструктор [ORM::__construct]:

$user = ORM::factory('user');
// или
$user = new Model_User();

Конструктор и фабричный метод также поддерживают значение первичного ключа для загрузки конкретной записи:

// Загружаем пользователя с ID 5
$user = ORM::factory('user', 5);

// Проверяем успешность загрузки объекта пользователя
if ($user->loaded()) { ... }

Опционально, Вы можете передать массив с парами ключ => значение для загрузки данных объекта по совпадающим критериям, указанным в массиве:

// Загрузка пользователя с email joe@example.com
$user = ORM::factory('user', array('email' => 'joe@example.com'));

Поиск записи

ORM поддерживает большинство методов класса [Database] для полноценного поиска данных модели. В свойстве _db_methods перечислен полный список поддерживаемых методов. Записи извлекаются после вызовов [ORM::find] или [ORM::find_all].

// Извлекаем первого активного пользователя по имени Bob
$user = ORM::factory('user')
	->where('active', '=', TRUE)
	->where('name', '=', 'Bob')
	->find();

// Ищем всех активных пользователей по имени Bob
$users = ORM::factory('user')
	...
	->find_all();

Когда Вы запрашиваете список моделей через [ORM::find_all], перебирать его можно аналогично обычным выборкам из БД:

foreach ($users as $user)
{
	...
}

Мощным инструментом ORM является метод [ORM::as_array], который возвращает полученные записи в виде массива. При использовании совместно с [ORM::find_all], будет возвращён массив всех записей. Хороший пример использование этого метода - когда необходимо передать значения для выпадающего списка:

// Отображается выпадающий список пользователей
// (используется id в качестве значения select option)
form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username') ...

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

Для получения количества записей для данного запроса, используйте [ORM::count_all].

// Число активных пользователей
$count = ORM::factory('user')->where('active', '=', TRUE)->count_all();

Если требуется подсчитать общее количество пользователей для данного запроса при лимитировании количества возвращаемых записей, используйте метод [ORM::reset] с параметром FALSE перед использованием count_all:

$user = ORM::factory('user');

// Общее число пользователей (reset FALSE предотвращает объект от очистки перез запросом)
$count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all();

// Получаем только первые 10 результатов
$users = $user->limit(10)->find_all();

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

Все свойства модели доступны через "магические" методы __get и __set.

$user = ORM::factory('user', 5);

// Выводит имя пользователя
echo $user->name;

// Изменяет имя пользователя
$user->name = 'Bob';

Для хранения данных/свойств, которые отсутствуют в таблице модели, надо использовать атрибут _ignored_columns.

class Model_User extends ORM
{
	...
	protected $_ignored_columns = array('field1', 'field2', ...)
	...
}

Множественные пары ключ => значение могут быть заданы с использованием метода [ORM::values]:

$user->values(array('username' => 'Joe', 'password' => 'bob'));

Создаем и сохраняем записи

Метод [ORM::save] используется как для создания новых записей, так и для обновления существующих.

// Создаем запись
$user = ORM::factory('user');
$user->name = 'New user';
$user->save();

// Редактируем запись
$user = ORM::factory('user', 5);
$user->name = 'User 2';
$user->save();

// Проверяем, сохранена ли запись
if ($user->saved()) { ... }

Вы можете обновить множество записей с помощью метода [ORM::save_all]:

$user = ORM::factory('user');
$user->name = 'Bob';

// Все активные пользователи получат имя 'Bob'
$user->where('active', '=', TRUE)->save_all();

Использование Updated и Created для столбцов БД

Свойства _updated_column и _created_column позволяют производить автоматическое обновление модели при её обновлении и сохранении. Это используется не по-умолчанию. Чтобы использовать эти свойства, следует их указать:

// date_created является столбцом таблицы, в котором хранится дата создания.
// Для сохранения метки времени, используем TRUE
protected $_created_column = array('date_created' => TRUE);

// date_modified является столбцом таблицы, в котором хранится дата изменения.
// В этом случае используется строка, определяющая формат для функции date()
protected $_updated_column = array('date_modified' => 'm/d/Y');

Удаление записей

Записи удаляются методами [ORM::delete] и [ORM::delete_all]. Эти методы работают аналогично описанному выше сохранению, за исключением того, что [ORM::delete] принимает необязательный параметр id для удаляемой записи.

Отношения

ORM предоставляет мощную поддержку отношений таблиц. Прочитать про отношения можно в справочнике по Ruby

Belongs-To и Has-Many

Допустим, мы работаем со школой, которая имеет много учеников (has many). Каждый студент приписан к одной школе (принадлежит - belongs to). Необходимо определить отношения моделей следующим образом:

// В модели school
protected $_has_many = array('students' => array());

// В модели student
protected $_belongs_to = array('school' => array());

Получаем информацию о школе студента:

$school = $student->school;

Ищем всех студентов школы:

// Учтите, что после students следует вызвать метод find_all
$students = $school->students->find_all();

// Чтобы сузить результаты поиска:
$students = $school->students->where('active', '=', TRUE)->find_all();

По-умолчанию, ORM будет искать поле school_id в таблице модели student. Это можно изменить, используя аттрибут foreign_key:

protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID'));

Внешний ключ будет перегружен как в модели student, так и в school.

Has-One

Has-One - это частный случай Has-Many, единственным отличаем которого является то, что в отношении участвует только одна запись. В дополнении к приведённому выше примеру школы, каждая школа будет иметь (has-one) только одного директора, который принадлежит (belongs-to) школе.

// Inside the school model
protected $_has_one = array('principal' => array());

Как и для Belongs-To, Вам не нужно использовать метод find для получение объекта, ссылающегося на Has-One объект - это будет сделано автоматически.

Has-Many "через" (through)

Отношение Has-Many "through" (так же известное как Has-And-Belongs-To-Many) оспользуется в случае если объект связан с несколькими объектами другого типа и наоборот. Например, студент записан на многие занятия и на занятие ходит много студентов. В этом случаеи используется промежуточная таблица. Используем для нашего примера промежуточную таблицу и модель - журнал (enrollment).

// В модели student
protected $_has_many = array('classes' => array('through' => 'enrollment'));

// В модели class
protected $_has_many = array('students' => array('through' => 'enrollment'));

Таблица enrollment должна содержать 2 внешних ключа: для занятий class_id и для студентов student_id. Наименование внешних и дальних ключей (foreign_key и far_key) могут быть переопределены при определении отношений. Например:

// В модели student (внешний ключ ссылается на модель student,
// в то время, как дальний ключ - на class)
protected $_has_many = array(
	'classes' => array(
		'through'     => 'enrollment',
		'foreign_key' => 'studentID',
		'far_key'     => 'classID'
));

// В модели class
protected $_has_many = array(
	'students' => array(
		'through'     => 'enrollment',
		'foreign_key' => 'classID',
		'far_key'     => 'studentID'
));

Определяем в модели enrollment:

// Журнал принадлежит как студенту, так и занятию
protected $_belongs_to = array('student' => array(), 'class' => array());

Для доступа к связанным объектам:

// Для получение занятий студента
$student->classes->find_all();

// Для получения студентов, записанных на занятие
$class->students->find_all();

Валидация

ORM тесно взимодействует с [Validate] библиотекой, позволяя использовать возможности этого класса в следующих свойствах:

  • _rules
  • _callbacks
  • _filters
  • _labels

_rules

protected $_rules = array
(
	'username' => array('not_empty' => array()),
	'email'    => array('not_empty' => array(), 'email' => array()),
);

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

_callbacks

protected $_callbacks = array
(
	'username' => array('username_unique'),
);

Значение поля username будет передано методы username_unique. Если метод не существует в текущей модели, то будет вызвана глобальная функция. Вот пример описания этого метода:

public function username_unique(Validate $data, $field)
{
	// Логика, проверяющая уникальность имени пользователя
	...
}

_filters

protected $_filters = array
(
	TRUE       => array('trim' => array()),
	'username' => array('stripslashes' => array()),
);

TRUE Указывает на то, что фильтр trim будет применён ко всем полям. Значение поля username будет отфильтровано с помощью функции stripslashes перед процессом валидации. Ввиду возможности передачи дополнительных опций для фильтров, значения фильтра задаются как пустые массивы.

Проверка объекта

Для проверки объекта, используйте [ORM::check]:

// Задание значений объекта и дальнейшая их валидация
if ($user->values($_POST)->check())
{
	$user->save();
}

Для доступа к объекту валидации данной модели, можно использовать метод validate():

// Ручное добавление дополнительного фильтра
$user->validate()->filter('username', 'trim');