Жадная рекурсивная загрузка или Теги для тегов для тегов

Вопрос 1:

Как мне сделать теги для тегов?

Исходные условия - есть таблицы items, itemtags, tags

items - сущности

tags - теги

itemtags - связь сущностей и тегов

Но кроме этого в таблице tags есть поле itemid, которое связывает ее напрямую с item, поскольку в нашем случае tag также является сущностью, к которой можно привесить тег. Да, там крыша уезжает, можно бесконечную рекурсию замутить если захотеть.

Таким образом в модели Tags получается две связи на itemtags - первая для обычной связи, а вторая для связи through item, чтобы вытянуть теги тегов.

Вопрос в чем - как следить за конфликтом имен? Тупо создать связь itemtags и вторую itemtags2?

Есть ли способ удобнее?

скажем так "более стандартное решение", чтобы его принять как данность и всегда применять.

====

Вопрос 2:

Как работать с limit при together?

Я использую 1.1.16 и ActiveRecord, при помощи with.

Исходные условия те же, что и в Вопросе 1.

Если писать конструкцию вида:




Items::model()->with(array(

  'itemtags' => array(

    'with' => array(

      'tags' => array(

        'with' => array(

          'itemtags' => array(

              'alias' => 'tag_itemtags',

              'with' => array(

                'tags' => array(

                  'alias' => 'tag_tags'

                )

              )

            ),

          ),

        ),

      ),

    ),

  ),

))->find($criteria);



То в принципе все работает.

Я пытаюсь сократить код, создавая в модели связи с through, навроде:




'itemtags' => array(self::HAS_MANY, 'Itemtags', 'tagid'),

'item' => array(self::BELONGS_TO, 'Items', 'itemid'),

'self_itemtags' => array(self::HAS_MANY, 'Itemtags', array('id' => 'itemid'), 'through' => 'item'),

'tags' => array(self::HAS_MANY, 'Tags', array('tagid' => 'id'), 'through' => 'self_itemtags'),

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

На уровне примеров это:

На сайте есть картинки.

Картинки бывают логотипы

Картинки бывают иконки

Картинки бывают обои

То есть получится примерно:

Тег Картинки

Тег Логотипы

Тег Иконки

Тег Обои

При этом Картинки - старший. И зачем каждой записи присваивать Логотипы и Картинки, если можно присвоить Логотипы, а к самому тегу Логотипы прилепить тег Картинки. Таким образом обеспечив поиск по тегу Картинки всем, у кого есть хотя бы один тег Логотипы, Иконки или Обои. И это можно до неограниченной вложенности делать. Рекурсия получается.

Пример другого такого запроса:

На сайте есть:

сущности Items

теги Tags

картинки Images

страницы Pages

Страницы, Картинки и Теги являются сущностями

Сущности могут иметь теги.

Где-то в этом месте пытаешься вытянуть все для всего, включая теги для тегов. Получается несколько раз использование связи itemtags, которая в модели написана один раз, и соответственно ее alias не меняется. Но даже если решить конфликт имен, проставив alias всем связям и убрать все through связи, то:

Ставишь together => true.

Получается единый запрос.

Но стоит к нему дописать limit, когда тебе нужно вытянуть например

Ровно 5

страниц с тегами и тегами тегов

с их картинками с тегами и тегами тегов

с их тегами с тегами тегов

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

Убираешь together, и получается, что нужно CDbCriteria приходится писать для каждой связи заново.

Как это сделать удобнее?

Ладно, вот мой запрос:




$_items = Items::model()->with(

      array(

        'images' => array(

          'select' => 'imgurl',

          'together' => true,

          'with' => array(

            'item' => array(

              'together' => true,

              'alias' => 'image_item',

              'with' => array(

                'tags' => array(

                  'select' => 'tag',

                  'alias' => 'image_tags',

                  'together' => true

                ),

              )

            )

          ),

        ),

        'tags' => array(

          'select' => 'tag',

          'together' => true

        ),

      )

    )->findAll($criteria);



Фото карты БД:

Сейчас запрос работает, но при этом создает лишнюю вложенность, когда для Image сначала вытаскивается Item, а потом для него вытаскивается Tag. Хотелось бы убрать этот уровень на уровне Yii

Как мне сделать напрямую Tags из Images, какие связи нужно создать в YII и как при этом следить за конфликтом имен столбцов.