Вывод новостей по сюжету — различия между версиями

Материал из Umicms
Перейти к:навигация, поиск
Строка 301: Строка 301:
 
Выводит обрамляющий блок для вывода результатов работы макроса, куда будут подставляться результирующие элементы. Отдельные новости будут отрисованы по блоку item.
 
Выводит обрамляющий блок для вывода результатов работы макроса, куда будут подставляться результирующие элементы. Отдельные новости будут отрисованы по блоку item.
  
%items%
+
'''%items%'''
  
 
     Выводит список страниц, отрисованных с помощью блока item_block.
 
     Выводит список страниц, отрисованных с помощью блока item_block.
Строка 309: Строка 309:
 
Отвечает за вывод отдельной новости, полученной в результате работы макроса.
 
Отвечает за вывод отдельной новости, полученной в результате работы макроса.
  
%id%
+
'''%id%'''
  
 
     Выводит id новости.
 
     Выводит id новости.
%link%
+
'''%link%'''
  
 
     Выводит uri новости.
 
     Выводит uri новости.
%value%
+
'''%value%'''
  
 
     Выводит название новости.
 
     Выводит название новости.
%publish_time%
+
'''%publish_time%'''
  
 
     Выводит время публикации новости в UNIX TIMESTAMP.
 
     Выводит время публикации новости в UNIX TIMESTAMP.
%total%
+
'''%total%'''
  
 
     Общее количество полученных новостей.
 
     Общее количество полученных новостей.
%per_page%
+
'''%per_page%'''
  
 
     Выводит количество новостей, отображаемых на странице.
 
     Выводит количество новостей, отображаемых на странице.

Версия 15:41, 31 октября 2013

Актуально для версии 2.9.1

Задача

Стандартно в UMI.CMS у типа данных "Новость" есть поле "Сюжеты", также есть одноименный тип данных. У любой новости можно выбрать некоторое количество сюжетов:

Subject1.png

Есть макрос %news related_links()%, который выводит список последних новостей, связанных по сюжету с указанной новостью. А если мы просто захотим вывести все новости, у которых указан определенный сюжеты или сюжеты, то такого макрос в системе нет. Можно конечно указать у новости тег и вывести все страницы с указанным тегом, но это не самое красивое и удобное решение, особенно, если используете теги для других нужд.

Решение

В этой статье будет приведен макрос, решающий нашу задачу, но сначала нужно будет внести некоторые изменения в тип данных "Сюжет публикации", добавим в этот тип данных следующую группу полей и поле, обязательно с теми же идентификаторами:

Subject2.png

Для использования, приведённого ниже, макроса, нам нужно будет заполнить созданное поле у элементов справочника "Сюжет публикации", обязательно латинскими буквами, например так:

Subject3.png

А потом можно будет выбрать эти значения у новостей:

Subject4.png

Описание макроса

%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);	
	}
}

Применение в xslt

Пример вызова

udata/news/subjectsList/(eco;pol)//or/3/1/

XML-ответ UData

<udata xmlns:xlink="http://www.w3.org/TR/xlink" module="news" method="subjectsList" generation-time="0.075129">
   <items>
      <item id="191" link="/novosti3/novost7/" xlink:href="upage://191" publish_time="1382102520">Новость7</item>
      <item id="190" link="/novosti3/novost6/" xlink:href="upage://190" publish_time="1382102520">Новость6</item>
      <item id="189" link="/novosti3/novost5/" xlink:href="upage://189" publish_time="1382102520">Новость5</item>
      <item id="187" link="/novosti2/novost4/" xlink:href="upage://187" publish_time="1382001240">Новость4</item>
      <item id="185" link="/novosti2/novost2/" xlink:href="upage://185" publish_time="1381913100">Новость2</item>
      <item id="184" link="/novosti2/novost1/" xlink:href="upage://184" publish_time="1381826640">Новость1</item>
      <item id="186" link="/news1/novost3/" xlink:href="upage://186" publish_time="1381742040">Новость3</item>
      <item id="78" link="/news1/speshite_akciya/" xlink:href="upage://78" publish_time="1261279500">Новость9</item>
      <item id="79" link="/news1/ne_speshite_ona_zakonchilas/" xlink:href="upage://79" publish_time="1259020800">Новость8</item>
   </items>
   <total>9</total>
   <per_page>3</per_page>
</udata>

Элементы и атрибуты

<items>

   Ветвь, содержащая элементы item — новости.

<item>

   Элемент, описывающий отдельную новость. Значение элемента — название страницы новости.

@id

   Идентификатор страницы новости.

@link

   Ссылка на страницу полного текста новости.

@xlink:href

   Ссылка UPage на страницу полного текста новости.

@publish_time

   Время публикации новости в UNIX TIMESTAMP.

<total>

   Общее количество полученных новостей.

<per_page>

   Количество новостей, отображаемых на странице.

Применение в tpl

Пример вызова макроса

%news subjectsList('eco;pol', 'default', 'or', '10', '1')%

Используемые шаблоны

Макрос оперирует шаблонами, находящимися в каталоге /tpls/news/. Вывод макроса осуществляется по шаблону, указанному в параметре template. Вы можете не указывать этот параметр, тогда для вывода будет использован шаблон по умолчанию — default.tpl.

Используемые блоки шаблона

items_block

Выводит обрамляющий блок для вывода результатов работы макроса, куда будут подставляться результирующие элементы. Отдельные новости будут отрисованы по блоку item.

%items%

   Выводит список страниц, отрисованных с помощью блока item_block.

item_block

Отвечает за вывод отдельной новости, полученной в результате работы макроса.

%id%

   Выводит id новости.

%link%

   Выводит uri новости.

%value%

   Выводит название новости.

%publish_time%

   Выводит время публикации новости в UNIX TIMESTAMP.

%total%

   Общее количество полученных новостей.

%per_page%

   Выводит количество новостей, отображаемых на странице.

items_block_empty

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