Связывание нодов "многие ко многим" при помощи CCK

28 апреля 2008 в 2:00

На семинаре по Друпалу я приводил пример связывания документов с помощью модуля CCK: есть ноды типа "авто", есть ноды типа "деталь для авто". Для всех авто можно указать список деталей, из которых автомобиль состоит, для всех деталей можно указать в каких автомобилях эта деталь используется. Далее, при просмотре соответствующего документа можно увидеть список все связанных нод.

Этот пример вызвал ряд вопросов, по этому здесь я более подробно опишу как реализовать такую связь.

1. Для начала нужно скачать модуль CCK и скопировать его в папку "sites/all/modules". Далее в меню "admin/build/modules" необходимо активировать модуль Content и Node Reference. Это минимально необходимые для моего примера модули, однако стоит активировать и все остальные пункты из группы CCK, так как они могут оказаться полезными для других целей.

2. Теперь нужно создать типы материалов, которые мы будем друг с другом связывать. Для этого в меню Content types ("admin/content/types") нужно выбрать таб "Add content type" и создать тип материала с человекопонятным именем (Name) "Автомобиль" и компьютеропонятным именем (Type) "auto", сохранить изменения и создать еще один тип контента с Name = "Деталь автомобиля" и Type = "auto_detail".

3. После того как мы создали новые типы материалов в них нужно добавить поля, которые свяжут автомобили и детали друг с другом. В меню Content types необходимо щелкнуть по ссылке"Edit" возле типа конетнта "Автомобиль", и выбрать таб "Add field". В строке "Name" надо задать машиннопонятное имя для создаваемого поля, например "auto_detail", а в качестве Field Type выбрать Node Reference, Autocomplete Text Field. После нажатия кнопки Create Field можно задать человекопонятное название для этого поля, выбрать будет ли поле обязательным и можно ли будет в него вносить несколько значений. Также надо указать, что это поле будет связано (Content types that can be referenced) с типом материала "Деталь автомобиля".

Те же действия, надо проделать и для типа "Деталь автомобиля", только в качестве машиннопонятного имени нового поля указать надо "auto", а в качестве типа связанного материала – "Автомобиль".

4. Вот и все. Теперь можно создать материал типа "Автомобиль" (пока привязывать его не к чему), затем создать материал типа "Деталь автомобиля" и привязать его к существующему авто. После того как "Деталь автомобиля" создана можно вернуться в наш первый "Автомобиль" и связать его с этой деталью.

5. Для того, чтобы кастомизировать стандартный вывод "связанных" ссылок, в папке темы скопируйте файл node.tpl.php под именем node-auto.tpl.php и используйте в нем переменные вида:

<?php
// Цикл по всем связанным нодам
for($i = 0; $i <= count($node->field_auto_detail) - 1; $i++){
print "nid = " . $node->field_auto_detail[$i]['nid'] . "
";
print "view = " . $node->field_auto_detail[$i]['view'] . "

";
}
?>



У этого примера есть один недостаток: если материал А связан с материалом Б, то это не значит, что материал Б связан с материалом А. Другими словами, если мы связали А с Б, но не связали Б с А, то на странице А будет ссылка на Б, но на странице Б не будет ссылки на А.

Если эту задачу решать с помощью Node API, то эту особенность CCK можно обойти.

update от direqtor:

Есть же тип поля для CCK - Node Referer вроде бы. Автоматом создает обратные ссылки на те материалы, которые ссылаются на данный: http://drupal.org/project/nodereferrer.

Так что проблема "односторонних" связей решена.

Комментарии

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

28 апреля 2008 в 3:31

Есть же тип поля для CCK - Node Referer вроде бы. Автоматом создает обратные ссылки на те материалы, которые ссылаются на данный.

28 апреля 2008 в 12:38

PopoFF wrote:
http://drupal.ru/node/12423

Белая страница у меня когда ссылаюсь на много нод - перегруз.

Огаога, и версия там старая девелоперская.
Я таки жажду увидеть радостное альтернативное решение.. -)

1 мая 2008 в 21:49

>Если эту задачу решать с помощью Node API, то эту особенность CCK можно обойти.

А можно поподробнее на этом моменте?.. -)

29 апреля 2008 в 18:57

Ромка, что-то такой способ не сильно хорош:

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

Не слишком много переходов туда сюда?

30 апреля 2008 в 16:41

gorr wrote:
Ромка, что-то такой способ не сильно хорош:

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

Не слишком много переходов туда сюда?

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

1 мая 2008 в 0:24

Ромка wrote:
gorr wrote:
Ромка, что-то такой способ не сильно хорош:

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

Не слишком много переходов туда сюда?

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


Следовало-бы сделать так:
Создаем авто, далее создаем деталь и указываем, что она относится к данному авто и при этом в материал авто также заносится ссылка на эту деталь(автоматически). Вот это удобно.)

2 мая 2008 в 15:47

gorr wrote:
Создаем авто, далее создаем деталь и указываем, что она относится к данному авто и при этом в материал авто также заносится ссылка на эту деталь(автоматически). Вот это удобно.)

Так это и делается при помощи Nodereferer, смотри обновление в первом посте.

