Модуль наследование бандлов (типов сущностей \ содержимого)

Аватар пользователя lemark lemark 20 октября 2011 в 4:10

Написал небольшой модуль позволяющий наследовать любые типы сущностей (бандлы).
Формально, модуль состоит из двух модулей.

Первый (bundle_inherit) не дает никакого функционала конечному пользователю, но предоставляет разработчикам возможность добавить к своим сущностям логику наследования.
Второй (bundle_inherit_node) использует Bundle Inherit API (функциональность модуля bundle_inherit) для расширения модуля node. При создании нового типа содержимого он позволяет наследовать его от любого другого типа той же сущности.

Наследование производится по отношению полей (fields). Наследование может быть двух типов:
Soft: Просто прикрепляет к новому типу те же поля, что есть в старом. Далее оба типа никак не отслеживаются и не синхронизируются.
Strict: Второй привязывает новосозданный тип к родительскому. Это значит что:
- Нельзя удалять или редактировать унаследованные поля в дочернем типе.
- Если к родительскому типу добавляется поле, оно автоматически добавляется ко всем дочерним типам.
- Если в родительском типе изменяется поле, оно также автоматически изменяется во всех унаследованных типах.
- Если поле удаляется из родительского типа, оно автоматически разблокируется во всех дочерних типах.

Модуль еще крайне сырой и практически не задокументирован. Выставляю "as is" дабы получить какой-то фидбэк и понять куда развивать его дальше.
Модуль уже не так сыр :) Прошел валидацию на друпалорге и на днях получил свой первый альфа релиз.

Есть например задумка не ограничиваться наследованием полей, но предоставить модулям возможность определять для своих типов собственные алгоритмы наследования, подчиненные общей логике Bundle Inherit API.

Собственно модуль размещен в двух репозиториях:
Drupal.org: http://drupal.org/project/bundle_inherit
Github: https://github.com/numesmat/Drupal-Bundle-Inherit

UPDATE:На гитхабе проект изначально размещался из-за ограничений песочницы на друпалорге и не вполне ясных перспектив преобразования в полный проект. Т.к. проект все таки вышел из песочницы и теперь имеет полноценную прописку на друпалорге, гит репозиторий возможно вскоре будет заморожен. В связи с чем настоятельно рекомендую пользоваться репозиторием друпалорга.

Немного более развернутая статья на хабре: http://habrahabr.ru/blogs/drupal/130870/

0 Thanks

Комментарии

Аватар пользователя lemark lemark 2 ноября 2011 в 23:59

Оно же в архиве: https://github.com/downloads/numesmat/Drupal-Bundle-Inherit/bundle_inher...
Сразу говорю, что архив будет обновляться несколько реже чем будут делаться коммиты.

UPDATE: архив более обновляться не будет т.к. модуль был официально размещен как проект на друпалорге: http://drupal.org/project/bundle_inherit

Аватар пользователя lemark lemark 20 октября 2011 в 7:23

Ну изначально он писался для интернет магазина.
Например есть тип товара "телевизоры" и подтип "плазменные панели". Тип "плазменные панели" всегда должен содержать все поля родительского типа + содержит некоторый набор полей характерных только для него.
Кроме того наследование сквозное. Т.е. к примеру указанную выше схему можно было бы расширить унаследовав тип "телевизоры" от типа "электроника".

А вообще подход актуален во всех случаях когда в типах должна быть какая-то иерархия. На новостном портале например может быть тип "новость" и подтип "происшествие". В подтип можно добавить поле с гуглкартой где будет отмечено место происшествия.

А весь профит собственно заключается в том, что если возникнет необходимость в изменении родительского типа и подтипов, достаточно будет отредактировать набор полей родительского типа.

Уже после написания модуля наткнулся на друпалорге на топик где предлагается подобный функционал реализовать. Там еще хорошая идея есть по поводу создания абстрактных типов. Т.е. типов от которых можно только наследовать другие типы но не создавать сущности этих типов. Собственно топик: http://drupal.org/node/100925

Аватар пользователя Ch Ch 20 октября 2011 в 10:24

