Перейти к основному содержимому

Использование тегов Pimcore для фильтрации во внешнем интерфейсе

Функциональность тегов Pimcore в первую очередь предназначена для использования в административной панели (Backend UI) для маркировки и фильтрации элементов. Тем не менее, иногда бывает полезно реализовать пользовательскую фильтрацию на фронтенде, основанную на этих тегах.

Назначение тегов

Приведенные ниже фрагменты кода помогут вам начать реализацию этой задачи.

Подготовка данных для шаблона

Подготовка данных сильно зависит от вашего шаблона и того, как вы хотите визуализировать иерархию тегов.

Например, вы можете построить дерево тегов на базе библиотеки Bootstrap Treeview.

фильтр по тегам во фронтенде

Для этого можно использовать код, аналогичный приведенному ниже:

<?php   

//Подготовка данных для шаблона в контроллере
$tagList = new \Pimcore\Model\Element\Tag\Listing();

//Выбор родительского узла для тегов или использование всех корневых тегов
if ($this->getParam("node")) {
$tagList->setCondition("parentId = ?", $request->query->getInt("node"));
} else {
$tagList->setCondition("ISNULL(parentId) OR parentId = 0");
}
$tagList->setOrderKey("name");
$tags = [];
foreach ($tagList->load() as $tag) {
$tags[] = $this->convertTagToArray($tag, $request->query->get('tags-filter'));
}

<?php   
/**
* Функция для преобразования тегов в массив, ожидаемый bootstrap tree view
*/
protected function convertTagToArray(\Pimcore\Model\Element\Tag $tag, $assignedTagIds)
{
$tagArray = [
"id" => $tag->getId(),
"text" => $tag->getName()
];
$state = [];
$state["checked"] = array_search($tag->getId(), $assignedTagIds) !== false;
$tagArray["state"] = $state;
$children = $tag->getChildren();
foreach ($children as $child) {
$childrenNodes = $this->convertTagToArray($child, $assignedTagIds);
if($this->hasCheckedNodes($childrenNodes)) {
$tagArray["state"]["expanded"] = true;
}
$tagArray['nodes'][] = $childrenNodes;
}
return $tagArray;
}

protected function hasCheckedNodes($nodesArray) {
$it = new \RecursiveIteratorIterator(
new \ParentIterator(new \RecursiveArrayIterator($nodesArray)),
\RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $key => $value) {
if ($key == 'state' && $value['checked']) {
return true;
}
}
return false;
}


// скрипт инициализации bootstrap treeview

$tree = $('#filter-tag-tree');
$tree.treeview({data: <?=json_encode($this->tagTree)?>, showCheckbox: true, levels: 1});


Фильтрация элементов на основе тегов

Для фильтрации элементов по тегам необходимо использовать расширенные SQL-запросы в листинге элементов. Ниже приведен пример фильтрации для списка ассетов. Листинги других элементов (объектов, документов) работают аналогичным образом.

Важно знать:

  • Теги и их иерархия хранятся в таблице tags.
  • В таблице tags есть колонка idPath, которая полезна для поиска тега вместе со всеми его дочерними тегами.
  • Связи тегов с элементами хранятся в таблице tags_assignment.
<?php  
public function filterForTags(Asset\Listing $listing, Request $request): Asset\Listing
{
//Получаем ID тегов для фильтрации (например, из параметров запроса)
$values = $request->query->all('tags-filter') ?: explode(',', $request->query->getString('tags-filter'));

if($values)
{
$conditionParts = [];
foreach ($values as $tagId) {

//Решаем, нужно ли учитывать дочерние теги
if ($request->query->getBool("considerChildTags")) {
$tag = \Pimcore\Model\Element\Tag::getById((int)$tagId);
if ($tag) {
//Получаем полный путь ID тега для фильтрации дочерних элементов
$tagPath = $tag->getFullIdPath();

$conditionParts[] = "id IN (
SELECT cId FROM tags_assignment INNER JOIN tags ON tags.id = tags_assignment.tagid
WHERE
ctype = 'asset' AND
(id = " . (int) $tagId . " OR idPath LIKE " . $listing->quote(Db::get()->escapeLike($tagPath) . "%") . ")
)";
}
} else {
$conditionParts[] = "id IN (
SELECT cId FROM tags_assignment WHERE ctype = 'asset' AND tagid = " . (int) $tagId .
")";
}
}


if (count($conditionParts) > 0) {
$condition = implode(" AND ", $conditionParts);
$listing->addConditionParam($condition);
}
}
return $listing;
}



Вы можете предложить улучшение документации или задать вопрос в комментариях.
Если вам нужна полноценная консультация — вы можете заказать её на нашем сайте.