Довольно интересная задачка сегодня встала: есть каталог с радиаторами и вентилями (различаются по шаблону). В каталоге есть возможность вывести отдельно радиаторы, отдельно вентили, а можно сразу выводить все товары скопом. Так вот, возникла задача фильтровать радиаторы по отдельным параметрам, при этом иметь возможность выводить сразу и товары, и вентили. При этом у вентилей, понятное дело, даже нет тех параметров, по которым будут фильтроваться радиаторы. Как же сделать выборку так, чтобы учесть условия отдельно для радиаторов, отдельно для вентилей, и при этом иметь общие условия (опубликован, не скрыт в меню, не удален), да еще и не плодить 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
)
)