Ого, ООП в сущностях. :-) Осталось только множественное наследование внедрить.
Кстати, вот ещё новый модуль для создания сущностей: ECK

Аватар пользователя lemark lemark 20 октября 2011 в 15:47
"Ch" wrote:

стати, вот ещё новый модуль для создания сущностей

Мне кажется это немного убивает концепцию сущностей. В том плане что сущности изначально не были ориентированы на end user usage. Это прежде всего инструмент для разработчика. Для конечного пользователя в базовую комплектацию включен модуль node который как раз и позволяет создавать новые типы материалов, сущности на их основе и т.п. Может конечно в этом ECK и есть какой-то смысл, но я пока его не вижу :)

Аватар пользователя lemark lemark 20 октября 2011 в 16:39
"Ch" wrote:

CCK тоже как бы для разработчиков прежде всего

Я имею ввиду разработчиков которые модули пишут)
А CCK был в 7ке встроен в ядро и как самостоятельный проект фактически доживает свои последние деньки.
Правда из него выделилась пара классных проектов. Как Field group например.

Аватар пользователя UnnamedNETUA UnnamedNETUA 20 октября 2011 в 20:18

Есть тип недвижимость, есть ее подтипы, квартиры, дома и тд, где есть поля как и общие так и отдельные (допустим гараж, там поле (метал или кирпич).
Правильно я понял, что я создам тип недвижимость, там накидаю это все, а потом создам "наборы"?

Можно скрин создания дочернего типа?

Аватар пользователя UnnamedNETUA UnnamedNETUA 21 октября 2011 в 10:34

Посмотрел, увидел что да, во втором типе нет настроек поля, они берутся из первого типа содержимого, но создав свое содержимое, вставив туда field_bf он создался, и со своими настройками, а field_cf уже не дает добавить, ибо уже оно где то есть.
В общем вижу что работает, но у вас, сам создал 2 типа, и не вижу где связывать их с друг другом и поля внутри. :(

Аватар пользователя lemark lemark 21 октября 2011 в 14:33

Тип можно связать с другим типом только при создании. В процессе создания задаете настройки во вкладке inherit.
С полями в Drupal такая штука. Есть два понятия. Поле и экземпляр поля. Экземпляр каждого поля может присутствовать по одному разу в каждом типе. Если вы пытаетесь добавить в родительский тип существующее поле (там где existing field) то модуль проверяет нет ли экземпляра этого поля в дочерних типах. Проверяет т.к. не может прикрепить еще один экземпляр поля при наследовании. Пока я выбрал запрещающую политику в таких случаях, однако подумываю сделать так чтобы модуль мог запрашивать разрешение пользователя и заменять в дочернем типе настройки уже существующего поля при добавлении экземпляра этого поля в родительский тип.

Надеюсь более менее понятно объяснил)

P.S. Набросал статью на хабр, там немного подробнее все описано: http://habrahabr.ru/blogs/drupal/130870/

Аватар пользователя Orion76 Orion76 15 февраля 2012 в 15:59

Наследование от нескольких родительских типов будет..

Полезно, например, былобы для добавления Наборов полей.
Например есть товар дрель..
Она имеет габариты:
Длина
ширина
высота

Имеет эл.характеристики:
Вольтаж
Ампертаж
Мощность

Есть другие товары, которые имеют габариты и не имеют эл.характеристик и наоборот.

Мне кажется, было бы намного удобнее, особенно при создании большого количества типов товаров, добавлять сразу группы полей(наследуемые от нескольких родительских типов).
Например просто проставил галки: габариты, эл.характеристили и т.д. и новый тип материала готов-))

Вроде понятно сформулировал?-))

Аватар пользователя 1Andres 1Andres 16 января в 13:02

Поддерживаю идею Orion76. В поиске решения этой проблемы решил написать в поиске "наследование типа материала товар drupal" и попал сюда.
 
