Вывод новостей по сюжету — различия между версиями
| Mad grant (обсуждение | вклад) | Mad grant (обсуждение | вклад)  | ||
| Строка 66: | Строка 66: | ||
| <source lang="php"> | <source lang="php"> | ||
| + | public function subjectsList($id = '', $template = '', $mode = '', $per_page = 0, $ignore_paging = false){	 | ||
| + | 	if(!$id){ | ||
| + | 		throw new publicException('<b>В макросе news subjectsList() необходимо указать первый параметр $id</b>'); | ||
| + | 	} | ||
| + | |||
| + | 	$id = preg_replace('/\s/', '', $id);		 | ||
| + | 	$parsId = array(); | ||
| + | 	$parsId = explode(';',$id); | ||
| + | 	unset($id); | ||
| + | |||
| + | 	if(!$template){ | ||
| + | 		$template = 'default'; | ||
| + | 	} | ||
| + | |||
| + | 	if(!$mode){ | ||
| + | 		$mode = 'and'; | ||
| + | 	} | ||
| + | |||
| + | 	if(!$per_page){ | ||
| + | 		(int) $per_page = $this->per_page; | ||
| + | 	} | ||
| + | |||
| + | 	if(!is_numeric($per_page)){ | ||
| + | 		throw new publicException('<b>В макрос news subjectsList() передано некорректно значение номера страницы</b>'); | ||
| + | 	} | ||
| + | |||
| + | 	list($template_block, $template_block_empty, $template_line) = def_module::loadTemplates("news/".$template, "items_block", "items_block_empty", "item_block"); | ||
| + | |||
| + | 	$currPageNum = getRequest('p'); | ||
| + | |||
| + | 	$resultSubjects = array(); | ||
| + | 	$subjectsQuery = new selector('objects'); | ||
| + | 	$subjectsQuery->types('object-type')->name('news', 'subject'); | ||
| + | 	$subjectsQuery->where('subject-id')->equals($parsId); | ||
| + | 	$resultSubjects = $subjectsQuery->result(); | ||
| + | 	unset($subjectsQuery, $parsId); | ||
| + | |||
| + | 	(int) $countSubject = count($resultSubjects); | ||
| + | |||
| + | 	if($countSubject === 0){ | ||
| + | 		throw new publicException('<b>Сюжеты с переданными id не найдены</b>'); | ||
| + | 	} | ||
| + | |||
| + | 	$resultItems = array(); | ||
| + | 	$itemsQuery = new selector('pages'); | ||
| + | 	$itemsQuery->types('object-type')->name('news', 'item'); | ||
| + | 	$itemsQuery->option('or-mode')->field('subjects'); | ||
| + | 	$itemsQuery->where('subjects')->equals($resultSubjects);	 | ||
| + | |||
| + | 	switch ($mode){ | ||
| + | 		case 'or': | ||
| + | 			$allItems = array(); | ||
| + | 			$allItems = $itemsQuery->result(); | ||
| + | |||
| + | 			if(count($allItems) === 0){ | ||
| + | 				return $template_block_empty; | ||
| + | 			} | ||
| + | |||
| + | 			foreach($allItems as $oneItem){				 | ||
| + | 				$items = array(); | ||
| + | 				$items[] = $oneItem->getValue('subjects'); | ||
| + | |||
| + | 				foreach($items as $item){					 | ||
| + | 					$test = array(); | ||
| + | 					$test = array_diff($resultSubjects, $item);	 | ||
| + | |||
| + | 					if (count($test) === 0){		 | ||
| + | |||
| + | 						if($countSubject > 1){		 | ||
| + | 							$resultItems[] = $oneItem;		 | ||
| + | |||
| + | 						}elseif(count($item) === 1){		 | ||
| + | 							$resultItems[] = $oneItem;			 | ||
| + | 						} | ||
| + | 					} | ||
| + | 				} | ||
| + | 			} | ||
| + | 			unset($itemsQuery, $allItems, $oneItem, $items, $item, $test, $resultSubjects, $countSubject); | ||
| + | |||
| + | 			usort($resultItems, function($a, $b){ | ||
| + | |||
| + | 				$a_publishTime = $a->getValue('publish_time'); | ||
| + | 				$b_publishTime = $b->getValue('publish_time'); | ||
| + | |||
| + | 				if ($a_publishTime == $b_publishTime) { | ||
| + | 					return 0; | ||
| + | 				} | ||
| + | 				return ($a_publishTime > $b_publishTime) ? -1 : 1; | ||
| + | 			}); | ||
| + | |||
| + | 			if(intval($ignore_paging) === 0){ | ||
| + | 				$offset = 0; | ||
| + | 				$offset = intval($currPageNum) * intval($per_page); | ||
| + | |||
| + | 				$resultItems = array_slice($resultItems, $offset, $per_page); | ||
| + | 				unset($offset); | ||
| + | 			} | ||
| + | 			$total = 0; | ||
| + | 			$total = count($resultItems); | ||
| + | |||
| + | 		break; | ||
| + | |||
| + | 		case 'and': | ||
| + | 			unset($resultSubjects, $countSubject); | ||
| + | |||
| + | 			$itemsQuery->order('publish_time')->desc(); | ||
| + | |||
| + | 			if(intval($ignore_paging) === 0){ | ||
| + | 				$offset  = 0; | ||
| + | 				$offset  = intval($currPageNum) * intval($per_page); | ||
| + | 				$itemsQuery->limit($offset , intval($per_page)); | ||
| + | 			} | ||
| + | 			$total = 0; | ||
| + | 			$total = $itemsQuery->length(); | ||
| + | 			$resultItems = $itemsQuery->result(); | ||
| + | 			unset($itemsQuery, $offset); | ||
| + | |||
| + | 		break; | ||
| + | |||
| + | 		default: | ||
| + | 			throw new publicException('<b>В макросе news subjectsList() необходимо указать корректное значение параметра $mode (or или and)</b>'); | ||
| + | 	}			 | ||
| + | 	if($total === 0){ | ||
| + | 		return $template_block_empty; | ||
| + | 	}else{ | ||
| + | 		$lines = Array(); | ||
| + | 		$block_arr = Array(); | ||
| + | |||
| + | 		foreach ($resultItems as $resultItem){ | ||
| + | 			$line_arr = array(); | ||
| + | |||
| + | 			$itemId = $resultItem->id; | ||
| + | 			$line_arr['attribute:id'] = $itemId; | ||
| + | 			$line_arr['attribute:link'] = $resultItem->link; | ||
| + | 			$line_arr['xlink:href'] = "upage://" . $itemId; | ||
| + | 			$line_arr['void:header'] = $lines_arr['name'] = $resultItem->getName(); | ||
| + | 			$line_arr['node:name'] =  $resultItem->getName(); | ||
| + | |||
| + | 			if($publish_time = $resultItem->getValue('publish_time')){ | ||
| + | 				$line_arr['attribute:publish_time'] = $publish_time->getFormattedDate("U"); | ||
| + | 			} | ||
| + | 			unset($resultItems, $resultItem); | ||
| + | |||
| + | 			$lines[] = def_module::parseTemplate($template_line, $line_arr, $itemId); | ||
| + | 			unset($line_arr); | ||
| + | |||
| + | 			$this->pushEditable("news", "item", $itemId); | ||
| + | 			unset($itemId); | ||
| + | 		} | ||
| + | 		$block_arr['subnodes:items'] = $block_arr['void:lines'] = $lines; | ||
| + | 		unset($lines); | ||
| + | |||
| + | 		$block_arr['total'] = $total; | ||
| + | 		$block_arr['per_page'] = $per_page; | ||
| + | 		unset($total, $per_page); | ||
| + | |||
| + | 		return def_module::parseTemplate($template_block, $block_arr);	 | ||
| + | 	} | ||
| + | } | ||
| </source> | </source> | ||
Версия 15:17, 31 октября 2013
Актуально для версии 2.9.1
Содержание
Задача
Стандартно в UMI.CMS у типа данных "Новость" есть поле "Сюжеты", также есть одноименный тип данных. У любой новости можно выбрать некоторое количество сюжетов:
Есть макрос %news related_links()%, который выводит список последних новостей, связанных по сюжету с указанной новостью. А если мы просто захотим вывести все новости, у которых указан определенный сюжеты или сюжеты, то такого макрос в системе нет. Можно конечно указать у новости тег и вывести все страницы с указанным тегом, но это не самое красивое и удобное решение, особенно, если используете теги для других нужд.
Решение
В этой статье будет приведен макрос, решающий нашу задачу, но сначала нужно будет внести некоторые изменения в тип данных "Сюжет публикации", добавим в этот тип данных следующую группу полей и поле, обязательно с теми же идентификаторами:
Для использования, приведённого ниже, макроса, нам нужно будет заполнить созданное поле у элементов справочника "Сюжет публикации", обязательно латинскими буквами, например так:
А потом можно будет выбрать эти значения у новостей:
Описание макроса
%news subjectsList()% — выводит новости, относящиеся к выбранн(ому)ым сюже(ту)там.
Параметры: news subjectsList($id, [$template = 'default', $mode = 'and', $per_page = 0, $ignore_paging = false])
$id
Принимает идентификатор сюжета, поле, которое мы создали ранее. Можно указать несколько идентификатором через знак ";".
$template
Принимает имя шаблона, по которому выводится результат макроса, если его не указать, то он принимает значение 'default' В XSLT-шаблонизаторе игнорируется.
$mode
Принимаем два значения 'and' и 'or', когда выбрано 'and', макрос возвращает новости, среди сюжетов которых присутствуют указанные в параметре $id сюжеты, когда выбрано 'or', макрос возвращаем новости, у которых сюжеты полностью совпадают с указанными в параметре $id сюжетами. Если параметр не указать, то будет по-умолчанию равен 'and'.
$per_page
Принимает число, которое обозначает максимальное количество новостей. Если этот параметр не указывать, будет взято значение, указанное в настройках модуля «Новости».
$ignore_paging
Принимаем булево значение («1» или «0»), указывающее макросу игнорировать значение текущей страницы списка вывода (параметр http-запроса p). То есть, если указать «1», макрос будет всегда выводить только первую страницу списка новостей.
Для применения этого макроса скопируйте содержимое листинга макроса в файл /classes/modules/news/__custom.php, и не забудьте указать имя метода в permissions.custom.php, то есть создать такой файл в директории /classes/modules/news/ со следующим содержимым:
<?php
   $permissions = array(
	'view' => array(
			'subjectsList'
		)
	);
