[EVO] Вопрос по фильтру, дополнительный тв

добрый день, встала такая задача дописать дополнительный тв для фильтрации, этот код ищет по одному тв
$filter = '';
if(isset($_GET['id']) AND $_GET['id'] != 'all')
{
	$filter= 'emkost,'.$_GET['id'].',7';
	
}

//echo $filter; die;

$txt = $modx->runSnippet('Ditto', array(
	    'startID' =>$modx->documentIdentifier,
        'tpl' => 'akk_price',
	    'orderBy'=> 'menuindex ASC',
        'paginate' => '1',
        'id'=> 'akk',
		'hideFolders' => '1',
		'display' => '20',
		'depth' => '5',
	
        
       
	'filter' => $filter,
        
	
));
echo $txt;

как прописать дополнительный тв?
пробовал сделать

$filter= 'emkost,'.$_GET['id'].',7'.'|'.'europa,'.$_GET['id'].',7';

после этого не ищет вообще.
можете подсказать как правильней дописать

22 комментария

avatar
$filter= 'tvemkost,'.$_GET['id'].',7'.'|'.'tveuropa,'.$_GET['id'].',7';


И неплохо было бы перед вставкой $_GET['id'] как-то экранировать или защитить. Так и поломать все можно через такой запрос :)

Вместо 7 лучше использовать 9 (не чувствителен к регистру) или вообще 1 (!=), если вам там нужно отсеивать просто по значению.
avatar
если кому потребуется, вот вывод дополнительный ТВ,

<code><?php
$filter = '';
if(isset($_GET['brand_shin']) AND $_GET['brand_shin'] != 'all')
{
 $filter= 'brand_shin,'.$_GET['brand_shin'].',7';
 
}
if(isset($_GET['visota']) AND $_GET['visota'] != 'all')
{
 $filter= '|visota,'.$_GET['visota'].',7';
 
}
if(isset($_GET['radius']) AND $_GET['radius'] != 'all')
{
 $filter= '|radius,'.$_GET['radius'].',7';
 
}
if(isset($_GET['shirina']) AND $_GET['shirina'] != 'all')
{
 $filter= '|shirina,'.$_GET['shirina'].',7';
 
}
if(isset($_GET['vid']) AND $_GET['vid'] != 'all')
{
 $filter= '|vid,'.$_GET['vid'].',7';
 
}


$txt = $modx->runSnippet('Ditto', array(
     	'startID' => $id,
        'tpl' => 'catalog_shin',
        'orderBy'=> 'menuindex ASC',
        'paginate' => '1',
        'id'=> 'shiny',
  		'hideFolders' => '1',
  		'display' => '20',
  		'depth' => '4',
 		'filter' => $filter,
        
 
));
echo $txt;
?></code>

это шаблон,
<code><li [[getClassRadius? &id=`[+id+]`]]><a href="[~[*id*]~]/?radius=[+id+]">[+title+]</a></li>

</code>
передается значение поиска

getClassRadius спипет для активного меню, где radius, передаваемое значение

<?php
$id_n=$_GET['radius'];
if($id==$id_n)
{
	echo 'class="active"';
}

?>
Комментарий отредактирован 2013-10-09 18:58:10 пользователем atrox1g
avatar
Вы наверно хотели сказать «если кому надо, чтоб сломали его сайт, а фильтр работал криво и только по одному из переданных параметров — берите это» ))))) Иначе сложно расценить сей широкий жест :)
avatar
Можете показать как правильно защитить его, чтобы не сломали его, как правильно экранировать и т.д., на будущее чтоб знать
avatar
Ну хотя бы $_GET пропустить через какой-нибудь htmlentities или через #$modx->db->escape

Делаете что-то подобное:

//список фильтров, которые учитываем
$filterArray=array('brand_shin','visota','radius','shirina','vid');
//список значений, которые не учитываем
$resetArray=array('all');
//тут будет строка фильтра
$filter='';

