Расширение фильтрации mFilter2 для тегов Tagger

mFilter2 — фильтрация найденных результатов.
Tagger — система управления тегами.

[[!mFilter2?
    &filters=`
        tagger|3:tgroup,
        tagger|1:tgroup,
        tagger|2:tgroup
    `
    &aliases=`
        tagger|3==cars,
        tagger|1==colors
    `
]]

3,1,2 — группы тегов Tagger-а.

Улучшенная версия от Евгения Шеронова:
<?php 
class taggerCustomFilter extends mse2FiltersHandler {
  
   /**
	 * Retrieves values from Tagger table
	 *
	 * @param array $fields
	 * @param array $ids
	 *
	 * @return array
	 */
	public function getTaggerValues(array $fields, array $ids) {
		$filters = array();
		
	    if(!$this->modx->addPackage('tagger',$this->modx->getOption('tagger.core_path',null,$this->modx->getOption('core_path').'components/tagger/').'model/')) {
	       return $filters; 
	    } 
        
		$q = $this->modx->newQuery('TaggerTagResource');
		$q->innerJoin('TaggerTag','TaggerTag','TaggerTag.id = TaggerTagResource.tag');
		$q->where(array('TaggerTagResource.resource:IN' => $ids,'TaggerTag.group:IN'=>$fields));
		$q->select(array('TaggerTagResource.resource,TaggerTag.tag,TaggerTag.group'));
		$tstart = microtime(true);
		if ($q->prepare() && $q->stmt->execute()) {
			$this->modx->queryTime += microtime(true) - $tstart;
			$this->modx->executedQueries++;
			while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
				foreach ($row as $k => $v) {
					$v = str_replace('"', '"', trim($v));
					
					if($k == 'tag') {
					    $k = $row['group'];
					}
					
					if ($k == 'resource' || $k == 'group') {
						continue;
					}
					elseif (isset($filters[$k][$v])) {
						$filters[$k][$v][$row['resource']] = $row['resource'];
					}
					else {
						$filters[$k][$v] = array($row['resource'] => $row['resource']);
					}
				}
			}
		}
		else {
			$this->modx->log(modX::LOG_LEVEL_ERROR, "[mSearch2] Error on get filter params.\nQuery: " . $q->toSQL() . "\nResponse: " . print_r($q->stmt->errorInfo(), 1));
		}

		return $filters;
	}
	
	/**
	 * Prepares values for filter
	 * Retrieves labels of tagger tags and replaces ids in array keys by it
	 *
	 * @param array $values
	 * @param string $name
	 *
	 * @return array Prepared values
	 */
	public function buildTgroupFilter(array $values,$name = '') {
	    if(!$this->modx->addPackage('tagger',$this->modx->getOption('tagger.core_path',null,$this->modx->getOption('core_path').'components/tagger/').'model/')) {
	       return array(); 
	    } 
         
        $tags = array_keys($values);
		if (empty($tags) || (count($tags) < 2 && empty($this->config['showEmptyFilters']))) {
			return array();
		}

		$results = array();
		$q = $this->modx->newQuery('TaggerTag', array('tag:IN' => $tags));
		$q->select('tag,label');
		$tstart = microtime(true);
		if ($q->prepare() && $q->stmt->execute()) {
			$this->modx->queryTime += microtime(true) - $tstart;
			$this->modx->executedQueries++;
			$tags = array();
			while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
				$tags[$row['tag']] = $row['label'];
			}

			foreach ($values as $tag => $ids) {
				$title = !isset($tags[$tag])
					? $this->modx->lexicon('mse2_filter_boolean_no')
					: $tags[$tag];
				$results[$title] = array(
					'title' => $title,
					'value' => $tag,
					'type' => 'tagger',
					'resources' => $ids
				);
			}
		}
		ksort($results);

		return $results;
	}
  
}
1. Положить файл в директорию core/components/msearch2/custom/filters/
2. Прописать в системной настройке mse2_filters_handler_class: taggerCustomFilter