?>
Листинг макроса
public function subjectsList($id = '', $template = '', $mode = '', $per_page = 0, $ignore_paging = false){	
	if(!$id){
		throw new publicException('<b>В макросе news subjectsList() необходимо указать первый параметр $id</b>');
	}
	
	$id = preg_replace('/\s/', '', $id);		
	$parsId = array();
	$parsId = explode(';',$id);
	unset($id);
	
	if(!$template){
		$template = 'default';
	}
	
	if(!$mode){
		$mode = 'and';
	}
	
	if(!$per_page){
		(int) $per_page = $this->per_page;
	}
	
	if(!is_numeric($per_page)){
		throw new publicException('<b>В макрос news subjectsList() передано некорректно значение номера страницы</b>');
	}
	
	list($template_block, $template_block_empty, $template_line) = def_module::loadTemplates("news/".$template, "items_block", "items_block_empty", "item_block");
	
	$currPageNum = getRequest('p');
	
	$resultSubjects = array();
	$subjectsQuery = new selector('objects');
	$subjectsQuery->types('object-type')->name('news', 'subject');
	$subjectsQuery->where('subject-id')->equals($parsId);
	$resultSubjects = $subjectsQuery->result();
	unset($subjectsQuery, $parsId);
	
	(int) $countSubject = count($resultSubjects);
	
	if($countSubject === 0){
		throw new publicException('<b>Сюжеты с переданными id не найдены</b>');
	}
	
	$resultItems = array();
	$itemsQuery = new selector('pages');
	$itemsQuery->types('object-type')->name('news', 'item');
	$itemsQuery->option('or-mode')->field('subjects');
	$itemsQuery->where('subjects')->equals($resultSubjects);	
	
	switch ($mode){
		case 'or':
			$allItems = array();
			$allItems = $itemsQuery->result();
			
			if(count($allItems) === 0){
				return $template_block_empty;
			}
			
			foreach($allItems as $oneItem){				
				$items = array();
				$items[] = $oneItem->getValue('subjects');
				
				foreach($items as $item){					
					$test = array();
					$test = array_diff($resultSubjects, $item);	
					
					if (count($test) === 0){		
					
						if($countSubject > 1){		
							$resultItems[] = $oneItem;		
							
						}elseif(count($item) === 1){		
							$resultItems[] = $oneItem;			
						}
					}
				}
			}
			unset($itemsQuery, $allItems, $oneItem, $items, $item, $test, $resultSubjects, $countSubject);
			
			usort($resultItems, function($a, $b){
			
				$a_publishTime = $a->getValue('publish_time');
				$b_publishTime = $b->getValue('publish_time');
				
				if ($a_publishTime == $b_publishTime) {
					return 0;
				}
				return ($a_publishTime > $b_publishTime) ? -1 : 1;
			});
			
			if(intval($ignore_paging) === 0){
				$offset = 0;
				$offset = intval($currPageNum) * intval($per_page);
				
				$resultItems = array_slice($resultItems, $offset, $per_page);
				unset($offset);
			}
			$total = 0;
			$total = count($resultItems);
			
		break;
		
		case 'and':
			unset($resultSubjects, $countSubject);
			
			$itemsQuery->order('publish_time')->desc();
			
			if(intval($ignore_paging) === 0){
				$offset  = 0;
				$offset  = intval($currPageNum) * intval($per_page);
				$itemsQuery->limit($offset , intval($per_page));
			}
			$total = 0;
			$total = $itemsQuery->length();
			$resultItems = $itemsQuery->result();
			unset($itemsQuery, $offset);
			
		break;
		
		default:
			throw new publicException('<b>В макросе news subjectsList() необходимо указать корректное значение параметра $mode (or или and)</b>');
	}			
	if($total === 0){
		return $template_block_empty;
	}else{
		$lines = Array();
		$block_arr = Array();
		foreach ($resultItems as $resultItem){
			$line_arr = array();
			$itemId = $resultItem->id;
			$line_arr['attribute:id'] = $itemId;
			$line_arr['attribute:link'] = $resultItem->link;
			$line_arr['xlink:href'] = "upage://" . $itemId;
			$line_arr['void:header'] = $lines_arr['name'] = $resultItem->getName();
			$line_arr['node:name'] =  $resultItem->getName();
			if($publish_time = $resultItem->getValue('publish_time')){
				$line_arr['attribute:publish_time'] = $publish_time->getFormattedDate("U");
			}
			unset($resultItems, $resultItem);
			
			$lines[] = def_module::parseTemplate($template_line, $line_arr, $itemId);
			unset($line_arr);
			
			$this->pushEditable("news", "item", $itemId);
			unset($itemId);
		}
		$block_arr['subnodes:items'] = $block_arr['void:lines'] = $lines;
		unset($lines);
		
		$block_arr['total'] = $total;
		$block_arr['per_page'] = $per_page;
		unset($total, $per_page);
		
		return def_module::parseTemplate($template_block, $block_arr);	
	}
}