3 мая 2008 в 14:17

Может я что-то не так понял.. но по ссылке из первого поста используется Node Reference, а Nodereferer это какой-то другой модуль.. -)

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

6 мая 2008 в 2:16

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

Мне как раз нужно разобраться как делать двойные связи и чтобы сцылки автоматом и там и там были, чтоб как по уставу. -)

По мне, так он просто не договорил, ибо имхо вся соль теммы в >Если эту задачу решать с помощью Node API, то эту особенность CCK можно обойти. -)

У этого примера есть один недостаток: если материал А связан с материалом Б, то это не значит, что материал Б связан с материалом А. Другими словами, если мы связали А с Б, но не связали Б с А, то на странице А будет ссылка на Б, но на странице Б не будет ссылки на А.

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

30 апреля 2008 в 17:53

Toshka wrote:
Мдаа если ты сам заполняешь базу таким образом, оно может ещё и сойдёт, а вот пользователям такой механизм уже конечно не откроешь. -(

Мне как раз нужно разобраться как делать двойные связи и чтобы сцылки автоматом и там и там были, чтоб как по уставу. -)

По мне, так он просто не договорил, ибо имхо вся соль теммы в >Если эту задачу решать с помощью Node API, то эту особенность CCK можно обойти. -)

У этого примера есть один недостаток: если материал А связан с материалом Б, то это не значит, что материал Б связан с материалом А. Другими словами, если мы связали А с Б, но не связали Б с А, то на странице А будет ссылка на Б, но на странице Б не будет ссылки на А.

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

Выше direqtor привел ссылку на модуль nodereferer, который как раз и реализует этот функционал. Ну а с использованием нод АПИ действительно можно сделать все по своему желанию, главное сформулировать это свое желание Lol

1 мая 2008 в 0:26

Ромка wrote:

Выше direqtor привел ссылку на модуль nodereferer, который как раз и реализует этот функционал. Ну а с использованием нод АПИ действительно можно сделать все по своему желанию, главное сформулировать это свое желание :))

Smile Smile Есть же модуль...
Ни к чему истреблять воробьев ядерными боеголовками.

1 мая 2008 в 8:47

Чтобы пример был понятен приведу со своего проекта.
Тип материала Объявление
Одно: http://trade.asiadata.ru/ru/node/281
Второе: http://trade.asiadata.ru/ru/node/40
Внизу через Node REFERENCE показывается тизер фирмы его разместившей.

Тип материала: Фирма - http://trade.asiadata.ru/ru/node/37
Внизу список всех ее объявлений через поле Node REFERER

При размещении объявления выбирается Фирма, а ссылка в самой Фирме создается автоматом.

Применительно к автомобилям и деталям оба поля можно сделать многозначными.
Тогда в одной детали можно ссылаться на несколько авто. Тогда в каждом автомобиле можно видеть список запчастей.

Вообще, во-многом эта связка Reference - Referer выполняет таксономические задачи.

6 мая 2008 в 5:48

а может ли обычный пользователь создавать связь? или это прерогатива только админа? Например, связь со своей анкетой юзера и определенной нодой?

8 мая 2008 в 12:37

НовичОК wrote:
а может ли обычный пользователь создавать связь? или это прерогатива только админа? Например, связь со своей анкетой юзера и определенной нодой?

Да, может.

8 мая 2008 в 17:27

Модуль под 6й не работает?
Я правильно понял что для его использования нужен CKK + Node Reference + собственно он сам?

11 мая 2008 в 17:26

А Node Relativity кстати говоря дурной совсем, я его тестировал...
Меню действий над дочерними нодами находиться прямо в ноде и там ссылки присоединения, ссылка там имеет вид, отличный от простого создания ноды добавлением к концу ссылки пометки принадлежности к нод релативити...
Так вот трабла заключается в том, что если создавать материал не с той менющки, то не будет возможности присоединить ноду, а зарегистрированный польщователь не видит этого меню и воспользоваться присоединением не может, что было для меня обломно.. хотя в той менюшке я видел ссылку как я понял на присоединения ноды, полагаю, что механизм макой - пользователь создаёт ноду обычным способом, а админ потом смотрит и присоединяет, жаль только у меня по этой ссылке не генерился список созданных и ещё не присоединённых нод..
Вобщем я опплевался. -)

18 мая 2008 в 0:18

Toshka, какую то ерунду вы пишете, вы видимо просто не поняли, что правом присоединенияк ноде имеет только хозяин НОДЫ - то есть вы создали Автомобиль - и только вы имеете право присоединить к ней детали, и никто другой. Чё вы понаписали - непонятно....

18 мая 2008 в 0:35