Исходная версия для истории и самоистязания:
<?php
class taggerCustomFilter extends mse2FiltersHandler {

	public function getTaggerValues(array $tags, array $ids) {

        $tagger = $this->modx->getService('tagger','Tagger',$this->modx->getOption('tagger.core_path',null,$this->modx->getOption('core_path').'components/tagger/').'model/tagger/');
        if (!($tagger instanceof Tagger)) return '';
        
		$filters = array();
		$q = $this->modx->newQuery('TaggerTagResource');
		
		$q->leftJoin('TaggerTag','TaggerTag','TaggerTagResource.tag = TaggerTag.id AND TaggerTag.group IN ("' . implode('","', $tags).'")');
		
		$q->select('TaggerTag.tag,TaggerTag.group,TaggerTagResource.resource');
		
		$tstart = microtime(true);
		if ($q->prepare() && $q->stmt->execute()) {
			$this->modx->queryTime += microtime(true) - $tstart;
			$this->modx->executedQueries++;
			
			
			while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
				foreach ($row as $k => $v) {
					$v = trim($v);
    				if($k == 'tag'){ $k = $row['group'];}
					
					if ($v == '' || $k == 'id' || $k == 'resource' || $k == 'group') {continue;}
					else if (isset($filters[$k][$v])) {
						$filters[$k][$v][] = $row['resource'];
					}
					else {
						$filters[$k][$v] = array($row['resource']);
					}
				}
			}
		}
		else {
			$this->modx->log(modX::LOG_LEVEL_ERROR, "[mSearch2] Error on get filter params.\nQuery: ".$q->toSql()."\nResponse: ".print_r($q->stmt->errorInfo(),1));
		}
		return $filters;
	}
	
	public function buildTgroupFilter(array $values, $name = '') {
		if (count($values) < 2 && empty($this->config['showEmptyFilters'])) {
			return array();
		}
		$results = array();
		foreach ($values as $value => $ids) {
			$results[$value] = array(
				'title' => $value
				,'value' => $value
				,'type' => 'default'
				,'resources' => $ids
			);
		}
		ksort($results);
		return $results;
	}
	
	public function filterTgroup(array $requested, array $values, array $ids) {
		$matched = array();
		$tmp = array_flip($ids);
		foreach ($requested as $value) {
			if (isset($values[$value])) {
				$resources = $values[$value];
				foreach ($resources as $id) {
					if (isset($tmp[$id])) {
						$matched[] = $id;
					}
				}
			}
		}
		return $matched;
	}

}
Виталий Серый
01 апреля 2017, 11:39
modx.pro
20
3 555
+8

Комментарии: 6

Alexander V
05 апреля 2017, 16:05
0
Разработчики Modx принципиально отказываются от тегов? Я понимаю, что это нарушает логику фреймворка. Заказчики одолели с вопросом тегов.
    Виталий Серый
    05 апреля 2017, 16:39
    0
    Как минимум из коробки есть тв. В остальном все зависит от задачи. Где-то вполне будет достаточно тех же тв, где-то нужно что-то поудобнее, а где-то теги вообще лишние.
    Т.ч. принципиального отказа не вижу, вижу вопрос, решение которого ложится на плечи разработчика проекта.
      Alexander V
      05 апреля 2017, 16:43
      0
      Так себе решение. Что касается TV.
    Евгений Шеронов
    23 мая 2018, 10:30
    +2
    Автор, я тут немного подправил код, чтобы из Tagger для отображения вытаскивать Label, а для значения Tag — так более правильно.
    gist.github.com/sheronov/a64692ced49a4f120ae87fd9795a0299

    Сохранил название методов и класса, если хотите — можете у себя в заметке поправить.

    Кстати, метод filterTgroup — немного лишний, так как если его нет, будет filterDefault отрабатывать.
    Sergey (Sentinel)
    29 апреля 2020, 18:51
    0
    важный момент
    в системную настройку
    extension_packages
    нужно добавить пакетик «tagger»
    {"tagger":{"path":"[[++core_path]]components/tagger/model/"}}
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      6