AbstractGrid.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Reports\Block\Adminhtml\Grid;
  7. /**
  8. * Backend reports grid
  9. */
  10. class AbstractGrid extends \Magento\Backend\Block\Widget\Grid\Extended
  11. {
  12. /**
  13. * @var string
  14. */
  15. protected $_resourceCollectionName = '';
  16. /**
  17. * @var null
  18. */
  19. protected $_currentCurrencyCode = null;
  20. /**
  21. * @var array
  22. */
  23. protected $_storeIds = [];
  24. /**
  25. * @var null
  26. */
  27. protected $_aggregatedColumns = null;
  28. /**
  29. * Reports data
  30. *
  31. * @var \Magento\Reports\Helper\Data
  32. */
  33. protected $_reportsData = null;
  34. /**
  35. * Reports grouped collection factory
  36. *
  37. * @var \Magento\Reports\Model\Grouped\CollectionFactory
  38. */
  39. protected $_collectionFactory;
  40. /**
  41. * Resource collection factory
  42. *
  43. * @var \Magento\Reports\Model\ResourceModel\Report\Collection\Factory
  44. */
  45. protected $_resourceFactory;
  46. /**
  47. * @param \Magento\Backend\Block\Template\Context $context
  48. * @param \Magento\Backend\Helper\Data $backendHelper
  49. * @param \Magento\Reports\Model\ResourceModel\Report\Collection\Factory $resourceFactory
  50. * @param \Magento\Reports\Model\Grouped\CollectionFactory $collectionFactory
  51. * @param \Magento\Reports\Helper\Data $reportsData
  52. * @param array $data
  53. */
  54. public function __construct(
  55. \Magento\Backend\Block\Template\Context $context,
  56. \Magento\Backend\Helper\Data $backendHelper,
  57. \Magento\Reports\Model\ResourceModel\Report\Collection\Factory $resourceFactory,
  58. \Magento\Reports\Model\Grouped\CollectionFactory $collectionFactory,
  59. \Magento\Reports\Helper\Data $reportsData,
  60. array $data = []
  61. ) {
  62. $this->_resourceFactory = $resourceFactory;
  63. $this->_collectionFactory = $collectionFactory;
  64. $this->_reportsData = $reportsData;
  65. parent::__construct($context, $backendHelper, $data);
  66. }
  67. /**
  68. * Pseudo constructor
  69. *
  70. * @return void
  71. */
  72. protected function _construct()
  73. {
  74. parent::_construct();
  75. $this->setFilterVisibility(false);
  76. $this->setPagerVisibility(false);
  77. $this->setUseAjax(false);
  78. if (isset($this->_columnGroupBy)) {
  79. $this->isColumnGrouped($this->_columnGroupBy, true);
  80. }
  81. $this->setEmptyCellLabel(__('We can\'t find records for this period.'));
  82. }
  83. /**
  84. * Get resource collection name
  85. *
  86. * @return string
  87. * @codeCoverageIgnore
  88. */
  89. public function getResourceCollectionName()
  90. {
  91. return $this->_resourceCollectionName;
  92. }
  93. /**
  94. * Return reports collection
  95. *
  96. * @return \Magento\Framework\Data\Collection
  97. */
  98. public function getCollection()
  99. {
  100. if ($this->_collection === null) {
  101. $this->setCollection($this->_collectionFactory->create());
  102. }
  103. return $this->_collection;
  104. }
  105. /**
  106. * Retrieve array of columns that should be aggregated
  107. *
  108. * @return array
  109. */
  110. protected function _getAggregatedColumns()
  111. {
  112. if ($this->_aggregatedColumns === null) {
  113. foreach ($this->getColumns() as $column) {
  114. if (!is_array($this->_aggregatedColumns)) {
  115. $this->_aggregatedColumns = [];
  116. }
  117. if ($column->hasTotal()) {
  118. $this->_aggregatedColumns[$column->getId()] = "{$column->getTotal()}({$column->getIndex()})";
  119. }
  120. }
  121. }
  122. return $this->_aggregatedColumns;
  123. }
  124. /**
  125. * Add column to grid
  126. * Overridden to add support for visibility_filter column option
  127. * It stands for conditional visibility of the column depending on filter field values
  128. * Value of visibility_filter supports (filter_field_name => filter_field_value) pairs
  129. *
  130. * @param string $columnId
  131. * @param array $column
  132. * @return $this
  133. */
  134. public function addColumn($columnId, $column)
  135. {
  136. if (is_array($column) && array_key_exists('visibility_filter', $column)) {
  137. $filterData = $this->getFilterData();
  138. $visibilityFilter = $column['visibility_filter'];
  139. if (!is_array($visibilityFilter)) {
  140. $visibilityFilter = [$visibilityFilter];
  141. }
  142. foreach ($visibilityFilter as $k => $v) {
  143. if (is_int($k)) {
  144. $filterFieldId = $v;
  145. $filterFieldValue = true;
  146. } else {
  147. $filterFieldId = $k;
  148. $filterFieldValue = $v;
  149. }
  150. if (!$filterData->hasData($filterFieldId) || $filterData->getData($filterFieldId) != $filterFieldValue
  151. ) {
  152. return $this; // don't add column
  153. }
  154. }
  155. }
  156. return parent::addColumn($columnId, $column);
  157. }
  158. /**
  159. * Get allowed store ids array intersected with selected scope in store switcher
  160. *
  161. * @return array
  162. */
  163. protected function _getStoreIds()
  164. {
  165. $storeIds = $this->getFilteredStores();
  166. // By default storeIds array contains only allowed stores
  167. $allowedStoreIds = array_keys($this->_storeManager->getStores());
  168. // And then array_intersect with post data for prevent unauthorized stores reports
  169. $storeIds = array_intersect($allowedStoreIds, $storeIds);
  170. // If selected all websites or unauthorized stores use only allowed
  171. if (empty($storeIds)) {
  172. $storeIds = $allowedStoreIds;
  173. }
  174. // reset array keys
  175. $storeIds = array_values($storeIds);
  176. return $storeIds;
  177. }
  178. /**
  179. * Apply sorting and filtering to collection
  180. *
  181. * @return $this|\Magento\Backend\Block\Widget\Grid
  182. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  183. * @SuppressWarnings(PHPMD.NPathComplexity)
  184. */
  185. protected function _prepareCollection()
  186. {
  187. $filterData = $this->getFilterData();
  188. if ($filterData->getData('from') == null || $filterData->getData('to') == null) {
  189. $this->setCountTotals(false);
  190. $this->setCountSubTotals(false);
  191. return parent::_prepareCollection();
  192. }
  193. $storeIds = $this->_getStoreIds();
  194. $orderStatuses = $filterData->getData('order_statuses');
  195. if (is_array($orderStatuses)) {
  196. if (count($orderStatuses) == 1 && strpos($orderStatuses[0], ',') !== false) {
  197. $filterData->setData('order_statuses', explode(',', $orderStatuses[0]));
  198. }
  199. }
  200. $resourceCollection = $this->_resourceFactory->create(
  201. $this->getResourceCollectionName()
  202. )->setPeriod(
  203. $filterData->getData('period_type')
  204. )->setDateRange(
  205. $filterData->getData('from', null),
  206. $filterData->getData('to', null)
  207. )->addStoreFilter(
  208. $storeIds
  209. )->setAggregatedColumns(
  210. $this->_getAggregatedColumns()
  211. );
  212. $this->_addOrderStatusFilter($resourceCollection, $filterData);
  213. $this->_addCustomFilter($resourceCollection, $filterData);
  214. if ($this->_isExport) {
  215. $this->setCollection($resourceCollection);
  216. return $this;
  217. }
  218. if ($filterData->getData('show_empty_rows', false)) {
  219. $this->_reportsData->prepareIntervalsCollection(
  220. $this->getCollection(),
  221. $filterData->getData('from', null),
  222. $filterData->getData('to', null),
  223. $filterData->getData('period_type')
  224. );
  225. }
  226. if ($this->getCountSubTotals()) {
  227. $this->getSubTotals();
  228. }
  229. if ($this->getCountTotals()) {
  230. $totalsCollection = $this->_resourceFactory->create(
  231. $this->getResourceCollectionName()
  232. )->setPeriod(
  233. $filterData->getData('period_type')
  234. )->setDateRange(
  235. $filterData->getData('from', null),
  236. $filterData->getData('to', null)
  237. )->addStoreFilter(
  238. $storeIds
  239. )->setAggregatedColumns(
  240. $this->_getAggregatedColumns()
  241. )->isTotals(
  242. true
  243. );
  244. $this->_addOrderStatusFilter($totalsCollection, $filterData);
  245. $this->_addCustomFilter($totalsCollection, $filterData);
  246. foreach ($totalsCollection as $item) {
  247. $this->setTotals($item);
  248. break;
  249. }
  250. }
  251. $this->getCollection()->setColumnGroupBy($this->_columnGroupBy);
  252. $this->getCollection()->setResourceCollection($resourceCollection);
  253. return parent::_prepareCollection();
  254. }
  255. /**
  256. * Return count totals
  257. *
  258. * @return array
  259. */
  260. public function getCountTotals()
  261. {
  262. if (!$this->getTotals()) {
  263. $filterData = $this->getFilterData();
  264. $totalsCollection = $this->_resourceFactory->create(
  265. $this->getResourceCollectionName()
  266. )->setPeriod(
  267. $filterData->getData('period_type')
  268. )->setDateRange(
  269. $filterData->getData('from', null),
  270. $filterData->getData('to', null)
  271. )->addStoreFilter(
  272. $this->_getStoreIds()
  273. )->setAggregatedColumns(
  274. $this->_getAggregatedColumns()
  275. )->isTotals(
  276. true
  277. );
  278. $this->_addOrderStatusFilter($totalsCollection, $filterData);
  279. $this->_addCustomFilter($totalsCollection, $filterData);
  280. if ($totalsCollection->load()->getSize() < 1 || !$filterData->getData('from')) {
  281. $this->setTotals(new \Magento\Framework\DataObject());
  282. $this->setCountTotals(false);
  283. } else {
  284. foreach ($totalsCollection->getItems() as $item) {
  285. $this->setTotals($item);
  286. break;
  287. }
  288. }
  289. }
  290. return parent::getCountTotals();
  291. }
  292. /**
  293. * Retrieve subtotal items
  294. *
  295. * @return array
  296. */
  297. public function getSubTotals()
  298. {
  299. $filterData = $this->getFilterData();
  300. $subTotalsCollection = $this->_resourceFactory->create(
  301. $this->getResourceCollectionName()
  302. )->setPeriod(
  303. $filterData->getData('period_type')
  304. )->setDateRange(
  305. $filterData->getData('from', null),
  306. $filterData->getData('to', null)
  307. )->addStoreFilter(
  308. $this->_getStoreIds()
  309. )->setAggregatedColumns(
  310. $this->_getAggregatedColumns()
  311. )->setIsSubTotals(
  312. true
  313. );
  314. $this->_addOrderStatusFilter($subTotalsCollection, $filterData);
  315. $this->_addCustomFilter($subTotalsCollection, $filterData);
  316. $this->setSubTotals($subTotalsCollection->getItems());
  317. return parent::getSubTotals();
  318. }
  319. /**
  320. * StoreIds setter
  321. *
  322. * @param array $storeIds
  323. * @return $this
  324. * @codeCoverageIgnore
  325. */
  326. public function setStoreIds($storeIds)
  327. {
  328. $this->_storeIds = $storeIds;
  329. return $this;
  330. }
  331. /**
  332. * Return current currency code
  333. *
  334. * @return string|\Magento\Directory\Model\Currency $currencyCode
  335. */
  336. public function getCurrentCurrencyCode()
  337. {
  338. if ($this->_currentCurrencyCode === null) {
  339. $this->_currentCurrencyCode = count($this->_storeIds) > 0
  340. ? $this->_storeManager->getStore(array_shift($this->_storeIds))->getCurrentCurrencyCode()
  341. : $this->_storeManager->getStore()->getBaseCurrencyCode();
  342. }
  343. return $this->_currentCurrencyCode;
  344. }
  345. /**
  346. * Get currency rate (base to given currency)
  347. *
  348. * @param string|\Magento\Directory\Model\Currency $toCurrency
  349. * @return float
  350. */
  351. public function getRate($toCurrency)
  352. {
  353. return $this->_storeManager->getStore()->getBaseCurrency()->getRate($toCurrency);
  354. }
  355. /**
  356. * Add order status filter
  357. *
  358. * @param \Magento\Reports\Model\ResourceModel\Report\Collection\AbstractCollection $collection
  359. * @param \Magento\Framework\DataObject $filterData
  360. * @return $this
  361. */
  362. protected function _addOrderStatusFilter($collection, $filterData)
  363. {
  364. $collection->addOrderStatusFilter($filterData->getData('order_statuses'));
  365. return $this;
  366. }
  367. /**
  368. * Adds custom filter to resource collection
  369. *
  370. * Can be overridden in child classes if custom filter needed
  371. *
  372. * @param \Magento\Reports\Model\ResourceModel\Report\Collection\AbstractCollection $collection
  373. * @param \Magento\Framework\DataObject $filterData
  374. * @return $this
  375. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  376. * @codeCoverageIgnore
  377. */
  378. protected function _addCustomFilter($collection, $filterData)
  379. {
  380. return $this;
  381. }
  382. /**
  383. * Return stores by website, group and store id
  384. *
  385. * @return array
  386. * @throws \Magento\Framework\Exception\LocalizedException
  387. */
  388. private function getFilteredStores(): array
  389. {
  390. $storeIds = [];
  391. $filterData = $this->getFilterData();
  392. if ($filterData) {
  393. if ($filterData->getWebsite()) {
  394. $storeIds = array_keys(
  395. $this->_storeManager->getWebsite($filterData->getWebsite())->getStores()
  396. );
  397. }
  398. if ($filterData->getGroup()) {
  399. $storeIds = array_keys(
  400. $this->_storeManager->getGroup($filterData->getGroup())->getStores()
  401. );
  402. }
  403. if ($filterData->getData('store_ids')) {
  404. $storeIds = explode(',', $filterData->getData('store_ids'));
  405. }
  406. }
  407. return is_array($storeIds) ? $storeIds : [];
  408. }
  409. }