Field_collection решает эту проблему, пробовал но мне не понравилось это решение, так как:
 

  1. Плодит сущности (хорошо когда просто все поля просто в одной ноде, не надо вспоминать где электрические поля, где габаритные) - как следствие усложняет архитектуру
  2. Во вьюсе проще работать с нативными полями которые входят в ноду, а не фиелд колекшными, которые нужно подключать через Связи (Отношения). Можно не добавлять связей, а запилить в качестве поля весь филд колекшин, но тогда пропадает гибкость выстраивания нужного порядка полей и их форматирования
  3. Излишние Связи (Отношения) во вьюс уменьшает производительность (установленный факт), кажется там появляются дополнительные запросы к БД (в этом не силён, не проверял, подсказывает чутьё)))
  4. Программный вывод филд коллекшн полей затруднён: Нельзя просто написать: $node->fc_electicheskie_polya->napryagenie. Нужно сначала выяснить ID филд коллекшн, потом загрузить этот филд коллекшн, и из него тянуть нужные поля..
Аватар пользователя Orion76 Orion76 16 января в 15:10
2

А я не поддерживаю идею того Orion76 "шестилетней давности"
Есть более простые и удобные способы-принципы организации данного функционала-)

Аватар пользователя 1Andres 1Andres 17 января в 7:41

Ужасно интересно.
Поделитесь, пожалуйста, в двух словах или двух названиях модулей. )

Аватар пользователя Orion76 Orion76 17 января в 9:50
2

Если необходимо каждому товару (или т.п. сущности) назначить произвольный список характеристик со значениями.
Как-то однозначно организовать ввод данных характеристик, чтобы потом по ним можно было фильтровать, сортировать, группировать связанные с ними товары, то способ такой..

Термины и определения:
1.Справочник - некий предопределенный список значений, например список цветов, список размеров одежды и т.п.
Обычно храниться в словаре таксономии или поле типа Список
2.Произвольное значение - значение типа число или строка, для которого нет смысла хранить "предопределенные значения", например вес, длина, ширина и т.п. Вводится пользователем вручную в поле типа "текст".
3.Единицы измерения - необходимы для Произвольных значений для указания их единиц измерения ,
например ширина: 20 см, длина: 1.5 м и т.п.

Наименования характеристик логичнее хранить в словаре таксономии

есть 2 типа характеристик:
1. Тип значения - Справочник.
Поля:
- Наименование характеристики (Справочник)
- Значение характеристики (Справочник)

2.Тип значения - Произвольное значение
Поля:
- Наименование характеристики (Справочник)
- Значение характеристики (Произвольное значение)
- Единица измерения (Справочник)

Итого для описания характеристики получается 2 сущности с разными наборами полей.
Добавляем в товар многострочное поле Характеристик типа entity reference (ссылка на сущность)
И все..
Мы можем добавлять к товару любое кол-во характеристик с любыми необходимыми значениями.

Если список типов товаров на сайте достаточно большой и необходимо как-то систематизировать ввод характеристик типов товаров, тот тут как-раз и можно применить метод, похожий на наследование.

Товары обычно категоризируют при помощи иерархического каталога.
Обычно этот каталог строиться при помощи словаря таксономии (пример):
1.Одежда
- Верхняя
- - Пальто
- - Шубы
2.Мобильные устройства
- Сматрофон
- Планшет
и т.п.

Т.е. что получается.
У всех товаров раздела Одежда есть характеристика: Размер
У всех товаров раздела Одежда - Верхняя есть характеристика: Сезон
У всех товаров раздела Одежда - Верхняя - Шубы есть характеристика: Тип меха

У всех товаров раздела Мобильные устройства есть характеристики: операционная система, тип процессора, размер оперативной памяти и т.п.

Т.е. можно заранее назначить разделам каталога список необходимых характеристик, по иерархии от общих к все более индивидуальным.
Т.е. просто добавив к термину таксономии каталога многострочное поле "Список характеристик" для ввода наименования характеристик, используемых для товаров данного раздела.

И при вводе товара в определенный раздел каталога сразу выводить на форму список характеристик, специфичных для данного раздела и его "родителей" выше по иерархии (плюс любые произвольные)

В краце как-то так.

Теоретически, что-то подобное можно и мышкой накликать и немного доработать специальным модулем.
Но было бы удобнее, если бы весь данный функционал предоставлялся специальным модулем.

