Пагинация комментариев к товару

В HostCMS вывод комментариев реализован самым простейшим способом, все комментарии выводятся в XML товара, поэтому если комментариев будет большое количество, то это может увеличивать время загрузки страницы товара.

Для избежания проблем с производительстью необходимо разбить вывод комментариев на несколько страниц.

Специально для этой цели был разработан контроллер вывода комментариев, для установки и использования контроллера необходимо:

  1. Создать файл контроллера *, код контроллера для удобства приведен в конце.

  2. Задействовать контроллер в ТДС интернет-магазина, для вывода первой страницы с комментариями используем примерно такой код:

    if ($Shop_Controller_Show->item)
    {
    	$oShopItemCommentController = new Shop_Item_Comment_Controller(
    		Core_Entity::factory('Shop_Item', $Shop_Controller_Show->item)
    	);
    
    	$Shop_Controller_Show
    		->comments(FALSE)
    		->addEntity(
    			$oShopItemCommentController->getCommentsAggregationXml()
    		)
    		->addEntity(
    			$oShopItemCommentController->getCommentsXml()
    		);
    }
  3. Для вывода последующих страниц такой:

    // ....
    
    $oShopItemCommentController = new Shop_Item_Comment_Controller(
    	Core_Entity::factory('Shop_Item', $oShopControllerShow->item)
    );
    
    $oShopItemCommentController->offset(Core_Array::getGet('offset', 0));
    $oShopItemCommentController->limit(Core_Array::getGet('limit', 5));
    
    $oShopControllerShow
    	->addEntity(
    		$oShopItemCommentController->getCommentsXml()
    	);
    
    // ....
    
    $oShopControllerShow->show();

* Код контроллера для вывода комментариев:

<?php

defined('HOSTCMS') || exit('HostCMS: access denied.');

class Shop_Item_Comment_Controller extends Core_Controller
{
	protected $_allowedProperties = array(
		'offset',
		'limit'
	);

	public function __construct(Shop_Item_Model $oShopItem)
	{
		parent::__construct(
			$oShopItem->showXmlComments(FALSE)
		);

		$this->offset = 0;
		$this->limit = 2;
	}

	public function show()
	{
		Core_Event::notify(get_class($this) . '.onBeforeRedeclaredShow', $this);
 
		$this->addEntity(
			$this->getCommentsXml()
		);

		parent::show();
	}
	
	/**
	 * Возвращает информацию о количестве и оценках комментариев на основе все добавленных к товару комментариев.
	 */
	public function getCommentsAggregationXml()
	{
		$sCountAll = 'COUNT(*)';
		$sCountGrades = 'SUM(
			IF (comments.grade > 0,
				1,
				0
			)
		)';
		$sSumGrades = 'SUM(
			IF (comments.grade > 0,
				comments.grade,
				0
			)
		)';

		$oCoreQueryBuilder = Core_QueryBuilder::select()
			->select(array(Core_QueryBuilder::expression($sCountAll), 'count'))
			->select(array(Core_QueryBuilder::expression($sCountGrades), 'grade_count'))
			->select(array(Core_QueryBuilder::expression($sSumGrades), 'grade_sum'))
			->from('comments')
			->join('comment_shop_items', 'comment_shop_items.comment_id', '=', 'comments.id', array(
				array('AND' => array('comment_shop_items.shop_item_id', '=', $this->getEntity()->id))
			))
			->where('comments.parent_id', '=', 0)
			->where('comments.active', '=', 1)
			->where('comments.deleted', '=', 0);

		$aResult = $oCoreQueryBuilder->execute()->asAssoc()->current();

		// Данные для расчета
		$commentsCount = $aResult['count'];
		$gradeSum = $aResult['grade_sum'];
		$gradeCount = $aResult['grade_count'];

		// Средняя оценка
		$avgGrade = $gradeCount > 0
			? $gradeSum / $gradeCount
			: 0;

		$fractionalPart = $avgGrade - floor($avgGrade);
		$avgGrade = floor($avgGrade);

		if ($fractionalPart >= 0.25 && $fractionalPart < 0.75)
		{
			$avgGrade += 0.5;
		}
		elseif ($fractionalPart >= 0.75)
		{
			$avgGrade += 1;
		}

		$oAggregationXml = Core::factory('Core_Xml_Entity')
			->name('comments_aggregation')
			->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('count')
					->value($commentsCount)
			)
			->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('grade_sum')
					->value($gradeSum)
			)
			->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('grade_count')
					->value($gradeCount)
			)
			->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('average_grade')
					->value($avgGrade)
			);

		return $oAggregationXml;
	}
	
	/**
	 * Возвращает список комментариев для вывода.
	 */
	public function getCommentsXml()
	{
		// Получаем список комментариев первого уровня
		$oComments = $this->getEntity()->Comments;
		$oComments->getTableColums();
		$oComments->queryBuilder()
			->sqlCalcFoundRows()
			->where('comments.active', '=', 1)
			->where('comments.parent_id', '=', 0)
			->orderBy('comments.datetime', 'DESC')
			->offset($this->offset)
			->limit($this->limit);

		$aoComments = $oComments->findAll();

		// Получаем общее количество родительских комментариев
		$result = Core_QueryBuilder::select(array('FOUND_ROWS()', 'count'))->execute()->asAssoc()->current();
		$total = $result['count'];

		$aoParentComments = array();
		$aCommentIds = array();
		foreach ($aoComments as $oComment)
		{
			$aoParentComments[$oComment->id] = $oComment;
			$aCommentIds[] = $oComment->id;
		}

		$oCommentsXml = Core::factory('Core_Xml_Entity')
			->name('comments')
			->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('offset')
					->value($this->offset)
			)->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('limit')
					->value($this->limit)
			)->addEntity(
				Core::factory('Core_Xml_Entity')
					->name('total')
					->value($total)
			);

		// Получаем список дочерних комментариев
		if ($aCommentIds)
		{
			$oChildComments = Core_Entity::factory('Comment');
			$oChildComments->queryBuilder()
				->where('comments.active', '=', 1)
				->where('comments.parent_id', 'IN', $aCommentIds)
				->orderBy('comments.datetime', 'DESC');
			$aoChildComments = $oChildComments->findAll();

			foreach ($aoChildComments as $oChildComment)
			{
				$aoParentComments[$oChildComment->parent_id]
					->addEntity(
						$oChildComment
					);
			}

			$oCommentsXml->addEntities(
				$aoParentComments
			);
		}

		return $oCommentsXml;
	}
}
comments powered by Disqus


Следующий "Ускорить индексирование сайта в поисковых системах" К списку Предыдущий "Адаптация сайта под мобильные устройства"