В
предыдущей части мы рассмотрели добавление дополнительных способов сортировки в каталогах магазина, в этой части будет реализован сам принцип мильтисортировки.
Сразу хочу принести извинения за задержку статьи, к сожалению, в России начинают сбываться опасения правозащитников относительно цензуры в Интернете. Недавно
Ростелеком по решению регионального суда вместо выборочной блокировки одного из ресурсов заблокировал всю площадку
blogspot.com и ряд других ресурсов Google.
Но вернёмся к статье. Чтобы мультисортировка заработала на уровне модели, необходимо в файле
.../catalog/model/catalog/product.php в теле функции getProducts весь код между переменной
$sort_data = array( ... ) и условием
if (isset($data['start']) || isset($data['limit'])) { ... } заключить в тело оператора
else следующей конструкции:
if (isset($data['sort']) && $intersected = array_intersect((array)$data['sort'], $sort_data)) {
$sql .= " ORDER BY ";
foreach($intersected as $key => $value) {
$order = 'ASC';
if (isset($data['order'][$key])) {
$_order = strtoupper($data['order'][$key]);
if ($_order == 'ASC' || $_order == 'DESC') $order = $_order;
}
if ($value == 'pd.name' || $value == 'p.model') {
$sql .= "LCASE($value) $order,";
} else {
$sql .= $value . " $order,";
}
}
$sql = rtrim($sql, ",");
} else {
// Вырезанный код вставить сюда
}
В файле контроллера
.../catalog/controller/product/category.php перед строкой с условием
if (isset($this->request->get['page'])) { ... } добавьте следующий код:
if ($config_multisort = $this->config->get('config_multisort')) {
$sort = explode(';', $sort);
$order = explode(';', $order);
$this->data['text_multisort'] = $this->language->get('text_multisort');
$multisort = array();
foreach($sort as $key => $type) {
$direction = isset($order[$key]) ? $order[$key] : 'ASC';
$multisort[] = "$type-$direction";
}
$this->data['config_multisort'] = $config_multisort;
$this->data['multisort'] = $multisort;
}
В этом же файле после заполнения массива переменной
$this->data['sorts'] добавить следующий код:
if ($config_multisort) {
$default = $selected = $unselected = array();
foreach ($this->data['sorts'] as $sorts) {
$checked = false;
preg_match('/^(\w+\.)?(\w+)-(\w+)$/', $sorts['value'], $matches);
$sorts['group'] = $matches[2];
foreach($multisort as $key => $sorted) {
if ($sorted == $sorts['value']) {
$this->data['text_sorting'] = $sorts['text'];
$checked = true; break;
} elseif (strpos($sorted, $sorts['group']) !== false) {
$checked = true; break;
}
}
if ($sorts['group'] == 'sort_order') {
$default[] = $sorts;
} elseif($checked) {
$selected[$key][] = $sorts;
} else {
$unselected[] = $sorts;
}
}
$_selected = array();
for($n=0; $n < count($selected); $n++) {
$_selected = array_merge($_selected, $selected[$n]);
}
$this->data['sorts'] = array_merge($default, $_selected, $unselected);
}
Далее в шаблоне файла
.../catalog/view/theme/default/template/product/category.tpl весь код тега
<select onchange="location = this.value;"> включите в тело оператора
else следующей конструкции:
<?php if ($config_multisort) { ?>
<div class="select"><span><?php if(count($multisort) > 1) {
echo sprintf($text_multisort, count($multisort)); }
else { echo $text_sorting; } ?>
</span><div class="option">
<?php $counter = 0.5;
foreach ($sorts as $sorts) {
if (in_array($sorts['value'], $multisort)) { ?>
<label<?php if(intval($counter) % 2) { ?> class="group" <?php } ?>>
<input type="radio" name="<?php echo $sorts['group']; ?>"
value="<?php echo $sorts['value']; ?>" checked />
<span><?php echo $sorts['text']; ?></span></label>
<?php } else { ?>
<label<?php if(intval($counter) % 2) { ?> class="group" <?php } ?>>
<input type="radio" name="<?php echo $sorts['group']; ?>"
value="<?php echo $sorts['value']; ?>" />
<span><?php echo $sorts['text']; ?></span></label>
<?php } $counter += 0.5; } ?>
</div>
<div style="display: none;" id="multisort"><?php echo $text_multisort; ?></div>
</div>
<?php } else { ?>
// Вырезанный код вставить сюда
<?php } ?>
Теперь позаботимся о стиле и интерактивности. Для этого в файле стилей
.../catalog/view/theme/default/stylesheet/stylesheet.css добавим следующее:
.select {
display: inline-block;
border:solid 1px #CCCCCC;
}
.select > span {
cursor: default; display: block;
white-space: nowrap; padding: 2px 20px 2px 2px;
background: #F8F8F8 url('../image/button-dropdown.png') right center no-repeat;
line-height: 1.45em; height: 1.45em;
}
.select .option {
color: black; border:solid 1px #CCCCCC;
margin-left: -1px; position: absolute;
background-color:#F8F8F8;
z-index: 10; display: none;
}
.select .option label {
display: table-row;
}
.select .option label span{
display: table-cell; vertical-align: middle;
padding-right: 4px; padding-left: 2px;
}
.select .option label.group {
background-color:#E9E9E9;
}
.select .option label:hover {
color:#fff;
background-color:#000080;
}
Интерактивность мы реализуем через JavaScript в файле
.../catalog/view/javascript/common.js.
После
$(document).ready(function() { добавьте следующий код:
$(document).click(function(event) { if ($(event.target).next().attr('class') !='option' && !$(event.target).parents('.option').length) { $('.option').hide(); } });
jQuery.fn.option = function() {
var url = 'http://' + location.host + location.pathname; var submitted = false;
$(this).parent().width($(this).width()); $(this).parent().click(function(event) {
if ($(this).find('.option').is(":visible")) {
var tagName = event.target.tagName.toLowerCase();
var parentTag = event.target.parentNode.tagName.toLowerCase();
if( parentTag == 'label') { if( tagName == 'span' ) submitted = true;
if( tagName == 'input' ) {
var radioboxes = $(this).find('input:radio'); var group = $(event.target).attr('name');
if(group == 'sort_order') { radioboxes.not('[name="sort_order"]').removeAttr('checked');
} else { radioboxes.filter('[name="sort_order"]').removeAttr('checked');}
var filters = new Array(); var sorts = new Array(); var orders = new Array();
radioboxes.filter(':checked').each(function() {
filters.push($(this).next('span').text()); var sort_order = $(this).val().split('-');
sorts.push(sort_order[0]); orders.push(sort_order[1]);
});
if (filters.length > 1) {
var multiple = $(this).children('#multisort').text().replace('%s', filters.length);
$(this).children('span').text(multiple);
} else $(this).children('span').text($(event.target).next('span').text());
if(submitted) { var search = location.search.replace(/[?&](sort|order)=((\w+\.?\w+);?)+/ig, '');
$(this).unbind(); $(this).find('.option').hide();
if(sorts.length) search += '&sort=' + sorts.join(';');
if(orders.length) search += '&order=' + orders.join(';');
location.href = url + search.replace(/^&/,'?');
}
}} else $(this).find('.option').hide(); } else { $(this).find('.option').show().css('display', 'table'); }});};
$('.option').option();
Стиль выше необходим для реализации элемента управления типа
select, а код на языке JavaScript реализует саму работу этого элемента управления. В результате мы получим элемент управления как на рисунке ниже.
Чтобы можно было включать/отключать данный вариант сортировки, в панель администрирования добавлена опция
config_multisort.
Не забудьте также определить текстовое значение переменной
text_multisort для своего языка. В данном примере в файле
.../catalog/language/russian/russian.php оно следующее: "Выбрано %s условия".