Сейчас как раз на одном проекте такое "пишется".
Когда-нибудь, возможно скоро будет готово-)

Аватар пользователя 1Andres 1Andres 18 января в 6:14

Большое спасибо.
Только в голове мне трудно исполнить этот псевдокод. )
  

Не понимаю как работают следующие моменты (после этого я потерял логическую нить):
 

Добавляем в товар многострочное поле Характеристик типа entity reference (ссылка на сущность)
И все..

Понимаю, что такое "многострочное поле Характеристик типа entity reference". Не понимаю как этим пользоваться в данном случае..
 

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

Что подразумевается под словами "выводить на форму" не понял.
  

И как следствие не могу представить ответы на 3 волнующих вопроса:
 

  1. Как можно фильтровать, сортировать, группировать такие товары?
  2. Как выводить эти характеристики на странице товара (если это возможно, важно в определённом, единообразном для всех товаров, порядке)?
  3. Как выводить часть заданных характеристик в листинге товаров (например в листинге нужно только самое необходимое для краткости: Диагональ экрана смартфона и Объём оперативной памяти)

  

В свободное время попробую сделать прототип используя этот подход, должно стать яснее.
  

Если можно, скиньте пожалуйста ссылку на пример каталога с фильтром, построенный на этих принципах (можно и в ЛС).

  

И ещё вопрос: Этот принцип улучшает производительность? в сравнение с:
 
Использованием большого кол-во типов материалов (у меня 70), и использования вместо ваших принципов: Метод создания кучи технических характеристик отдельными полями (у меня 570, некоторые из них пересекаются по типам, но не так уж и много, некоторые дублируются (знаю это большой грех, надеюсь дойдут руки поправить)).

Аватар пользователя Orion76 Orion76 18 января в 9:57
1

схемка данных https://drive.google.com/file/d/15r3wTbmiSqxrqiaqts3AdA0Uz_SzQZfc/view?u...

1Andres wrote:

Понимаю, что такое "многострочное поле Характеристик типа entity reference". Не понимаю как этим пользоваться в данном случае..

Тот же принцип как и работа поля модуля Paragraphs.

Поле характеристики товара имеет тип Ссылка на сущность
Может ссылаться на типы сущностей
- Характеристика "Справочник"
- Характеристика "Значение"

Если необходимо добавить к товару характеристику Цвет
добавляем в поле Характеристики ссылку на сущность типа Характеристика "Справочник"
в добавленной сущности:
в поле Наименование выбираем из списка "Цвет"
в поле Значение выбираем из списка "Красный"

Если необходимо добавить к товару характеристику Длина
добавляем в поле Характеристики ссылку на сущность типа Характеристика "Значение"
в добавленной сущности:
в поле Наименование выбираем из списка "Длина"
в поле Значение вводим "123"
в поле Единицы измерения выбираем из списка "см"

1Andres wrote:

Что подразумевается под словами "выводить на форму" не понял.

В категории каталога храниться список Наименований характеристик товаров категории , например:
- размер
- цвет
- материал

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

1Andres wrote:

В свободное время попробую сделать прототип используя этот подход, должно стать яснее.

1. Рекомендую для сущностей Характеристики использовать модуль Paragraphs или Field Collection
ноды для характеристики слишком "много"
2.Возможно может пригодиться модуль Inline Entity Form ( https://www.drupal.org/project/inline_entity_form )

1Andres wrote:

И ещё вопрос: Этот принцип улучшает производительность? в сравнение с:

Это не про "производительность"..
Это про оптимальную структуру данных.
Нет необходимости добавлять 70 типов материалов
и 570 характеристик.

Достаточно ОДНОГО типа материала
ДВУХ типов материалов для хранения данных характеристик
И нескольких словарей таксономии для хранения предопределенных значений .

Т.е. при таком способе "расширение" списка типов товаров можно осуществлять банальным импортированием справочных данных (словарей таксономии) и непосредственно самих товаров.

А производительность..
Увеличение производительности достигается правильной организацией работы кэша.
Если товар не изменяется по нескольку раз в час, зачем каждый раз рендерить вывод товара?
Достаточно это сделать 1 раз после добавления-изменения товара.

Изменился товар
Сбросился кэш
При следующем выводе товара на страницу отрендирился и закэшировался вывод.
А далее показываем данные из кэша, пока товар не изменится.

Аватар пользователя 1Andres 1Andres 25 января в 19:15

Оооогромное спасибо, это бесценная информация.
 
 

Наконец появилось время создать прототип. Многое что прояснилось. Понял как хранятся характеристики (модуль параграфс делает понимание интуитивней)
 
 

Сформировалось ещё пара вопросов:
 

1) Понял как забивать характеристики вручную. Однако это будет утомительно..
 

