Блог
Пагинация комментариев к товару
В HostCMS вывод комментариев реализован самым простейшим способом, все комментарии выводятся в XML товара, поэтому если комментариев будет большое количество, то это может увеличивать время загрузки страницы товара.
Для избежания проблем с производительстью необходимо разбить вывод комментариев на несколько страниц.
Специально для этой цели был разработан контроллер вывода комментариев, для установки и использования контроллера необходимо:
-
Создать файл контроллера *, код контроллера для удобства приведен в конце.
-
Задействовать контроллер в ТДС интернет-магазина, для вывода первой страницы с комментариями используем примерно такой код:
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() ); }
-
Для вывода последующих страниц такой:
// .... $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;
}
}