Решил сделать свой первый проект с помощью Yii и столкнулся со сложностью.
Есть таблица вида
item
id
user_id
city_id
…
status
в которой хранятся общие сведения об объявлениях (недвижимость).
И есть таблица с подробной информацией о каждом объявлении
item_flat
id
area_kitchen
floor
floor_max
…
id в первой и во второй таблице соответственно ключи.
Вторая таблица хранит специфичные сведения для конкретного типа объявления. Например для квартиры (item_flat) необходимо указать площадь кухни, жилую площадь и т.д. Хотя для коммерческой недвижимости эти поля неактуальны.
Собственно теперь вопрос: как реализовать все через 1 класс наиболее грамотно с использованием AR?
И правильно ли я подошел к вопросу проектирования БД?
Реализовать можно при помощи 2 моделей: Item и ItemFlat. Вставка данных транзакциями.
Первая фраза из цитаты очень говорящая. Из этого вытекает, что не правильно. Я бы использовал паттерн EAV в данном случае, либо если видов объектов недвижимости не так много и их атрибуты заранее известны, то по таблице на каждую сущность.
creocoder, что-то я не очень понял что не так в цитате. Для коммерческой недвижимости эта информация неактуальна (площадь кухни и т.д.), поэтому будет создана еще 1 таблица со своими специфичными полями. Например, если объявление о продаже/покупке гаража, то необходимо отметить наличие погреба, количество машин, наличие ямы ну и т.д. Соответственно для гаража таблица будет иметь вид
item_garage
id
number_of_cars
cellar
…
И класс соответственно ItemGarage.
Ну в принципе я так и думал делать. Только через третий класс, который будет полностью отвечать за объект недвижимости (квартира или гараж), скрывая особенности хранения в БД. Вопрос именно в том, как это правильно сделать? Т.е. можно ли использовать возможности AR и отношение типа HAS_ONE, чтобы не писать свой класс. Ведь реализовывать придется те же функции (save(), delete() и т.д.), костыль какой-то получается.
Вот это в принципе я и хочу реализовать, только чтобы не хранить общую для всех объявлений информацию (дата создания, id пользователя…) я разбил таблицы на общую (items) часть и специфичные (item_flat, item_garage).
С EAV не знаком, спасибо, почитаю.
Большое спасибо за отклик, очень надеюсь на помощь.
Идея с хранением общей информации в одной таблице, а в других - только данных, относящихся к конкретному типу объявления, кажется мне хорошей. Да и с помощью Active Record это реализовать не сложно. Создаете классы ItemFlat, ItemGarage с realtions:
В обратную сторону уже сложнее, т.к. заранее неизвестно, с какой таблицей нужно будет соединять таблицу Item, и в realtions() уже так явно не задать отношение…
Меня этот вопрос тоже интересует, т.к. я не хочу создавать классы под каждый тип Item, а хотелось бы использовать только один Active Record класс Item. Пока вариант в голову приходит такой: завести поле (напр. $content) в классе Item, в которое при извлечении айтемов ложить всё, что не входит в мета данные таблицы Item. А такие данные появятся, если в передаваемых методам поиска find критериях указывать join = ‘INNER JOIN ItemFlat ON t.id = ItemFlat.id’. В итоге обратиться к информации айтема можно будет например вот так: $item->content[‘floor’].
andy_s, при поиске может и не сложно это сделать, но с добавлением все вовсе не так однозначно. Как с помощью AR можно используя 1 конструкцию save() создать сразу 2 записи в разных таблицах (items и item_garage например)?
И по хорошему, так как ItemGarage вполне самодостаточный объект, внутренняя реализация должна быть скрыта. Т.е. для внешнего пользователя класса должно казаться, что все данные хранятся в одной таблице. И соответственно операции типа
$garage = new ItemGarage;
$garage->user_id = ...;
$garage->number_of_cars = ...;
должны быть доступны напрямую, а не через дополнительные конструкции типа
$garage->items->user_id = ...;
или в любом другом виде. Т.е. хотелось бы иметь для внешнего пользователя наиболее простой интерфейс для работы.
А где хранить правила валидации, если не создавать отдельно классы? Может глуплю, просто еще совсем молод и зелен
В общем смысле я практикую следующий подход: все, что можно - хранится по отдельным справочникам. Справочники могут быть вложенными, как, например Country->State->City. Как правило справочники пополняемые, т.е. в процессе эксплуатации приложения в них добавляются данные. Отдельно стоит вопрос по правам редактирования/удаления данных, а так же доверия введенным данным.
При внесении/редактировании данных в таблицах, использующих справочники, последние выглядят как Select’ы, и, где надо, рядом кнопочка [+].
Голубая мечта - написать автоматический генератор интерфейсов к БД. Что-то подобное я делал много лет назад на Clipper. Достаточно было описать структуру данных таблицы и структуры/правила активных представлений (аналог формы), и на базе этих описаний движок автоматом генерировал весь интерфейс. Дело оставалось за выборками.
Так же и тут. Предлагаю все, что может быть потенциально использовано более чем в одном месте (одной записи) - выносить в справочники. Это обычная практика при нормализации баз данных.