Введение в ORM

Комментарии: 8  Просмотры: 24 792

Пока мы с вами рассмотрели два способа работы с базами данных в Кохане: с помощью SQL-запросов и с помощью Query Builder-а. В этом и последующих уроках мы поговорим о еще одном способе — взаимодействие с базой данных с помощью ORM (Объектно-реляционное отображение). ORM очень любят новички, а вот продвинутые программисты не всегда рекомендуют его использовать. Вообще все это напоминает ситуацию с ООП. Перед тем как перейти к объектно-ориентированному подходу, рекомендуется сначала нормально изучить процедурный подход. Но речь сейчас не об этом. ORM любят не зря — он очень прост и удобен. При использовании SQL-запросов приходится фактически учить еще один язык — SQL (хотя это тоже надо!). Правда проблема даже не в составлении этих запросов. А в том, что сейчас нам понадобилось вытащить все записи из таблицы, потом только одну с определенным id, через какое-то время — запись с определенными условиями, а в конце вообще связать две таблицы через JOIN и получить записи из обеих. Это получается в модели нам нужно под каждый запрос писать свой метод ? И начинаются танцы с бубном. Создается модель CRUD для четырех базовых запросов SQL, создаются условия вроде «если мы передали id, то вытаскиваем запись с этим id, а иначе вытаскиваем все записи» и так далее. Сплошная головная боль и проблемы. Query Builder немножко упрощает все это дело, но не сильно.
А теперь представьте, что таблица — это объект и нужную запись мы можем получить просто написав:

echo $название_таблицы->название поля;

то есть что-то вроде

echo $article->name;

Хотим изменить имя текущей записи на другое, просто пишем

$article->name = 'Работа с сессиями в Kohana';

Вот примерно таким образом ORM и работает. Фактически мы манипулируем данными БД как обычными объектами PHP. То есть нас избавляют от необходимости писать все эти «лишние» методы по вставке, удалению, обновлению и выборке данных.
Что мне больше всего понравилось — организация связей между таблицами. Не нужно прописывать миллион JOIN с условиями ON table1.id = table2.category_id. Достаточно один раз указать в каждой таблице эту связь (имя связанной таблицы и названия ключей для связи) и все, можно получать значения сразу из нескольких таблиц.
Как и модуль database, который мы включали в файле bootstrap.php, ORM тоже является модулем и его тоже нужно раскомментировать для подключения:

'orm'        => MODPATH.'orm',        // Object Relationship Mapping

Необходимо помнить еще о том, что модуль ORM не может работать без включенного модуля database, так как использует его методы. По этой же причине для модуля ORM не требуется свой конфигурационный файл. И наши Модели теперь будут наследовать не класс Model, как раньше, а класс ORM, то есть выглядеть наша новая Модель будет примерно так:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Model_Article extends ORM {
}

Фактически то, что мы видим — это уже рабочая модель, которая работает с таблицей articles. При этом данная таблица обязательно должна содержать поле первичного ключа.
Вообще при работе с ORM нужно придерживаться нескольких правил:
— Название модели должно быть в единственном числе. Например: Model_Article, Model_Category, Model_User.
— Название таблицы должно быть во множественном числе. Например: articles, users, roles.
Но в английском языке бывают слова, в которых образование множественного числа происходит не по общим правилам: слова в единственном и множественном числе пишуться одинаково (news, clothes, chess), слова-исключения (man-men, foot-feet) и так далее. Даже в нашем случае category станет categories, а не categorys. Чтобы избежать проблем есть возможность указывать название таблицы вручную. Делается это так:

protected $_table_name = 'categories';

- Каждая таблица должна содержать первичный ключ с названием id. Но опять же, если такое название нас не устраивает, мы можем поменять его и указать новое внутри модели:

protected $_primary_key = 'my_id';

- Поля для связи с другими таблицами должны быть в единственном числе и заканчиваться на _id. Например: article_id, category_id, user_id. Я лично такие поля с самого начала изучения SQL так именую, поэтому у меня проблем с привыканием не возникло.
В случае, если для работы Модели нужно использовать не стандартную БД, а какую-то другую, достаточно указать ее название:

protected $_db_group = 'my_db';

В конечном итоге ваша модель может выглядеть вот так:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Model_Category extends ORM {
    protected $_table_name = 'categories';
    protected $_primary_key = 'cat_id';
    protected $_db_group = 'my_db';
}

Если же вы пользуетесь дефолтной БД и правилами именования ORM для таблиц и полей, то все эти свойства можно опустить (что и происходит в 99% случаев).
В следующем уроке мы уже вплотную займемся практикой и будем получать записи из БД, причем вы увидите, что основная работа уже будет вестись внутри контроллера, а не модели.

<< Назад | Вперед >> | Обсудить на форуме


К записи оставлено 8 коммент.

«…Даже в нашем случае category станет categories, а не categorys…» — тут не совсем так, это было в ko3.1.
У меня в ko3.2 работает как category => categories, country => countries и тд.
Но если, допустим, таблица «news», то модель должна быть «new».
И еще, если явно в ORM указывать имя таблицы через $_table_name, то не работает потом кеширование.

Так я не возражаю, вполне возможно оно и нормально преобразовывает. Насколько я знаю, для этого используется Хелпер Inflector, а он в общем-то нормально делает, да и настроить его можно для таких исключений, потому что new и news — это новый и новости, а это как-то не то :/

Вот с кешированием действительно интересно….Проблемка мда.

Все верно, хелпер Inflector использует uncountable из system\config\inflector.php — так что с news будет все нормально. Нужно по правилам английского делать) Накрайняк добавить чего нет.

Если с прямым указанием таблиц такие проблемы, как тут говорят, то действительно тогда определенно лучше ковырять Inflector

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

Добрый день Денис!

Возникла проблема с созданием класса наследника ORM.

Объявляю в папке моделей классы:

class Model_Fun extends Model_BaseORM …
class Model_Category extends Model_BaseORM …

имена таблиц в базе данных соответственно
funs и categories

А контроллере классы моделей создаются без проблем
$categoryModel = Model::factory(‘Category’);
$funModel = Model::factory(‘Fun’);

А для таблицы imagecategories я создал файл imagecategory.php с обхявлением класса

class Model_Imagecategory extends Model_BaseORM …

Проблема состоит в том, что в контроллере при создании класса

$categoryModel = Model::factory(‘Imagecategory’);
возникает ошибка
Class ‘Model_Imagecategory’ not found

Как правильно всё назвать чтобы всё создавалось как надо?
Заранее спасибо

А у меня таблицу не находит. Создаю модель class Model_User extends ORM {
protected $_table_name = ‘sys_users’;
protected $_primary_key = ‘user_id’;
} в файле /application/classes/Model/Model_User.php
Создаю её экземпляр в контроллере $user = ORM::factory(‘User’);
и получаю ошибку Database_Exception [ 1146 ]: Table ‘ecollege.users’ doesn’t exist [ SHOW FULL COLUMNS FROM `users` ]. Хотя я явно указал с какой таблицей нужно работать protected $_table_name = ‘sys_users’; В чем неполадка, Денис?



Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.