Я постараюсь сделать это как можно проще, но, боюсь, этот вариант использования выходит за рамки первоначального намерения Zend_Db. Это касается набора таблиц, которые у меня есть для разметки страниц (или чего-либо еще, например, документов) в CMS.
У меня есть три таблицы:
- Страницы (
pages
) - Теги (
tags
) - TagLink (
tags_link
), которая представляет собой таблицу связи "многие ко многим" между страницами и тегами.
Pages - это простая таблица (я удалил несущественные столбцы из кода ниже):
CREATE TABLE `pages` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
FULLTEXT KEY `search` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Теги тоже довольно просты, хотя есть самореференциальный столбец (parent_tag_id
):
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) NOT NULL,
`parent_tag_id` int(11) NOT NULL DEFAULT '0',
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `GetByParentTagId` (`parent_tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
TagLink снова довольно прост:
CREATE TABLE `tags_link` (
`tag_id` int(11) NOT NULL,
`module_type` varchar(50) NOT NULL,
`foreign_key` int(11) NOT NULL,
UNIQUE KEY `Unique` (`tag_id`,`module_type`,`foreign_key`),
KEY `Search` (`module_type`,`foreign_key`),
KEY `AllByTagId` (`tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Усложняющим фактором является то, что TagLink может ссылаться на любую другую таблицу в базе данных, а не только на страницы. Так что, если, например, у меня есть раздел загрузки документов, его тоже можно пометить. Чтобы облегчить этот способ работы, существует ключ с несколькими столбцами.
Чтобы прояснить это, я продемонстрирую пару запросов на вставку, которые могут выполняться при добавлении тегов в таблицу (например, Pages):
INSERT INTO `tags_link`
SET `tag_id` = '1',
`module_type` = 'Pages',
`foreign_key` = '2'
INSERT INTO `tags_link`
SET `tag_id` = '1',
`module_type` = 'Documents',
`foreign_key` = '3'
Как видите, столбец module_type
- это просто произвольная строка, описывающая, где находится внешний ключ. Это не имя таблицы, поскольку все, что имеет идентификатор, может иметь теги, связанные с ним, даже если это не обязательно в базе данных MySQL.
Теперь к Zend_Db_Table
$_referenceMap
в PageTable
:
protected $_referenceMap = array(
'TagLink' => array(
'columns' => 'id',
'refTableClass' => 'Models_Tag_TagLinkTable',
'refColumns' => 'foreign_key'
),
);
Но это не учитывает мой произвольный столбец module_type
и вернет любую TagLink с тем же внешним ключом. Очевидно, это плохо, потому что, например, вы получаете ссылки на теги для документов, смешанные со ссылками на страницы.
Итак, мой вопрос: как я могу учесть этот дополнительный столбец при настройке этой ссылки? Цель состоит в том, чтобы избежать наличия класса TagLink для каждого module_type
, как у меня сейчас.
Я бы предположил, что что-то вроде следующего может объяснить мои требования, хотя, очевидно, это не так:
protected $_referenceMap = array(
'TagLink' => array(
'columns' => 'id',
'refTableClass' => 'Models_Tag_TagLinkTable',
'refColumns' => 'foreign_key',
'where' => 'module_type = "Pages"'
),
);
Моя текущая реализация переопределяет метод _fetch
в Documents_TagLinkTable
следующим образом:
protected function _fetch(Zend_Db_Table_Select $select) {
$select->where("module_type = 'Documents_Secondary_Tags' OR module_type = 'Documents_Primary_Tags' OR module_type = 'Documents'");
return parent::_fetch($select);
}
Как видите, к любому объекту может быть добавлено более одного набора тегов.