mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 09:17:35 +00:00
530 lines
16 KiB
PHP
530 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
namespace Magento\Review\Model\ResourceModel;
|
|
|
|
use Magento\Framework\App\Config\ScopeConfigInterface;
|
|
use Magento\Framework\App\ObjectManager;
|
|
|
|
/**
|
|
* Rating resource model
|
|
*
|
|
* @api
|
|
* @since 100.0.2
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*/
|
|
class Rating extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
|
|
{
|
|
public const RATING_STATUS_APPROVED = 'Approved';
|
|
|
|
/**
|
|
* @var \Magento\Store\Model\StoreManagerInterface
|
|
*/
|
|
protected $_storeManager;
|
|
|
|
/**
|
|
* @var \Magento\Framework\Module\Manager
|
|
*/
|
|
protected $moduleManager;
|
|
|
|
/**
|
|
* @var \Psr\Log\LoggerInterface
|
|
*/
|
|
protected $_logger;
|
|
|
|
/**
|
|
* @var ScopeConfigInterface
|
|
*/
|
|
private $scopeConfig;
|
|
|
|
/**
|
|
* @var Review\Summary
|
|
*/
|
|
private $_reviewSummary;
|
|
|
|
/**
|
|
* @param \Magento\Framework\Model\ResourceModel\Db\Context $context
|
|
* @param \Psr\Log\LoggerInterface $logger
|
|
* @param \Magento\Framework\Module\Manager $moduleManager
|
|
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
|
|
* @param Review\Summary $reviewSummary
|
|
* @param string $connectionName
|
|
* @param ScopeConfigInterface|null $scopeConfig
|
|
*/
|
|
public function __construct(
|
|
\Magento\Framework\Model\ResourceModel\Db\Context $context,
|
|
\Psr\Log\LoggerInterface $logger,
|
|
\Magento\Framework\Module\Manager $moduleManager,
|
|
\Magento\Store\Model\StoreManagerInterface $storeManager,
|
|
\Magento\Review\Model\ResourceModel\Review\Summary $reviewSummary,
|
|
$connectionName = null,
|
|
ScopeConfigInterface $scopeConfig = null
|
|
) {
|
|
$this->moduleManager = $moduleManager;
|
|
$this->_storeManager = $storeManager;
|
|
$this->_logger = $logger;
|
|
$this->_reviewSummary = $reviewSummary;
|
|
$this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
|
|
parent::__construct($context, $connectionName);
|
|
}
|
|
|
|
/**
|
|
* Resource initialization
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function _construct()
|
|
{
|
|
$this->_init('rating', 'rating_id');
|
|
}
|
|
|
|
/**
|
|
* Initialize unique fields
|
|
*
|
|
* @return $this
|
|
*/
|
|
protected function _initUniqueFields()
|
|
{
|
|
$this->_uniqueFields = [['field' => 'rating_code', 'title' => '']];
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Retrieve select object for load object data
|
|
*
|
|
* @param string $field
|
|
* @param mixed $value
|
|
* @param \Magento\Review\Model\Rating $object
|
|
* @return \Magento\Framework\DB\Select
|
|
*/
|
|
protected function _getLoadSelect($field, $value, $object)
|
|
{
|
|
$connection = $this->getConnection();
|
|
|
|
$table = $this->getMainTable();
|
|
$storeId = (int)$this->_storeManager->getStore(\Magento\Store\Model\Store::ADMIN_CODE)->getId();
|
|
$select = parent::_getLoadSelect($field, $value, $object);
|
|
$codeExpr = $connection->getIfNullSql('title.value', "{$table}.rating_code");
|
|
|
|
$select->joinLeft(
|
|
['title' => $this->getTable('rating_title')],
|
|
$connection->quoteInto("{$table}.rating_id = title.rating_id AND title.store_id = ?", $storeId),
|
|
['rating_code' => $codeExpr]
|
|
);
|
|
|
|
return $select;
|
|
}
|
|
|
|
/**
|
|
* Actions after load
|
|
*
|
|
* @param \Magento\Framework\Model\AbstractModel|\Magento\Review\Model\Rating $object
|
|
* @return $this
|
|
*/
|
|
protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object)
|
|
{
|
|
parent::_afterLoad($object);
|
|
|
|
if (!$object->getId()) {
|
|
return $this;
|
|
}
|
|
|
|
$connection = $this->getConnection();
|
|
$bind = [':rating_id' => (int)$object->getId()];
|
|
// load rating titles
|
|
$select = $connection->select()->from(
|
|
$this->getTable('rating_title'),
|
|
['store_id', 'value']
|
|
)->where(
|
|
'rating_id=:rating_id'
|
|
);
|
|
|
|
$result = $connection->fetchPairs($select, $bind);
|
|
if ($result) {
|
|
$object->setRatingCodes($result);
|
|
}
|
|
|
|
// load rating available in stores
|
|
$object->setStores($this->getStores((int)$object->getId()));
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Retrieve store IDs related to given rating
|
|
*
|
|
* @param int $ratingId
|
|
* @return array
|
|
*/
|
|
public function getStores($ratingId)
|
|
{
|
|
$select = $this->getConnection()->select()->from(
|
|
$this->getTable('rating_store'),
|
|
'store_id'
|
|
)->where(
|
|
'rating_id = ?',
|
|
$ratingId
|
|
);
|
|
return $this->getConnection()->fetchCol($select);
|
|
}
|
|
|
|
/**
|
|
* Actions after save
|
|
*
|
|
* @param \Magento\Framework\Model\AbstractModel|\Magento\Review\Model\Rating $object
|
|
* @return $this
|
|
*/
|
|
protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
|
|
{
|
|
parent::_afterSave($object);
|
|
if ($object->hasRatingCodes()) {
|
|
$this->processRatingCodes($object);
|
|
}
|
|
|
|
if ($object->hasStores()) {
|
|
$this->processRatingStores($object);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Process rating codes
|
|
*
|
|
* @param \Magento\Framework\Model\AbstractModel $object
|
|
* @return $this
|
|
*/
|
|
protected function processRatingCodes(\Magento\Framework\Model\AbstractModel $object)
|
|
{
|
|
$connection = $this->getConnection();
|
|
$ratingId = (int)$object->getId();
|
|
$table = $this->getTable('rating_title');
|
|
$select = $connection->select()->from($table, ['store_id', 'value'])
|
|
->where('rating_id = :rating_id');
|
|
$old = $connection->fetchPairs($select, [':rating_id' => $ratingId]);
|
|
$new = array_filter(array_map('trim', $object->getRatingCodes()));
|
|
$this->deleteRatingData($ratingId, $table, array_keys(array_diff_assoc($old, $new)));
|
|
|
|
$insert = [];
|
|
foreach (array_diff_assoc($new, $old) as $storeId => $title) {
|
|
$insert[] = ['rating_id' => $ratingId, 'store_id' => (int)$storeId, 'value' => $title];
|
|
}
|
|
$this->insertRatingData($table, $insert);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Process rating stores
|
|
*
|
|
* @param \Magento\Framework\Model\AbstractModel $object
|
|
* @return $this
|
|
*/
|
|
protected function processRatingStores(\Magento\Framework\Model\AbstractModel $object)
|
|
{
|
|
$connection = $this->getConnection();
|
|
$ratingId = (int)$object->getId();
|
|
$table = $this->getTable('rating_store');
|
|
$select = $connection->select()->from($table, ['store_id'])
|
|
->where('rating_id = :rating_id');
|
|
$old = $connection->fetchCol($select, [':rating_id' => $ratingId]);
|
|
$new = $object->getStores();
|
|
$this->deleteRatingData($ratingId, $table, array_diff($old, $new));
|
|
|
|
$insert = [];
|
|
foreach (array_diff($new, $old) as $storeId) {
|
|
$insert[] = ['rating_id' => $ratingId, 'store_id' => (int)$storeId];
|
|
}
|
|
$this->insertRatingData($table, $insert);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Delete rating data
|
|
*
|
|
* @param int $ratingId
|
|
* @param string $table
|
|
* @param array $storeIds
|
|
* @return void
|
|
*/
|
|
protected function deleteRatingData($ratingId, $table, array $storeIds)
|
|
{
|
|
if (empty($storeIds)) {
|
|
return;
|
|
}
|
|
$connection = $this->getConnection();
|
|
$connection->beginTransaction();
|
|
try {
|
|
$where = ['rating_id = ?' => $ratingId, 'store_id IN(?)' => $storeIds];
|
|
$connection->delete($table, $where);
|
|
$connection->commit();
|
|
} catch (\Exception $e) {
|
|
$this->_logger->critical($e);
|
|
$connection->rollBack();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Insert rating data
|
|
*
|
|
* @param string $table
|
|
* @param array $data
|
|
* @return void
|
|
*/
|
|
protected function insertRatingData($table, array $data)
|
|
{
|
|
if (empty($data)) {
|
|
return;
|
|
}
|
|
$connection = $this->getConnection();
|
|
$connection->beginTransaction();
|
|
try {
|
|
$connection->insertMultiple($table, $data);
|
|
$connection->commit();
|
|
} catch (\Exception $e) {
|
|
$this->_logger->critical($e);
|
|
$connection->rollBack();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform actions after object delete
|
|
*
|
|
* Prepare rating data for reaggregate all data for reviews
|
|
*
|
|
* @param \Magento\Framework\Model\AbstractModel $object
|
|
* @return $this
|
|
*/
|
|
protected function _afterDelete(\Magento\Framework\Model\AbstractModel $object)
|
|
{
|
|
parent::_afterDelete($object);
|
|
if (!$this->moduleManager->isEnabled('Magento_Review') &&
|
|
!$this->scopeConfig->getValue(
|
|
\Magento\Review\Observer\PredispatchReviewObserver::XML_PATH_REVIEW_ACTIVE,
|
|
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
|
|
)
|
|
) {
|
|
return $this;
|
|
}
|
|
$data = $this->_getEntitySummaryData($object);
|
|
$summary = [];
|
|
foreach ($data as $row) {
|
|
$clone = clone $object;
|
|
$clone->addData($row);
|
|
$summary[$clone->getStoreId()][$clone->getEntityPkValue()] = $clone;
|
|
}
|
|
$this->_reviewSummary->reAggregate($summary);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return array of rating summary
|
|
*
|
|
* @param \Magento\Review\Model\Rating $object
|
|
* @param boolean $onlyForCurrentStore
|
|
* @return array
|
|
*/
|
|
public function getEntitySummary($object, $onlyForCurrentStore = true)
|
|
{
|
|
$data = $this->_getEntitySummaryData($object);
|
|
|
|
if ($onlyForCurrentStore) {
|
|
foreach ($data as $row) {
|
|
if ($row['store_id'] == $this->_storeManager->getStore()->getId()) {
|
|
$object->addData($row);
|
|
}
|
|
}
|
|
return $object;
|
|
}
|
|
|
|
$stores = $this->_storeManager->getStores();
|
|
|
|
$result = [];
|
|
foreach ($data as $row) {
|
|
$clone = clone $object;
|
|
$clone->addData($row);
|
|
$result[$clone->getStoreId()] = $clone;
|
|
}
|
|
|
|
$usedStoresId = array_keys($result);
|
|
foreach ($stores as $store) {
|
|
if (!in_array($store->getId(), $usedStoresId)) {
|
|
$clone = clone $object;
|
|
$clone->setCount(0);
|
|
$clone->setSum(0);
|
|
$clone->setStoreId($store->getId());
|
|
$result[$store->getId()] = $clone;
|
|
}
|
|
}
|
|
return array_values($result);
|
|
}
|
|
|
|
/**
|
|
* Return data of rating summary
|
|
*
|
|
* @param \Magento\Review\Model\Rating $object
|
|
* @return array
|
|
*/
|
|
protected function _getEntitySummaryData($object)
|
|
{
|
|
$connection = $this->getConnection();
|
|
|
|
$sumColumn = new \Zend_Db_Expr("SUM(rating_vote.{$connection->quoteIdentifier('percent')})");
|
|
$countColumn = new \Zend_Db_Expr("COUNT(*)");
|
|
|
|
$select = $connection->select()->from(
|
|
['rating_vote' => $this->getTable('rating_option_vote')],
|
|
['entity_pk_value' => 'rating_vote.entity_pk_value', 'sum' => $sumColumn, 'count' => $countColumn]
|
|
)->join(
|
|
['review' => $this->getTable('review')],
|
|
'rating_vote.review_id=review.review_id',
|
|
[]
|
|
)->joinLeft(
|
|
['review_store' => $this->getTable('review_store')],
|
|
'rating_vote.review_id=review_store.review_id',
|
|
['review_store.store_id']
|
|
);
|
|
if (!$this->_storeManager->isSingleStoreMode()) {
|
|
$select->join(
|
|
['rating_store' => $this->getTable('rating_store')],
|
|
'rating_store.rating_id = rating_vote.rating_id AND rating_store.store_id = review_store.store_id',
|
|
[]
|
|
);
|
|
}
|
|
$select->join(
|
|
['review_status' => $this->getTable('review_status')],
|
|
'review.status_id = review_status.status_id',
|
|
[]
|
|
)->where(
|
|
'review_status.status_code = :status_code'
|
|
)->group(
|
|
'rating_vote.entity_pk_value'
|
|
)->group(
|
|
'review_store.store_id'
|
|
);
|
|
$bind = [':status_code' => self::RATING_STATUS_APPROVED];
|
|
|
|
$entityPkValue = $object->getEntityPkValue();
|
|
if ($entityPkValue) {
|
|
$select->where('rating_vote.entity_pk_value = :pk_value');
|
|
$bind[':pk_value'] = $entityPkValue;
|
|
}
|
|
|
|
return $connection->fetchAll($select, $bind);
|
|
}
|
|
|
|
/**
|
|
* Review summary
|
|
*
|
|
* @param \Magento\Review\Model\Rating $object
|
|
* @param boolean $onlyForCurrentStore
|
|
* @return array
|
|
*/
|
|
public function getReviewSummary($object, $onlyForCurrentStore = true)
|
|
{
|
|
$connection = $this->getConnection();
|
|
|
|
$sumColumn = new \Zend_Db_Expr("SUM(rating_vote.{$connection->quoteIdentifier('percent')})");
|
|
$countColumn = new \Zend_Db_Expr('COUNT(*)');
|
|
$select = $connection->select()->from(
|
|
['rating_vote' => $this->getTable('rating_option_vote')],
|
|
['sum' => $sumColumn, 'count' => $countColumn]
|
|
)->joinLeft(
|
|
['review_store' => $this->getTable('review_store')],
|
|
'rating_vote.review_id = review_store.review_id',
|
|
['review_store.store_id']
|
|
);
|
|
if (!$this->_storeManager->isSingleStoreMode()) {
|
|
$select->join(
|
|
['rating_store' => $this->getTable('rating_store')],
|
|
'rating_store.rating_id = rating_vote.rating_id AND rating_store.store_id = review_store.store_id',
|
|
[]
|
|
);
|
|
}
|
|
$select->where(
|
|
'rating_vote.review_id = :review_id'
|
|
)->group(
|
|
'rating_vote.review_id'
|
|
)->group(
|
|
'review_store.store_id'
|
|
);
|
|
|
|
$data = $connection->fetchAll($select, [':review_id' => $object->getReviewId()]);
|
|
|
|
$currentStore = $this->_storeManager->isSingleStoreMode() ? $this->_storeManager->getStore()->getId() : null;
|
|
|
|
if ($onlyForCurrentStore) {
|
|
foreach ($data as $row) {
|
|
if ($row['store_id'] !== $currentStore) {
|
|
$object->addData($row);
|
|
}
|
|
}
|
|
return $object;
|
|
}
|
|
|
|
$result = [];
|
|
|
|
$stores = $this->_storeManager->getStore()->getResourceCollection()->load();
|
|
|
|
foreach ($data as $row) {
|
|
$clone = clone $object;
|
|
$clone->addData($row);
|
|
$result[$clone->getStoreId()] = $clone;
|
|
}
|
|
|
|
$usedStoresId = array_keys($result);
|
|
|
|
foreach ($stores as $store) {
|
|
if (!in_array($store->getId(), $usedStoresId)) {
|
|
$clone = clone $object;
|
|
$clone->setCount(0);
|
|
$clone->setSum(0);
|
|
$clone->setStoreId($store->getId());
|
|
$result[$store->getId()] = $clone;
|
|
}
|
|
}
|
|
|
|
return array_values($result);
|
|
}
|
|
|
|
/**
|
|
* Get rating entity type id by code
|
|
*
|
|
* @param string $entityCode
|
|
* @return int
|
|
*/
|
|
public function getEntityIdByCode($entityCode)
|
|
{
|
|
$select = $this->getConnection()->select()->from(
|
|
$this->getTable('rating_entity'),
|
|
['entity_id']
|
|
)->where(
|
|
'entity_code = :entity_code'
|
|
);
|
|
|
|
return $this->getConnection()->fetchOne($select, [':entity_code' => $entityCode]);
|
|
}
|
|
|
|
/**
|
|
* Delete ratings by product id
|
|
*
|
|
* @param int $productId
|
|
* @return $this
|
|
*/
|
|
public function deleteAggregatedRatingsByProductId($productId)
|
|
{
|
|
$entityId = $this->getEntityIdByCode(\Magento\Review\Model\Rating::ENTITY_PRODUCT_CODE);
|
|
$connection = $this->getConnection();
|
|
$select = $connection->select()->from($this->getMainTable(), 'rating_id')->where('entity_id = :entity_id');
|
|
$ratingIds = $connection->fetchCol($select, [':entity_id' => $entityId]);
|
|
|
|
if ($ratingIds) {
|
|
$where = ['entity_pk_value = ?' => (int)$productId, 'rating_id IN(?)' => $ratingIds];
|
|
$connection->delete($this->getTable('rating_option_vote_aggregated'), $where);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
}
|