//получаем $_GET, очищаем и формируем фильтр с учетом разрешенных фильтров и запрещенных значений
$p=$_GET;
foreach ($p as $k=>$v){
    $k=htmlentities($k,ENT_QUOTES,$modx->config['modx_charset']);
    $v=htmlentities($v,ENT_QUOTES,$modx->config['modx_charset']);

    if(in_array($k,$filterArray)&&!in_array($v,$resetArray)){
        $filter.='tv'.$k.','.$v.',7|';
    }
}
$params=array(
     	'startID' => (int)$id,
        'tpl' => 'catalog_shin',
        'orderBy'=> 'menuindex ASC',
        'paginate' => '1',
        'id'=> 'shiny',
  	'hideFolders' => '1',
  	'display' => '20',
  	'depth' => '4'
);

//если фильтр не пустой, присоединяем его к параметрам
if($filter!=''){$params['filter']=$filter;}

//вызываем Ditto с параметрами
$txt = $modx->runSnippet('Ditto', $params);

//возвращаем результат выполнения Ditto
return $txt;


Могут быть нюансы из-за невнимательности и того, что не тестировалось — но принцип, я так понимаю — понятен.
avatar
Спасибо за разъяснение) будем исправлять
avatar
Да не за что. Если в фильтрах не предполагается кавычек или тегов — то можно заменить htmlentities на
$k=$modx->db->escape($modx->stripTags($k));
$v=$modx->db->escape($modx->stripTags($v));


От всего, конечно, не защитишься — но по крайней мере это не передача голых $_GET-ов сразу в базу))))
Комментарий отредактирован 2013-10-09 19:53:22 пользователем webber
avatar
а на каком этапе вы фильтруете гет запросы?
$filterArray=array('brand_shin','visota','radius','shirina','vid');
//список значений, которые не учитываем
$resetArray=array('all');

я просмотрел нету нигде условий и проверки это так чисто для вида?
avatar
Неожиданный вопрос, через 4 года :)) Да и не совсем понятный :))
Наверно вы про этот незаметный кусок:
//получаем $_GET, очищаем и формируем фильтр с учетом разрешенных фильтров и запрещенных значений
$p = $_GET;
foreach ($p as $k => $v){
    $k = htmlentities($k, ENT_QUOTES, $modx->config['modx_charset']);
    $v = htmlentities($v, ENT_QUOTES, $modx->config['modx_charset']);

    if(in_array($k, $filterArray) && !in_array($v, $resetArray)){
        $filter .= 'tv' . $k . ',' . $v . ',7|';
    }
}


данный кусок как-раз и прогоняет весь $_GET с предварительным htmlentities (можно защититься и получше, за 4 года много что поменялось), а потом проверяет на наличие в массиве разрешенных $filterArray и отсутствие в массиве запрещенных $resetArray и если все ок — добавляет к фильтрам $filter. Ну или я не понял в чем вопрос.
avatar
avatar
Еще такой вопрос, сколько товаров максимально может обработать фильтр дитто?
avatar
Тут надо вопрос ставить шире — сколько может обрабатывать MODx в связке с Ditto — а тут уж все зависит от оперативки на хостинге :) Если количество большое — лучше использовать DocLister и переработать хотя бы немного вывод одного товара — т.к. при большом количестве товаров и большом количестве ТВ у них начнет тормозить MySQL уже при 10 000 точно за счет JOIN-ов таблицы со значениями ТВ.

Принцип же действия самих фильтров Ditto — это тупое отсеивание неподходящих результатов. Т.е. Дитто сначала соберет все — а уж потом пройдется по массиву и выкинет то, что не подходит под фильтр. Отсюда и его прожорливость — берется вся выборка (нагрузка на базу) плюс туда-сюда гоняется неоднократно весь массив результатов (а массивы кушают много памяти).
Комментарий отредактирован 2013-10-09 19:52:06 пользователем webber
avatar
вы в сниппете фильтруете, так кто мешает:
— поетапно пройтись по базе ТВ отсекая ТВшки, тоесть ищем если !empty($_GET['visota']), в $ids результат contentid и так по всем ТВ. А в Дитто передать documents = implode(',',$ids).
Комментарий отредактирован 2013-10-10 13:17:12 пользователем bumkaka
avatar
может и отклонение есть из темы, новую тему не хочу создавать. Как бы реализовать все фильтр от и до?

