Привет! Мне то там то тут попадается задачка, когда нужно сохранять (в реляционной базе данных) состояние сущности, зависящее от некоторого контекста.
Ставлю тег "Drupal", потому что в Друпале стопудово есть что-то такое )) Друпальщики, подскажите!
Приведу пример для наглядности.
Есть поле формы для ввода текста новости. Мы хотим для него настраивать описание-подсказку и набор кнопок wysiwyg-редактора, например. На сайте есть две новостных ленты, и при добавлении в каждую из них нужно показывать свою подсказку. А набор кнопок может зависеть от группы, в которой состоит текущий юзер. Итого, при отображении поля нам нужно получить контекст (группа юзера и номер новостной ленты) и собрать соответствующие этому контексту значения.
Первый кандидат - вот такая конструкцию:
field_id | parent_id | user_group | newsfeed_id | label | description | buttons
--------------------------------------------------------------------------------------------
1 | null | null | null | 'Текст' | 'Текст новости' | 'basic'
2 | 1 | 'admin' | null | null | null | 'full'
3 | 1 | null | 2 | null | 'Текст пресс-релиза'| null
4 | 3 | 'sekretarsha'| null | null | null | 'none'
Храним все в одной таблице, контекст задается значениями колонок group_id и newsfeed_id. Свойства, заполненные NULL-ом берутся из строчки, на которую ссылаемся по parent_id. Что тут не нравится:
1. если выяснится, что на контекст влияет что-то еще, придется добавлять колонку (менять схему).
2. магическое деление строк на "настоящие" и "доопределяющие".
3. контекст можно задавать только равенством (если надо что-то типа "регистрация > 3 месяцев" - опять идем колдовать со схемой).
Развиваю мысль дальше. Окей, раз мы не знаем точно, как устроен контекст, сделаем для него что-то типа Entity-Attribute-Value:
field:
field_id | context_id | label | description | buttons
context:
context_id | parent_context_id
context_definition:
context_id | property | operator | value
Теперь наследуются не поля, а контексты (хм, хорошо ли это?). Контекст определяется набором атрибутов, причем для атрибута мы можем задавать не только условие равенства, но и что-то более хитрое. Например, определить секретарш, зарегистрированных дольше 3х месяцев:
context_id | property | operator | value
--------------------------------------------------
1 | 'reg_age' | > | 7776000
1 | 'group' | = | 'sekretarsha'
Понятно, что можно составить список всех атрибутов и вместо кода атрибута хранить id.
Можно и на этом не останавливаться, а оставить в табличке field только то, что точно не может быть переопределено, а все прочие значения тоже хранить в EAV с фильтром по контексту - избавимся от "магических" (ненастоящих) строчек в основной таблице, ну и вообще сможем использовать эту конструкцию для всех таких случаев (чтобы не трогать схему никогда). О ужас, что-то такое:
value_definition:
entity_type | entity_id | context_id | property | value
Но блин... все это сильно пахнет велосипедом :)
Хочу спросить уважаемое сообщество: существует ли какой-то паттерн под этот класс задач, или продукт, где это реализовано в реюзабельном виде? Или хоть по каким словам гуглить :)
Похожие задачи:
- настроить внешний вид блока на сайте в зависимости от текущего раздела / юзера / источника перехода / запущенного A/B-теста и т.д.
- настроить права на операции над объектом в зависимости от групп юзера / свойств объекта / принадлежности объекта юзеру / фазы луны и т.д.
- задать скидку на товар в зависимости от...
Данных мало, можно все вытянуть двумя запросами и раскидать как надо уже в памяти.