Создание двухсторонней сортировки order_by для xslt шаблонов

сортирока, не такое уж и сложное дело custom order_by

Наверное, все, кто работал над созданием интернет-магазинов, встречались с задачей вывода ссылок для сортировки товаров по цене, по названию и т.п. Для этих целей в umi есть макрос system order_by() , который выводит ссылку для сортировки страницы каталога (или других списков, поддерживающих сортировку и фильтрацию) по указанному свойству. Но для удобной и полноценной задачи его сил не хватало.

Из недостающего функционала можно отметить 2 принципиальных момента:
1.
Отсутствие сортировки в обе стороны (а-я, я-а). И хотя технически данная возможность в самом механизме заложена, но ссылки для выполнения данной сортировки приходилось генерить своими силами.
2. Потребность в шаблоне указывать тип данных объекта каталога (object type id). То есть для вывода ссылки на сортировку по цене в каталоге, приходилось прописывать в шаблоне system/order_by/price/72, а в виду того, что в разных версиях umi тип данных "объект каталога" имеет разный object type id, приходилось всегда держать это в голове. Что такое object type id и где его найти в системе umi смотрите в статье "В чем разница hierarchyTypeId и objectTypeId"

Потом на wiki.umisoft появилась была удалена статья "Обновленный макрос system order by (двойная сортировка по одной ссылке)" , в которой описывалось хорошее решение первого вопроса с сортировкой в обе стороны, но и тут, при попытке использовать данный макрос для xslt шаблонов, возникли некоторые сложности.

Немного усложняло жизнь отсутствие примера шаблона для вывода результатов данного макроса. Почему-то никак не удавалось посмотреть тот xml, который отдавал данный макрос, даже через xsl:copy-of... если кто знает, в чем заключается причина такой аномалии, отпишите, буду очень рад)

И сильно усложняло жизнь то, что в данном макросе для xslt шаблонизатора не было возможности отследить какое направление сортировки используется в данный момент, то есть в tpl была возможность задать разные шаблоны для ссылок в разные направления, а в xslt нет.

В итоге, пришло время написать свой вариант макроса для сортировка списка объектов по какому-либо свойству.

Макрос умеет выводить ссылки в обе стороны сортировки. При отсутствии сортировки ссылка производит сортировку А-Я, далее макрос выводит ссылку на противоположную сортировку относительно текущего направления сортировки.
Макросу можно явно указать object type id типа данных объектов для сортировки. Если он не указан явно, система проверяет указан ли id родительского раздела, внутри которого находятся объекты для сортировки (если нет, то макрос считает родительским разделом текущую страницу), определяет основной тип данных в данном разделе и использует его.

Инструкция по применению

  1. В файл /classes/modules/custom.php закидываем пак функций
    public function order_by($fieldName, $parent_id=NULL, $typeId=NULL, $template = "default") {
    	if(!$fieldName) return;
    	$from = Array('%5B', '%5D');
    	$to = Array('[', ']');
    	$result = self::generateOrderBy($fieldName, $typeId, $template, $parent_id);
    	$result = str_replace($from, $to, $result);
    	return $result;
    }
    
    public static function generateOrderBy($fieldName, $type_id, $template = "default", $parent_id) {
    
    	if(!$template) $template = "default";
    	list($template_block, $template_block_a1, $template_block_a2) = def_module::loadTemplates("tpls/numpages/{$template}.tpl", "order_by", "order_by_a", "order_by_b");
    
    	if(!$parent_id) $parent_id = cmsController::getInstance()->getCurrentElementId();
    	$i_need_deep = 1;
    	if(!$type_id) $type_id = umiHierarchy::getInstance()->getDominantTypeId($parent_id, $i_need_deep);
    
    	if(!($type = umiObjectTypesCollection::getInstance()->getType($type_id))) return "";
    
    	$block_arr = Array();
    	if(($field_id = $type->getFieldId($fieldName)) || ($fieldName == "name")) {
    		$params = $_GET;
    
    		unset($params['path']);
    		$order_filter = getArrayKey($params, 'order_filter');
    
    		$tpl = 0;     
    		if(is_array($order_filter)) {
    			if (array_key_exists($fieldName, $order_filter)){
    				if ($order_filter[$fieldName] == 1){
    					$tpl = $template_block_a1;
    					unset($params['order_filter']);
    					$params['order_filter'][$fieldName] = 0;
    					$order_direction = 1;
    				} else {
    					$tpl = $template_block_a2;
    					unset($params['order_filter']);
    					$params['order_filter'][$fieldName] = 1;
    					$order_direction = 0;
    				}
    			} else {
    				unset($params['order_filter']);
    				$params['order_filter'][$fieldName] = 1;
    				$tpl = $template_block;
    				$order_direction = 'non';
    			}
    		} else {
    		unset($params['order_filter']);
    		$params['order_filter'][$fieldName] = 1;
    		$tpl = $template_block;
    		$order_direction = 'non';
    		}
    
    		$params = self::protectParams($params);
    		$q = (sizeof($params)) ? "&" . http_build_query($params, '', '&') : "";
    		//$q = (sizeof($params)) ? "&" . str_replace("&", "&", http_build_query($params)) : "";
    		$q = urldecode($q);
    		$q = str_replace("%", "%", $q);
    
    		$block_arr['link'] = "?" . $q;
    		$block_arr['attribute:direction'] = $order_direction; //главное тут
    
    		if($fieldName == "name") {
    			$block_arr['title'] = getLabel('field-name');
    		} else {
    			$block_arr['title'] = umiFieldsCollection::getInstance()->getField($field_id)->getTitle();
    		}   
    		return def_module::parseTemplate($tpl, $block_arr);
    	}
    	return "";
    }
    
    protected static function protectParams($params) {
    	foreach($params as $i => $v) {
    		if(is_array($v)) {
    			$params[$i] = self::protectParams($v);
    		} else {
    			$v = htmlspecialchars($v);
    			$params[$i] = str_replace("%", "%", $v);
    		}
    	}
    	return $params;
    }
  2. Добавляем шаблоны для вывода ссылки
    
    <xsl:template match="udata[@module='custom' and @method = 'order_by']">
    	<a href="{link}" class="direction{@direction}">&#8595;&#8593;<xsl:value-of select="title" /></a>
    </xsl:template>
    
    
    <xsl:template match="udata[@module='custom' and @method = 'order_by' and @direction='0']">
    	<a href="{link}" class="direction{@direction}">&#8595;<xsl:value-of select="title" /></a>
    </xsl:template>
    
    
    <xsl:template match="udata[@module='custom' and @method = 'order_by' and @direction='1']">
    	<a href="{link}" class="direction{@direction}">&#8593;<xsl:value-of select="title" /></a>
    </xsl:template>
    
  3. Параметры функции custom order_by(Имя_поля,[id_родительского_раздела, object_type_id ]). Примеры вызова:
    Вывод ссылки на сортировку по полю цена, тип данных определяется автоматически по страницам дочерним к текущей странице
    <xsl:apply-templates select="document('udata://custom/order_by/price')" />
    
    Вывод ссылки на сортировку по полю цена, тип данных определяется автоматически по страницам дочерним к странице с id = 14
    <xsl:apply-templates select="document('udata://custom/order_by/price/14')" />
    
    Вывод ссылки на сортировку по полю цена, тип данных задан явно и равен 72 (Объект каталога)
    <xsl:apply-templates select="document('udata://custom/order_by/price//72')" />


comments powered by HyperComments