Из то что есть уже:
Форма
<form action="/test/" method="get">
		<label>от</label>			
			<input type="text" name="price_s" value="">
		<label>до</label>
			<input type="text" name="price_po" value="">
		<select name="categoryZU">
			<option value="">Категория</option>
			<option value="1">(ИЖС) поселений</option>
			<option value="2">(ДНП, СНТ) сельхозназначения</option>
			<option value="3">коммерческая</option>
		</select>
		<input type="submit" value="Найти " />
	</form>

Сниппет:
<?php
$output = '';
$filter = array();
$sl = 0;
if($_GET['categoryZU'] == 1) $sl = '(ИЖС) поселений';
if($_GET['categoryZU'] == 2) $sl = '(ДНП, СНТ) сельхозназначения';
if($_GET['categoryZU'] == 3) $sl = 'коммерческая';
if(isset($_GET['price']) && !is_array($_GET['price']) && $_GET['price'] != 0) $filter[] =  '(SELECT contentid FROM mdxd_catalog_tmplvar_contentvalues WHERE value BETWEEN "'.$_GET['price_s'].'" AND "'.$_GET['price_po'].'")';

// или так if(isset($_GET['price']) && !is_array($_GET['price']) && $_GET['price'] != 0) $filter[] =  'price,'.$_GET['price_s'].',5|price,'.$_GET['price_po'].',6';
if(isset($_GET['categoryZU']) && !is_array($_GET['categoryZU']) && $_GET['categoryZU'] != 0) $filter[] = '(SELECT contentid FROM mdxd_catalog_tmplvar_contentvalues WHERE value like "'.$sl.'")';
 
$params['parents'] = '12';
$params['tpl'] = 'prodlistTpl';
$params['descTpl'] = 'prodlistdescTpl';
$params['sqlFilter'] = '1';
$params['sortDir'] = 'desc';
$params['display'] = '10';
$params['noResult'] = '<p>Объектов, соответствующих условиям поиска нет. Попробуйте задать более мягкие условия.</p>';
$filt = implode(' UNION ALL ',$filter);
$n = count($filter);
if ($n==0) $params['where'] = '';
if ($n==1) $params['where'] = "sc.id IN (SELECT contentid FROM ($filt) AS vremennaia GROUP BY contentid)";
if ($n>1) $params['where'] = "sc.id IN (SELECT contentid FROM ($filt) AS vremennaia GROUP BY contentid HAVING count(contentid)>($n-1))";
$output = $modx->runSnippet('catalogView',$params);
return $output;
?>

Условие по «Категория» срабатывает, а по цене нет. Как будто этого запроса и нет вовсе.
avatar
Сделано через доклистер, но работает цена от и до через ползунок


$params = array(
	    'snippetToCache'=>'DocLister',
		'idType'=>'parents',
	    'cacheId'=>'catalog',
        'display'=> $display,
	    'depth'=>'4',
        'tpl'=>'catalog',
	    'tvList'=>'price,image',
        'id'=>'catalog',
        'controller'=>'site_content',
        'addWhereList'=>'isfolder=0 AND template=6',
        'paginate'=>'pages',
	    'filters' => 'tv:price:gt:0',
		 'orderBy'=> $getOrder.' '.$getDir,
 		'tvSortType'=>'UNSIGNED',
		
        'parents'=> $modx->documentObject['id'],

	
	    
        'TplNextP'=>'@CODE:<li class="next"><a href="[+link+]">>></a></li>',
        'TplPrevP'=>'@CODE:<li class="previous"><a href="[+link+]"><<</a></li>',
        'TplPage'=>'@CODE:<li><a href="[+link+]">[+num+]</a></li>',
        'TplCurrentPage'=>'@CODE:<li class="disabled"><a href="[+link+]">[+num+]</a></li>',
        'TplWrapPaginate'=>'@CODE:<ul class="pager">[+wrap+]</ul>',
	'noneTPL'=>'@CODE: <p style="width: 985px;font-weight:bold">К сожалению, по вашему запросу ничего не обнаружено. Попробуйте поискать еще раз.</p>'
);

