HAS_ONE отношения, добавление данных

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

Есть таблица вида

item


id

user_id

city_id

status

в которой хранятся общие сведения об объявлениях (недвижимость).

И есть таблица с подробной информацией о каждом объявлении

item_flat


id

area_kitchen

floor

floor_max

id в первой и во второй таблице соответственно ключи.

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

Собственно теперь вопрос: как реализовать все через 1 класс наиболее грамотно с использованием AR?

И правильно ли я подошел к вопросу проектирования БД?

Очень надеюсь на вашу помощь, заранее спасибо.

  1. Реализовать можно при помощи 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 не знаком, спасибо, почитаю.

Большое спасибо за отклик, очень надеюсь на помощь.

Мне кажется, что EAV здесь - это перебор :)

Идея с хранением общей информации в одной таблице, а в других - только данных, относящихся к конкретному типу объявления, кажется мне хорошей. Да и с помощью Active Record это реализовать не сложно. Создаете классы ItemFlat, ItemGarage с realtions:


'item' => array(HAS_ONE, 'Item', 'id')

Затем можно будет извлечь квартиры вот так:


$flats = ItemFlat::model()->with('item')->findAll()

В обратную сторону уже сложнее, т.к. заранее неизвестно, с какой таблицей нужно будет соединять таблицу 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 = ...;



или в любом другом виде. Т.е. хотелось бы иметь для внешнего пользователя наиболее простой интерфейс для работы.

А где хранить правила валидации, если не создавать отдельно классы? Может глуплю, просто еще совсем молод и зелен :rolleyes:

Либо перегрузить save(), либо использовать beforeSave() для вставки данных в таблицу Item. Дело техники.

Перегрузить метод __get($name) примерно так:




if ($this->item->hasAttribute($name))

    return $this->item->getAttribute($name);

else

    return parent::__get($name);



Правила валидации в вашем случае хранить, естесственно, в созданном классе :) А вот в задаче, которую описал я, хранить их надо не иначе как в бд.

В общем, идея проста - создать класс (напр. ItemContent), где добавить нужный функционал, а от него уже наследовать ItemGarage, ItemFlat и т.д.

andy_s, спасибо за консультацию. Я в принципе так и думал делать, просто надеялся, что готовое решение есть в Yii :).

Пока только присматриваюсь к Yii.

В общем смысле я практикую следующий подход: все, что можно - хранится по отдельным справочникам. Справочники могут быть вложенными, как, например Country->State->City. Как правило справочники пополняемые, т.е. в процессе эксплуатации приложения в них добавляются данные. Отдельно стоит вопрос по правам редактирования/удаления данных, а так же доверия введенным данным.

При внесении/редактировании данных в таблицах, использующих справочники, последние выглядят как Select’ы, и, где надо, рядом кнопочка [+].

Голубая мечта - написать автоматический генератор интерфейсов к БД. Что-то подобное я делал много лет назад на Clipper. Достаточно было описать структуру данных таблицы и структуры/правила активных представлений (аналог формы), и на базе этих описаний движок автоматом генерировал весь интерфейс. Дело оставалось за выборками.

Так же и тут. Предлагаю все, что может быть потенциально использовано более чем в одном месте (одной записи) - выносить в справочники. Это обычная практика при нормализации баз данных.