Пример создания сложной фильтрации по каталогу (кастомный макрос)

Материал из Umicms
Версия от 12:33, 5 июня 2013; Mad grant (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к:навигация, поиск

Бывает стандартных средств фильтрации не хватает для реализации интернет проекта, на помощь таким вещам приходят собственные разработки, написанные на основе существующих макросов. Для одного из проектов был создан дополнительный макрос и размещен в classes/modules/custom.php, public function getObjectsListNew, он был создан на основе getObjectsList в classes/modules/catalog/class.php. Файл custom.php при обновлении системы не затирается. Также в tpls/catalog/default.tpl в первом блоке был поставлен вызов: %custom getObjectsListNew(…)% вместо: %catalog getObjectsList(…)%

public function getObjectsListNew: Если какие либо параметры в GET запрос не переданы то запускается стандартный метод, в ином случае работает новый макрос. Изменен в новом макросе был в основном только процесс выборки нужных объектов, начало и конец остались прежними. Задачей было сделать фильтрацию в которой некоторые группы полей должны были быть объединены логическим И, а между собой сами группы объединены логическим ИЛИ. В фильтрации участвовал один выпадающий список и некоторые количество группы с чекбоксами. Суть кода: составление SQL запроса к базе данных, благодаря которому будут найдены нужные элементы и переданы дальше системе для отображения в нужной форме.

Доп. информация: http://api.umi-cms.ru

public function getObjectsListNew($template = "default", $path = false, $limit = false, $ignore_paging = false, $i_need_deep = 0) 
{ 
    if(!array_key_exists('fields_filter',$_GET) || !array_sum($_GET['fields_filter'])){
    $catalog_inst = cmsController::getInstance()->getModule("catalog");
    return $catalog_inst->getObjectsList($template, $path, $limit, $ignore_paging, $i_need_deep);
    }
    if(def_module::breakMe()) return;
		if(!$template) $template = "default";
		if (!$i_need_deep) $i_need_deep = intval(getRequest('param4'));
		if (!$i_need_deep) $i_need_deep = 0;
		$i_need_deep = intval($i_need_deep);
		if ($i_need_deep === -1) $i_need_deep = 100;
		
		$hierarchy = umiHierarchy::getInstance();
		list($template_block, $template_block_empty, $template_block_search_empty, $template_line) = def_module::loadTemplates("tpls/catalog/{$template}.tpl", "objects_block", "objects_block_empty", "objects_block_search_empty", "objects_block_line");
		$hierarchy_type_id = umiHierarchyTypesCollection::getInstance()->getTypeByName("catalog", "object")->getId();
		$category_id = def_module::analyzeRequiredPath($path);
		// KEYWORD_GRAB_ALL определена в config.php = mode=all
		if($category_id === false && $path != KEYWORD_GRAB_ALL) {
			throw new publicException("Element not found: \"{$path}\"");
		}
    $hierarchy_type_id = umiHierarchyTypesCollection::getInstance()->getTypeByName("catalog", "object")->getId();
    $hierarchy_type = umiHierarchyTypesCollection::getInstance()->getType($hierarchy_type_id);
		$type_id = umiObjectTypesCollection::getInstance()->getBaseType($hierarchy_type->getName(), $hierarchy_type->getExt());
    if(!$type_id) {
			$type_id = umiObjectTypesCollection::getInstance()->getBaseType($hierarchy_type->getName(), $hierarchy_type->getExt());
		}
    //Берем $per_page (кол-во элементов на странице) из атрибута макроса либо из реестра каталога (настройка модуля каталог), 
    $per_page_r = regedit::getInstance()->getVal("//modules/catalog/per_page");
		$per_page = ($limit) ? $limit : $per_page_r;
		// $curr_page - текущая страница, параметр нужен для выборки данных для нужной страницы  
		$curr_page = getRequest('p');
		if($ignore_paging) $curr_page = 0;
		// Начало измененной части кода:
		// Какой тип объектов в разделе каталога, в модуле Шаблоны данных (775 или 780) 
    $idType = umiHierarchy::getInstance()->getDominantTypeId($category_id);
    // Получаем экземпляр для выбранного типа, чтобы потом использовать некоторые методы
    $objType = umiObjectTypesCollection::getInstance()->getType($idType);
    
    $arr_get = $_GET['fields_filter'];
    $c_index = 0;
    $str1 = "";
    // Выпадающий список с идентификатором поля: nazva, строим для него часть sql запроса 
    $str_ind_1 = "nazva";
    if(array_key_exists($str_ind_1,$arr_get) && $arr_get[$str_ind_1]){
     $c_index++;
     $idField = $objType->getFieldId($str_ind_1);
     $str1 = "AND (c{$c_index}.obj_id = o.id AND c{$c_index}.field_id = '{$idField}' AND (c{$c_index}.rel_val IN ('{$arr_get[$str_ind_1]}')))"; 
    }
    // 775 - один из id типов данных в модуле Шаблоны данных
    // В массивах $total_arr[N=2] до N, будут идентификаторы полей каждой группы, группы перечислены в массиве $arr_group
    // В $group помещаются объекты все полей, мы потом в foreach-е берем имена каждого поля. 
    $total_arr = Array();
    if($idType == 775){
       $arr_group = Array('komnat','klass','plowad','cena');
       for($x = 2, $i = 0; $x < count($arr_group)+2; $x++, $i++){
        $group = umiObjectTypesCollection::getInstance()->getType($idType)->getFieldsGroupByName($arr_group[$i])->getFields();
        foreach($group as $fieldsName) {
         $total_arr[$x][] = $fieldsName->getName();
        }
      }
    }
    // Аналогично с $idType = 775
    if($idType == 780){
       $arr_group = Array('klass','komnat','plowad','cena','tip_pomeweniya');
       for($x = 2, $i = 0; $x < count($arr_group)+2; $x++, $i++){
         $group = $objType->getFieldsGroupByName($arr_group[$i])->getFields();
         foreach($group as $fieldsName) {
           $total_arr[$x][] = $fieldsName->getName();
         }
      }
    }
    
    $str2 = $str3 = $str4 = $str5 = $str6 = "";
    //Самуй запутанный цикл в котором составляем sql запросы для каждой группы полей, которая есть в GET массиве
    //Попадают в Sql-запрос только поля из GET, т.е. те которые учавствуют в фильтрации в текущем запросе.
    for($t = 2; $t < count($total_arr)+2; $t++){
      $str_rec = "";
      $count = 0;
      for($i =0; $i < count($total_arr[$t]); $i++ ){
        if(array_key_exists($total_arr[$t][$i],$arr_get)){
        if (!$str_rec) $c_index++;  
        $count++;
        $str_var = "c".$c_index.".field_id = '{$objType->getFieldId($total_arr[$t][$i])}'";
        if ($str_rec != "") {$str_rec .= " OR ".$str_var;}
        else $str_rec .= $str_var;
        }
     }
      if ($count > 1) {$str_rec = "AND (c{$c_index}.obj_id = o.id AND ({$str_rec}) AND (c{$c_index}.int_val IN ('1')))";
      }
      if ($count == 1) {$str_rec = "AND (c{$c_index}.obj_id = o.id AND {$str_rec} AND (c{$c_index}.int_val IN ('1')))";
      }
      if ($count > 0){
        switch($t){
        case 2: $str2 = $str_rec; break;
        case 3: $str3 = $str_rec; break;
        case 4: $str4 = $str_rec; break;
        case 5: $str5 = $str_rec; break;
        case 6: $str6 = $str_rec; break;
        }
      }
    }
    // Данный блок необходим для сортировки, если она была активирована на странице
    if(array_key_exists('order_filter',$_GET)){
      $c_index++;
      $id_field = $objType->getFieldId(key($_GET['order_filter']));
      $ord_1 = "AND (c{$c_index}.obj_id = o.id AND c{$c_index}.field_id = '{$id_field}') ";
      $type_field = umiFieldsCollection::getInstance()->getField($id_field)->getFieldType()->getDataType();
      $ord_2 = "ORDER BY c{$c_index}.{$type_field}_val ASC";
      } 
      else {
      $ord_1 = "";
      $ord_2 = "ORDER BY h.ord";
      }
    // Первый из двух блоков, дополнящих составленные выше части sql запроса, все зависит от велечены $c_index   
    $oc = "";
    for ($i =1; $i <= $c_index; $i++ ){
      $oc_var = "cms3_object_content c{$i}";
      if ($i > 1) {$oc .= ", ".$oc_var;}
      else $oc .= $oc_var;
    }
    // Второй из двух блоков, дополнящих составленные выше части sql запроса, все зависит от велечены $c_index
    $c_obj_id = "";  
    if ($c_index > 1){
      for ($i = 2, $b = 1; $i <= $c_index; $i++, $b++){
      $obj_id_var = "AND c{$b}.obj_id = c{$i}.obj_id ";
      $c_obj_id .= $obj_id_var;
      }
    }
    // Лимиты по выводу данных, на основе них в $result будет отобран определнный участок данных. 
    $limit_1 = $per_page*$curr_page;
    $limit_2 = $limit_1 + $per_page;
    $begin_1 = "SELECT DISTINCT h.id FROM cms3_hierarchy_relations hr, cms3_objects o, cms3_hierarchy h , ";
    $begin_2 = " WHERE h.obj_id = o.id AND h.is_deleted = '0' ";
    $average = "AND ((hr.child_id = h.id AND (hr.rel_id = '{$category_id}' AND hr.level <= '1'))) AND h.is_active = '1' AND h.type_id IN ('{$hierarchy_type_id}') ";
    //Знак SQL; - обязательно должен быть у левого края окна!!!
    // Собираем все части Sql запроса
    $sqls=<<<SQL
    {$begin_1}
    {$oc}
    {$begin_2}
    {$str1}
    {$str2}
    {$str3}
    {$str4}
    {$str5}
    {$str6}
    {$ord_1}
    {$average}
    {$c_obj_id}
    {$ord_2}
SQL;

    // l_mysql_query - находится в lib.php в корне сайта. Выполняем sql запрос.
    $result = l_mysql_query($sqls);
			$res = Array();
			while ($row = mysql_fetch_row($result)) {
				list($element_id) = $row;
				$element_id = intval($element_id);
				if(in_array($element_id, $res) == false) {
					$res[] = $element_id;
				}
			}
	  // Отбираем данные с учетом лимитов.
		$result = array_slice($res,$limit_1,$limit_2);
		$total = count($res);
		// Передаем отобранные данные оставшейся части кода, которая осталась без изменений.
		if(($sz = sizeof($result)) > 0) {
			$block_arr = Array();
			$lines = Array();
			for($i = 0; $i < $sz; $i++) {
				$element_id = $result[$i];
				$element = umiHierarchy::getInstance()->getElement($element_id);
				if(!$element) continue;
				$line_arr = Array();
				$line_arr['attribute:id'] = $element_id;
				$line_arr['attribute:alt_name'] = $element->getAltName();
				$line_arr['attribute:link'] = umiHierarchy::getInstance()->getPathById($element_id);
				$line_arr['xlink:href'] = "upage://" . $element_id;
				$line_arr['node:text'] = $element->getName();
				$lines[] = def_module::parseTemplate($template_line, $line_arr, $element_id);
				templater::pushEditable("catalog", "object", $element_id);
				umiHierarchy::getInstance()->unloadElement($element_id);
			}
			$block_arr['subnodes:lines'] = $lines;
			$block_arr['numpages'] = umiPagenum::generateNumPage($total, $per_page);
			$block_arr['total'] = $total;
			$block_arr['per_page'] = $per_page;
			$block_arr['category_id'] = $category_id;
			
			if($type_id) {
				$block_arr['type_id'] = $type_id;
			}
			return def_module::parseTemplate($template_block, $block_arr, $category_id);
		} else {
			$block_arr['numpages'] = umiPagenum::generateNumPage(0, 0);
			$block_arr['lines'] = "";
			$block_arr['total'] = 0;
			$block_arr['per_page'] = 0;
			$block_arr['category_id'] = $category_id;
			
			return def_module::parseTemplate($template_block_empty, $block_arr, $category_id);
		}
    }