Я использую для связей :
1) CCK ( http://drupal.org/project/cck ), поле node reference
2) Для обратной ссылки viewfiled ( http://drupal.org/project/viewfield ) и ReferencedByFilter ( http://drupal.org/project/ReferencedByFilter )
Этот подход не требует обратного связывания.

30 мая 2008 в 13:02

Вопрос к sas@drupal.org: можно уточнить ваши настройки view модуля ReferencedByFilter?
Если я правильно понял, то при передаче этому view номера ноды должен высыпаться список нод, которые на переданную ссылаются.
У меня при просмотре этого view с переданным номером ноды, на которую гарантированно ссылается лишь одна другая нода, вываливаются все опубликованные ноды. Хэлп по этому модулю куцый (только readme.txt), видимо я что-то не так прописал. Заранее благодарю!

2 июля 2008 в 1:27
Аватар пользователя BMW BMW 0

Топик старый, но вдруг кому-то понадобиться.
На мой взгляд лучше честно, добавлять обратные ссылки, к текущим. Использую при этом стандартное, или почти стандартное cck поле (не заводя отдельных полей как в nodeReferrer).

Для этого в 6 есть 2 модуля, cnr и
backreference.

24 февраля 2011 в 15:22

У меня такой вопрос, на который я до сих пор не могу найти ответ.

Допустим, все, что описано в топике - сделано.
Была создана страница с автомобилем MMW-320. Как сделать так, чтобы ЛЮБОЙ пользователь, нажав на специальную ссылку на этой странице, перейти к форме добавления Детали, конкретно к этому авто?

То есть, в ссылке на форму, очевидно, должен передаваться id ноды (bmw-320), это не сложно сделать. А вот как сделать, чтобы на странице добавления детали в поле выбора автомобиля автоматически выбирался пункт bmw-320?

Тут хуками или как решать задачу?

15 апреля 2011 в 19:48

"Zonder" wrote:
Как сделать так, чтобы ЛЮБОЙ пользователь, нажав на специальную ссылку на этой странице, перейти к форме добавления Детали, конкретно к этому авто?

"direqtor" wrote:
Все уже придумано до нас!

[module=nodereference_url]

за 3 года, по видимому, ничего не изменилось Wink

У меня вот другой вопрос. Как на странице ноды получить список нод к которым привязана исходная (не наоборот). cnr не подходит, т.к. Обратная связь мне не нужна.

18 апреля 2011 в 13:18
Аватар пользователя BMW BMW 0

"<a href="mailto:Sentrashy@drupal.org">Sentrashy@drupal.org</a>" wrote:
получить список нод к которым привязана исходная (не наоборот). cnr не подходит

А каким образом вы связь осуществляли?

14 июля 2011 в 19:40

Мне как человеку, привыкшему работать с реляционными базами данных, описанный в статье способ представляется чудовищным. Обычно это делается следующим способом (попытаюсь объяснить это в терминах Drupal-а). Создаётся новый тип материала, который можно назвать "автомобиль-деталь" с двумя полями - ссылка на тип "автомобиль" и ссылка на тип "деталь". Разумеется, для этого нужно использовать модуль Node Reference (не понимаю, почему такого типа поля до сих пор нет в ядре). Чтобы привязать конкретный автомобиль к конкретной детали (или наоборот, что одно и то же), нужно создать новый узел типа "автомобиль-деталь" с указанием соответствующих полей. Разумеется, конечный пользователь не должен видеть ни типа "автомобиль-деталь", ни узлов этого типа.
Аналогичный способ реализован в модуле Relation. Но там больше вопросов, чем ответов.

4 сентября 2011 в 12:10

"Nikki" wrote:
Мне как человеку, привыкшему работать с реляционными базами данных, описанный в статье способ представляется чудовищным. Обычно это делается следующим способом (попытаюсь объяснить это в терминах Drupal-а). Создаётся новый тип материала, который можно назвать "автомобиль-деталь" с двумя полями - ссылка на тип "автомобиль" и ссылка на тип "деталь". Разумеется, для этого нужно использовать модуль Node Reference (не понимаю, почему такого типа поля до сих пор нет в ядре). Чтобы привязать конкретный автомобиль к конкретной детали (или наоборот, что одно и то же), нужно создать новый узел типа "автомобиль-деталь" с указанием соответствующих полей. Разумеется, конечный пользователь не должен видеть ни типа "автомобиль-деталь", ни узлов этого типа.
Аналогичный способ реализован в модуле Relation. Но там больше вопросов, чем ответов
Изящно. Однако в этом способе тоже больше вопросов, чем ответов.

4 сентября 2011 в 12:33

"Nikki" wrote:
Мне как человеку, привыкшему работать с реляционными базами данных,

Топикстартеру: добавьте еще один update от меня.
http://drupal.org/project/cnr - это то, что директор Smile доктор прописал. Делаем nodereference-поле с А на Б и nodereference-поле с Б на А. Потом через Corresponding node references связываем их вместе. Теперь связь можно видеть и редактировать как в А, так и в Б - поля синхронизируется автоматически.

10 сентября 2011 в 9:24

"direqtor" wrote:
Топикстартеру: добавьте еще один update от меня.
http://drupal.org/project/cnr - это то, что директор Smile доктор прописал. Делаем nodereference-поле с А на Б и nodereference-поле с Б на А. Потом через Corresponding node references связываем их вместе. Теперь связь можно видеть и редактировать как в А, так и в Б - поля синхронизируется автоматически.

никакуих проблем не возникало? у меня почему-то никак не синхронизируются.

14 февраля 2013 в 9:08