Довольно интересная задачка сегодня встала: есть каталог с радиаторами и вентилями (различаются по шаблону). В каталоге есть возможность вывести отдельно радиаторы, отдельно вентили, а можно сразу выводить все товары скопом. Так вот, возникла задача фильтровать радиаторы по отдельным параметрам, при этом иметь возможность выводить сразу и товары, и вентили. При этом у вентилей, понятное дело, даже нет тех параметров, по которым будут фильтроваться радиаторы. Как же сделать выборку так, чтобы учесть условия отдельно для радиаторов, отдельно для вентилей, и при этом иметь общие условия (опубликован, не скрыт в меню, не удален), да еще и не плодить SQL-запросы?
xPDO-запрос получился такой:
public function prepareQueryBeforeCount(xPDOQuery $c) { $c = parent::prepareQueryBeforeCount($c); $alias = $c->getAlias(); // Поиск по модели радиатора $radiators_where = array(); if($radiator_model_id = $this->getProperty('radiator_model_id')){ $categories = array(); $this->getCategories($radiator_model_id, $categories); if($categories){ $radiators_where['parent:IN'] = $categories; } unset($categories); } if($radiator_height = (int)$this->getProperty('radiator_height')){ $c->leftJoin('modTemplateVarResource', 'tv_radiator_height', "tv_radiator_height.tmplvarid = 4 AND tv_radiator_height.contentid = {$alias}.id"); $radiators_where[] = "CAST(tv_radiator_height.value as UNSIGNED) <= {$radiator_height}"; } if($radiators_where){ $c->where(array( array( "template" => 5, $radiators_where, ), "OR:template:!=" => 5, )); } return $c; }
Если у нас не переданы специальные условия для фильтра радиаторов, то у нас формируется обычный запрос:
SELECT modResource.* FROM `modx_site_content` AS `modResource` JOIN `modx_shopmodx_products` `Product` ON `modResource`.`id` = `Product`.`resource_id` WHERE ( `modResource`.`deleted` = 0 AND `modResource`.`hidemenu` = 0 AND `modResource`.`published` = 1 )
А если мы передадим в вызов «radiator_height» => 350, то получим такой:
SELECT modResource.* FROM `modx_site_content` AS `modResource` JOIN `modx_shopmodx_products` `Product` ON `modResource`.`id` = `Product`.`resource_id` LEFT JOIN `modx_site_tmplvar_contentvalues` `tv_radiator_height` ON tv_radiator_height.tmplvarid = 4 AND tv_radiator_height.contentid = modResource.id WHERE ( ( `modResource`.`deleted` = 0 AND `modResource`.`hidemenu` = 0 AND `modResource`.`published` = 1 ) AND ( ( `modResource`.`template` = 5 AND CAST(tv_radiator_height.value as UNSIGNED) <= 350 ) OR `modResource`.`template` != 5 ) )
Обратите внимание, что у нас есть один обособленный блок условий по статусам публикации, и есть второй блок, в котором условия прописаны буквально «где шаблон 5 И Все условия по радиаторам ИЛИ шаблон не 5».
Таким образом мы можем составлять довольно сложные запросы индивидуально для радиаторов, и отдельно для всех товаров в целом.
Вот более сложная выборка, если мы передаем такие параметры:
$params = array( "radiator_height" => 650, "radiator_depth" => 200, "radiator_model_id" => [ 1248, 19, ], "where" => [ "template" => 5, ], );
В данном случае мы запросили только радиаторы (добавив условие по шаблону), указали определенные модельные линейки радиаторов (параметр radiator_model_id) и максимальную высоту и глубину секций. Вот такой SQL-запрос получился:
SELECT modResource.* FROM `modx_site_content` AS `modResource` JOIN `modx_shopmodx_products` `Product` ON `modResource`.`id` = `Product`.`resource_id` LEFT JOIN `modx_site_tmplvar_contentvalues` `tv_radiator_height` ON tv_radiator_height.tmplvarid = 4 AND tv_radiator_height.contentid = modResource.id LEFT JOIN `modx_site_tmplvar_contentvalues` `tv_radiator_depth` ON tv_radiator_depth.tmplvarid = 7 AND tv_radiator_depth.contentid = modResource.id WHERE ( ( `modResource`.`deleted` = 0 AND `modResource`.`hidemenu` = 0 AND `modResource`.`published` = 1 ) AND ( ( `modResource`.`template` = 5 AND ( `modResource`.`parent` IN (1248,19,27,230,1249) AND CAST(tv_radiator_height.value as UNSIGNED) <= 650 AND CAST(tv_radiator_depth.value as UNSIGNED) <= 200 ) ) OR `modResource`.`template` != 5 ) )