В категории каталога храниться список Наименований характеристик товаров категории , например:
- размер
- цвет
- материал
 

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

 

Можно, пожалуйста поподробней или пример кода, который автоматически (программно) добавляет на форму добавления товара характеристики присущие "выбранному термину" и "родителю этого термина" по списку Наименований характеристик?
 
 

2)

Если товар не изменяется по нескольку раз в час, зачем каждый раз рендерить вывод товара?
Достаточно это сделать 1 раз после добавления-изменения товара.
 

Изменился товар
Сбросился кэш

 

Я это осознал примерно полгода назад. Странно, что нигде об этом не пишут, пытался найти по ключевикам в поиске, что бы увидеть хорошие практики, но ничего не нашёл..
 
 

Моя "хорошая практика":
 

Храню, так называемый main_render_html (осторожно, это может показаться смешным) в Full Html поле ноды или термина для которой этот "кэш" предназначен. А сохраняет и выводит его примерно такой php код:

<?php
// Выясняем есть ли кэш в ноде
if (!get__main_render_html_cache($node)){ // Если кэша нет - генерируем, сохраняем в поле ноды и выводим

    

$var_array['body'] = token_replace($node->body['und'][0]['value']);
    
    
    
$main_html_render render_shablon (__DIR__ '/node-group--katalog.content'$var_array);
    print 
saving__main_render_html_cache ($node$main_html_render);
    
} else { 
// Если кэш есть - просто выводим
    
print get__main_render_html_cache($node);
}
?>

 
 

Как это реализуете вы? Где хранится этот "долгоиграющий" кэш? Есть ли модуль или кастомный код?

Аватар пользователя Orion76 Orion76 25 января в 20:45
1Andres wrote:

Можно, пожалуйста поподробней или пример кода, который автоматически (программно) добавляет на форму добавления товара характеристики присущие "выбранному термину" и "родителю этого термина" по списку Наименований характеристик?

Список наименований характеристик, как я писал ранее должен храниться в термине категории товара.
Реализуем hook_form_alter для формы СОЗДАНИЯ товара.
В нем из термина категории товара подгружаем наименования характеристик и в список характеристик товара добавляем данные характеристики.

для удобной работы с полями сущностей, в том числе и "вложенных" почитайте это руководство:
http://xandeadx.ru/blog/drupal/549

1Andres wrote:

Как это реализуете вы? Где хранится этот "долгоиграющий" кэш? Есть ли модуль или кастомный код?

С кэшем все намного проще: https://www.drupal.org/docs/7/api/cache-api/cache-api-overview

по сути это 2 функции:
cache_get - получить кэш
cache_set - сохранить в кэш

https://www.drupal.org/docs/7/api/cache-api/cache-api-overview

принцип простой.
Кэшу нужен уникальный идентификатор .
обычно идентификатор составляется из префикса и уникального идентификатора кэшируемого контента.

<?php
$prefix
'my_node_cache' //(можно объявить как константу)
$id $node->nid;
$cid="{$prefix}:{$id}"  // my_node_cache:123
?>

далее пробуем получить данные из кэша по его $cid.
если в кэше они есть, используем их
если в кэше их нет, генерируем данные заново, сохраняем в кэш на будущее.

По ссылке выше есть пример, так же куча примеров в самом коде друпал.
Они все примерно однотипные, т.е. как описано выше.
ищутся поиском по коду по словам cache_get.