echo '<ul class="result_filt">';


$f = array('tv:price:gt:0');
if(isset($_GET['price-min']) && (int)$_GET['price-min']>0){
        $f[] = 'tv:price:egt:'.(int)$_GET['price-min'];
}
if(isset($_GET['price-max']) && (int)$_GET['price-max']>0){
        $f[] = 'tv:price:elt:'.(int)$_GET['price-max'];
}
if(!empty($_GET['pol']) && is_scalar($_GET['pol'])){
  $f[] = 'tv:pol:is:'.$_GET['pol'];
   echo '<li>Для ребенка? - '.$_GET['pol'].'</li>';
}
if(!empty($_GET['proizvod']) && is_scalar($_GET['proizvod'])){
  $f[] = 'tv:proizvod:is:'.$_GET['proizvod'];
    echo '<li>Производитель - '.$_GET['proizvod'].'</li>';
}
if(!empty($_GET['vozrast']) && is_scalar($_GET['vozrast'])){
  $f[] = 'tv:vozrast:is:'.$_GET['vozrast'];
  echo '<li>Производитель - '.$_GET['vozrast'].'</li>';
}


echo '</ul>';


$params['filters'] = 'AND('.implode("; ", $f).')';
return $modx->runSnippet("CacheAccelerator", $params);
avatar
Спасибо попробую.
avatar
попробовал, опять таки фильтрует по категории categoryZU, но цену нет. У меня нюансы есть, товары хран-ся в каталоге shopkeeper, вроде прописал табличку в контроллере. Что посоветуете?
avatar
&controller=`site_content ` это не значит что вы работаете с таблицей site_content. Это значит, что вы работаете контроллером таким. В вашем случае скорее всего нужен контроллер onetable. Ну и дальше уже формировать значение параметра addWhereList…

P.S. Стукните в скайп и я постараюсь помочь с реализацией, чтобы включить этот контроллер в стандартную поставку DocLister'a.
avatar
я понимаю это, использую &controller=`onetable` и внутри таблицу на нужную поменял. Стучу в скайп
avatar
Если хранить товары в отдельной таблице Шопкипера (modx_catalog), то и ТВ в этом случае хранятся в отдельной таблице (modx_catalog_tmplvar_contentvalues). ПОэтому onetable тут явно не подойдет (он работает с одной таблицей). Надо переделывать контроллер site_content и все что касается выборки и фильтрации ТВ (в частности core/filter/tv.filter.php и core/extender/tv.extender.inc тоже нужно копировать и переназначать там имена таблиц для ТВ).
avatar
Добавил новый контроллер shopkeeper и модифицировал фильтры, экстендеры ТВ параметров, чтобы не приходилось заниматься копи-пастом. Особо не тестировал, но вроде работает. Единственное отличие от site_content контроллера — алиас таблицы c заменен на s.
avatar
Вопрос встал по checkbox,
как код
if(!empty($_GET['vozrast']) && is_scalar($_GET['vozrast'])){
  $f[] = 'tv:vozrast:is:'.$_GET['vozrast'];
  echo '<li>Производитель - '.$_GET['vozrast'].'</li>';

переделать под checkbox?
Фильтр не хочет работать. Выводит каждый checkbox как отдельный параметр (например &test=1&test=2, а правильно будет &test=1,2 )
Комментарий отредактирован 2014-04-28 09:56:20 пользователем xrustit
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.