123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Sales\Model\ResourceModel\Report\Bestsellers;
- /**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
- class Collection extends \Magento\Sales\Model\ResourceModel\Report\Collection\AbstractCollection
- {
- /**
- * Rating limit
- *
- * @var int
- */
- protected $_ratingLimit = 5;
- /**
- * Selected columns
- *
- * @var array
- */
- protected $_selectedColumns = [];
- /**
- * Tables per period
- *
- * @var array
- */
- protected $tableForPeriod = [
- 'daily' => 'sales_bestsellers_aggregated_daily',
- 'monthly' => 'sales_bestsellers_aggregated_monthly',
- 'yearly' => 'sales_bestsellers_aggregated_yearly',
- ];
- /**
- * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
- * @param \Psr\Log\LoggerInterface $logger
- * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
- * @param \Magento\Framework\Event\ManagerInterface $eventManager
- * @param \Magento\Sales\Model\ResourceModel\Report $resource
- * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- */
- public function __construct(
- \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
- \Psr\Log\LoggerInterface $logger,
- \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
- \Magento\Framework\Event\ManagerInterface $eventManager,
- \Magento\Sales\Model\ResourceModel\Report $resource,
- \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
- ) {
- $resource->init($this->getTableByAggregationPeriod('daily'));
- parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $resource, $connection);
- }
- /**
- * Return ordered filed
- *
- * @return string
- */
- protected function getOrderedField()
- {
- return 'qty_ordered';
- }
- /**
- * Return table per period
- *
- * @param string $period
- * @return mixed
- */
- public function getTableByAggregationPeriod($period)
- {
- return $this->tableForPeriod[$period];
- }
- /**
- * Retrieve selected columns
- *
- * @return array
- */
- protected function _getSelectedColumns()
- {
- $connection = $this->getConnection();
- if (!$this->_selectedColumns) {
- if ($this->isTotals()) {
- $this->_selectedColumns = $this->getAggregatedColumns();
- } else {
- $this->_selectedColumns = [
- 'period' => sprintf('MAX(%s)', $connection->getDateFormatSql('period', '%Y-%m-%d')),
- $this->getOrderedField() => 'SUM(' . $this->getOrderedField() . ')',
- 'product_id' => 'product_id',
- 'product_name' => 'MAX(product_name)',
- 'product_price' => 'MAX(product_price)',
- ];
- if ('year' == $this->_period) {
- $this->_selectedColumns['period'] = $connection->getDateFormatSql('period', '%Y');
- } elseif ('month' == $this->_period) {
- $this->_selectedColumns['period'] = $connection->getDateFormatSql('period', '%Y-%m');
- }
- }
- }
- return $this->_selectedColumns;
- }
- /**
- * Make select object for date boundary
- *
- * @param string $from
- * @param string $to
- * @return \Magento\Framework\DB\Select
- */
- protected function _makeBoundarySelect($from, $to)
- {
- $connection = $this->getConnection();
- $cols = $this->_getSelectedColumns();
- $cols[$this->getOrderedField()] = 'SUM(' . $this->getOrderedField() . ')';
- $select = $connection->select()->from(
- $this->getResource()->getMainTable(),
- $cols
- )->where(
- 'period >= ?',
- $from
- )->where(
- 'period <= ?',
- $to
- )->group(
- 'product_id'
- )->order(
- $this->getOrderedField() . ' DESC'
- )->limit(
- $this->_ratingLimit
- );
- $this->_applyStoresFilterToSelect($select);
- return $select;
- }
- /**
- * Init collection select
- *
- * @return $this
- */
- protected function _applyAggregatedTable()
- {
- $select = $this->getSelect();
- //if grouping by product, not by period
- if (!$this->_period) {
- $cols = $this->_getSelectedColumns();
- $cols[$this->getOrderedField()] = 'SUM(' . $this->getOrderedField() . ')';
- if ($this->_from || $this->_to) {
- $mainTable = $this->getTable($this->getTableByAggregationPeriod('daily'));
- $select->from($mainTable, $cols);
- } else {
- $mainTable = $this->getTable($this->getTableByAggregationPeriod('yearly'));
- $select->from($mainTable, $cols);
- }
- //exclude removed products
- $select->where(new \Zend_Db_Expr($mainTable . '.product_id IS NOT NULL'))->group(
- 'product_id'
- )->order(
- $this->getOrderedField() . ' ' . \Magento\Framework\DB\Select::SQL_DESC
- )->limit(
- $this->_ratingLimit
- );
- return $this;
- }
- if ('year' == $this->_period) {
- $mainTable = $this->getTable($this->getTableByAggregationPeriod('yearly'));
- $select->from($mainTable, $this->_getSelectedColumns());
- } elseif ('month' == $this->_period) {
- $mainTable = $this->getTable($this->getTableByAggregationPeriod('monthly'));
- $select->from($mainTable, $this->_getSelectedColumns());
- } else {
- $mainTable = $this->getTable($this->getTableByAggregationPeriod('daily'));
- $select->from($mainTable, $this->_getSelectedColumns());
- }
- if (!$this->isTotals()) {
- $select->group(['period', 'product_id']);
- }
- $select->where('rating_pos <= ?', $this->_ratingLimit);
- return $this;
- }
- /**
- * Get SQL for get record count
- *
- * @return \Magento\Framework\DB\Select
- */
- public function getSelectCountSql()
- {
- $this->_renderFilters();
- $select = clone $this->getSelect();
- $select->reset(\Magento\Framework\DB\Select::ORDER);
- return $this->getConnection()->select()->from($select, 'COUNT(*)');
- }
- /**
- * Set ids for store restrictions
- *
- * @param int|int[] $storeIds
- * @return $this
- */
- public function addStoreRestrictions($storeIds)
- {
- if (!is_array($storeIds)) {
- $storeIds = [$storeIds];
- }
- $currentStoreIds = $this->_storesIds;
- if (isset(
- $currentStoreIds
- ) && $currentStoreIds != \Magento\Store\Model\Store::DEFAULT_STORE_ID && $currentStoreIds != [
- \Magento\Store\Model\Store::DEFAULT_STORE_ID
- ]
- ) {
- if (!is_array($currentStoreIds)) {
- $currentStoreIds = [$currentStoreIds];
- }
- $this->_storesIds = array_intersect($currentStoreIds, $storeIds);
- } else {
- $this->_storesIds = $storeIds;
- }
- return $this;
- }
- /**
- * Redeclare parent method for applying filters after parent method
- * but before adding unions and calculating totals
- *
- * @return $this|\Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
- */
- protected function _beforeLoad()
- {
- parent::_beforeLoad();
- $this->_applyStoresFilter();
- if ($this->_period) {
- $selectUnions = [];
- // apply date boundaries (before calling $this->_applyDateRangeFilter())
- $periodFrom = $this->_from !== null ? new \DateTime($this->_from) : null;
- $periodTo = $this->_to !== null ? new \DateTime($this->_to) : null;
- if ('year' == $this->_period) {
- if ($periodFrom) {
- // not the first day of the year
- if ($periodFrom->format('m') != 1 || $periodFrom->format('d') != 1) {
- $dtFrom = clone $periodFrom;
- // last day of the year
- $dtTo = clone $periodFrom;
- $dtTo->setDate($dtTo->format('Y'), 12, 31);
- if (!$periodTo || $dtTo < $periodTo) {
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- // first day of the next year
- $this->_from = clone $periodFrom;
- $this->_from->modify('+1 year');
- $this->_from->setDate($this->_from->format('Y'), 1, 1);
- $this->_from = $this->_from->format('Y-m-d');
- }
- }
- }
- if ($periodTo) {
- // not the last day of the year
- if ($periodTo->format('m') != 12 || $periodTo->format('d') != 31) {
- $dtFrom = clone $periodTo;
- $dtFrom->setDate($dtFrom->format('Y'), 1, 1);
- // first day of the year
- $dtTo = clone $periodTo;
- if (!$periodFrom || $dtFrom > $periodFrom) {
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- // last day of the previous year
- $this->_to = clone $periodTo;
- $this->_to->modify('-1 year');
- $this->_to->setDate($this->_to->format('Y'), 12, 31);
- $this->_to = $this->_to->format('Y-m-d');
- }
- }
- }
- if ($periodFrom && $periodTo) {
- // the same year
- if ($periodTo->format('Y') == $periodFrom->format('Y')) {
- $dtFrom = clone $periodFrom;
- $dtTo = clone $periodTo;
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- $this->getSelect()->where('1<>1');
- }
- }
- } elseif ('month' == $this->_period) {
- if ($periodFrom) {
- // not the first day of the month
- if ($periodFrom->format('d') != 1) {
- $dtFrom = clone $periodFrom;
- // last day of the month
- $dtTo = clone $periodFrom;
- $dtTo->modify('+1 month');
- $dtTo->setDate($dtTo->format('Y'), $dtTo->format('m'), 1);
- $dtTo->modify('-1 day');
- if (!$periodTo || $dtTo < $periodTo) {
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- // first day of the next month
- $this->_from = clone $periodFrom;
- $this->_from->modify('+1 month');
- $this->_from->setDate($this->_from->format('Y'), $this->_from->format('m'), 1);
- $this->_from = $this->_from->format('Y-m-d');
- }
- }
- }
- if ($periodTo) {
- // not the last day of the month
- if ($periodTo->format('d') != $periodTo->format('t')) {
- $dtFrom = clone $periodTo;
- $dtFrom->setDate($dtFrom->format('Y'), $dtFrom->format('m'), 1);
- // first day of the month
- $dtTo = clone $periodTo;
- if (!$periodFrom || $dtFrom > $periodFrom) {
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- // last day of the previous month
- $this->_to = clone $periodTo;
- $this->_to->setDate($this->_to->format('Y'), $this->_to->format('m'), 1);
- $this->_to->modify('-1 day');
- $this->_to = $this->_to->format('Y-m-d');
- }
- }
- }
- if ($periodFrom && $periodTo) {
- // the same month
- if ($periodTo->format('Y') == $periodFrom->format('Y') &&
- $periodTo->format('m') == $periodFrom->format('m')
- ) {
- $dtFrom = clone $periodFrom;
- $dtTo = clone $periodTo;
- $selectUnions[] = $this->_makeBoundarySelect(
- $dtFrom->format('Y-m-d'),
- $dtTo->format('Y-m-d')
- );
- $this->getSelect()->where('1<>1');
- }
- }
- }
- $this->_applyDateRangeFilter();
- // add unions to select
- if ($selectUnions) {
- $unionParts = [];
- $cloneSelect = clone $this->getSelect();
- $unionParts[] = '(' . $cloneSelect . ')';
- foreach ($selectUnions as $union) {
- $unionParts[] = '(' . $union . ')';
- }
- $this->getSelect()->reset()->union($unionParts, \Magento\Framework\DB\Select::SQL_UNION_ALL);
- }
- if ($this->isTotals()) {
- // calculate total
- $cloneSelect = clone $this->getSelect();
- $this->getSelect()->reset()->from($cloneSelect, $this->getAggregatedColumns());
- } else {
- // add sorting
- $this->getSelect()->order(['period ASC', $this->getOrderedField() . ' DESC']);
- }
- }
- return $this;
- }
- }
|