Аватар пользователя 1Andres 1Andres 28 января в 20:13

1) Спасибо за наводку, то есть hook_form_alter.
Может кому пригодится: здесь OldWarrior расказал решение для данного вопроса.
 
 

2)

по сути это 2 функции:
cache_get - получить кэш
cache_set - сохранить в кэш

cache_get / cache_set - сохраняет в общем кэш хранилище (таблица БД или file_cache в файлах или ещё где то). Когда я нажму Очистить все кэши : все кэшированные данные, в том числе Таблицы технических харрактеристик товаров очистятся, и им придётся генерироваться заново.
 

Если же "кэшировать" как я, в full_html поле Node - такой кэш хранится бесконечно долго - пока характеристики не изменятся, но характеристики товара никогда не меняются.
 

Может у вас есть идея как сделать тоже самое менее колхозно, или такое возможно реализовать с помощью cache_get / cache_set?
 
 

3)

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

 

Попытался настроить несколько открытых фильтров по Тех. хар. Views и столкнулся с тем, что ничего не выходит. Пробывал выводить во Views, и Содержимое, и Paragraphs.. Никак не получается. (оно и понятно, фильтры вью работают с одной сущностью row, а у нас многострочное поле Paragraphs в ноде, Абстактно думается: что тут нужно проходить Foreach по строкам поля ноды field_moi_paragraph_dlya_th, что бы установить соответствия заданным открытым фильтрам и характеристиками, но Views такое не умеет).

Или при таком способе невозможно настроить фильтрацию товаров по нескольким параметрам стандартным способом (натыкав во Views)? придётся кодить свои фильтры / сортировки для каталогов?

Аватар пользователя Artu Artu 30 марта 2013 в 15:37

для большого структуированного сайта то что нужно.
Прийдет время - буду тестить.

Аватар пользователя samodelkin samodelkin 22 декабря 2013 в 20:55

Скажите какая версия модуля более актуальна 7.x-1.0-альфа2 или 7.x-1.x-Dev? Смущает что альфа была аж 2011 году.

Аватар пользователя 1Andres 1Andres 17 января в 7:55

Спасибо за отличный модуль.
 
 
Есть пожелание: добавить поддержку наследования field_group.
 
Зачем: Как писал кто то в issue: "это будет естественно для данного модуля".

 
 

Например я делаю так: Создаю родительский тип материала Товар, в нём 4 вкладки (реализованные с помощью field_group)
1. Товар
- Заголовок
- Модель
- Цена
- Старая цена (перечёркнутая)
- Термин таксаномии
 

2. Тех. характеристики
- Габариты
- Электичество
 

3. Описание
- Полное описание
- Краткое описание (используется для листинга)
 

4. Изображения
- Поле для добавления изображений

  

И от него мне можно наследовать любую категорию товаров. Во вновь созданном типе почти всё готово: осталось только добавить специфичных тех. характеристик. Очень быстро! )

  

На данный момент придётся в каждом новом типе материала вручную создавать field_group (Их получается по 5 штук: 1 группа горизонтальных вкладок и 4 горизонтальные вкладки).

  
Нашёл патч в issues, может кому пригодится здесь.

Аватар пользователя 1Andres 1Andres 17 января в 12:49

Замечание:

Патч написан для dev версии модуля. При установке патча через Терминал " patch -p1 < field-group-support-1337278-3.patch" всё проходит отлично
 
Но dev версия сыпет ошибками, когда запускаешь обновления /update.php
 
Устанавливаем 7.x-1.0-alpha2. Ошибок при /update.php нет, отлично! Ставим патч:
 

patch -p1 < field-group-support-1337278-3.patch
patching file bundle_inherit.module
Hunk #1 FAILED at 24.
Hunk #2 FAILED at 109.
Hunk #3 FAILED at 117.
Hunk #4 FAILED at 137.
Hunk #5 FAILED at 162.
5 out of 5 hunks FAILED -- saving rejects to file bundle_inherit.module.rej

 
Упс..
 
Патчим руками. Всё путём! )