mFilter2. принцип OR поменять на AND Работа выполнена

Дней на работу: 1 Стоимость работы: 3000 Дополнение: mFilter2

Добрый день.

В фильтрах минишопа фильтр тегов работает по приципу OR, необходимо поменять на AND.

То бишь показывать товары в которых есть и первый тег И (а не ИЛИ) второй.

Решившему задачу скромное вознаграждение в 3000р
15 июля 2015, 21:22    Антон ХайЭксель   G+  
5    1054

Комментарии (11)

  1. Ivan Shvindin 15 июля 2015, 23:52 # -1
    Давайте доступы ivan@shvindin.ru
    1. Володя 15 июля 2015, 23:54 # 0
      s2391.h4.modhost.pro/katalog/
      s2391
      U2lXd8Eh9wJH
      1. Антон ХайЭксель 16 июля 2015, 00:25 # 0
        В принципе можно на тестовом — да ;)

        вообще подобная необходимость нужна на паре сайтов. Хотелось бы универсального решения. в идеале лаконичный файл core/components/msearch2/custom/filters/custom.class.php
          1. Антон ХайЭксель 16 июля 2015, 01:11 # 0
            получился опять же OR
            1. Антон ХайЭксель 16 июля 2015, 01:17 # 0
              То бишь дефолтный фильтр выбирает товары в которых есть тег1 или тег2 или тег3
              А нужен который будет выбирать товары в которых есть тег1 и тег2 и тег3

              надеюсь так понятнее объяснил
              1. Володя 16 июля 2015, 01:32 # 0
                ну тогда так s2391.h4.modhost.pro/katalog
                1. Антон ХайЭксель 16 июля 2015, 02:04 # 0
                  Ты маг и волшебник. скинь реквизиты для перевода на почту i@orenbu.ru — завтра переведем бонус ;)
      2. Антон ХайЭксель 16 июля 2015, 02:10 # +1
        Просуммирую метод Володи, думаю может понадобится кому-то еще

        1. естественно меняем класс обработчик фильтров. Идем в настройки системы и в настройках mSearch2 меняем параметр mse2_filters_handler_class на CustomFilter

        2. теперь нам нужно создать сам класс. для этого создаем файл core/components/msearch2/custom/filters/custom.class.php с содержимым

        <?php
        class CustomFilter extends mse2FiltersHandler {
        
            public function getMsOptionMyValues(array $keys, array $ids) {
        		$filters = array();
        		$q = $this->modx->newQuery('msProductOption');
        		$q->where(array('product_id:IN' => $ids, 'key:IN' => $keys));
        		$q->select('`product_id`,`key`,`value`');
        		$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)) {
        				$value = trim($row['value']);
        				if ($value == '') {continue;}
        				$key = $row['key'];
        				// Get ready for the special options in "key==value" format
        				if (strpos($value, '==')) {
        					list($key, $value) = explode('==', $value);
        					$key = preg_replace('/\s+/', '_', $key);
        				}
        				// --
        				if (isset($filters[$key][$value])) {
        					$filters[$key][$value][] = $row['product_id'];
        				}
        				else {
        					$filters[$key][$value] = array($row['product_id']);
        				}
        			}
        		}
        		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 buildDefaultMyFilter(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 filterDefaultMy(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;
        					}
        				}
        			}
        		}
        		
        	    $match = $matched;
        		$matched = array();
        		$count = count($requested);
        		$count_values = array_count_values($match);
        		foreach ($count_values as $id => $value) {
        		    if ($value >= $count) {
        		        $matched[] = $id;
        		    }
        		    else {
        		        $matched[] = 0;
        		    }
        		}
        		return $matched;
        	}
        	
        }
        осталось добавить в чанк вызова мфильтра строчку

        &filters=`
        		msoption|tags:DefaultMy'


        вуаля — фильтр работает как нужно ;)
        1. maslitto 17 ноября 2015, 16:27 # 0
          Разве не должно быть в этом месте название метода getMsOptionValues?
           public function getMsOptionMyValues(array $keys, array $ids)
          
          1. Николай 06 июня 2016, 21:38 # 0
            Попробовал реализовать принцип AND для фильтрации по ТВ. Выборка как я понял стандартная подойдёт, поэтому getTvValues не трогаем. Заменил filterDefault следующим образом:

            <?php
            class CustomFilter extends mse2FiltersHandler {
                
            	public function filterMy(array $requested, array $values, array $ids) {
            	    
                    $matched = array();
                    
                    foreach($ids as $id) {
                        $flag = 1;
                        foreach($requested as $value) {
                            if( !in_array($id, $values[$value]) ) {
                                $flag = 0;
                                break;
                            }
                        }
                        if($flag) $matched[] = $id;
                    }
            
            		
            		return $matched;
            	}
            }
            
            
            т.е. в $matched у меня только id которые попадают под все выбранные параметры:

            Всё бы ничего, но при использовании параметра &suggestions=`1` при выборе только одного чекбокса, остальные становятся недоступными, даже если они актуальны:



            Опция Гараж попадает в выбранный фильтр, но она почему-то неактивна. Если отключить &suggestions=`0`, то можно выбрать и гараж, но тогда не будет работать предсказание по фильтрам. Ломаю голову, не доходит логика работы фильтра… Надо смотреть в сторону build-методовв?

            Вы должны авторизоваться, чтобы оставлять комментарии.