AbstractTotals.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Backend\Model\Widget\Grid;
  7. /**
  8. * @api
  9. * @since 100.0.2
  10. */
  11. abstract class AbstractTotals implements \Magento\Backend\Model\Widget\Grid\TotalsInterface
  12. {
  13. /**
  14. * List of columns should be proceed with expression
  15. * 'key' => column index
  16. * 'value' => column expression
  17. *
  18. * @var array
  19. */
  20. protected $_columns = [];
  21. /**
  22. * Array of totals based on columns index
  23. * 'key' => column index
  24. * 'value' => counted total
  25. *
  26. * @var array
  27. */
  28. protected $_totals = [];
  29. /**
  30. * Factory model
  31. *
  32. * @var \Magento\Framework\DataObject\Factory
  33. */
  34. protected $_factory;
  35. /**
  36. * Parser for expressions like operand operation operand
  37. *
  38. * @var \Magento\Backend\Model\Widget\Grid\Parser
  39. */
  40. protected $_parser;
  41. /**
  42. * @param \Magento\Framework\DataObject\Factory $factory
  43. * @param \Magento\Backend\Model\Widget\Grid\Parser $parser
  44. */
  45. public function __construct(
  46. \Magento\Framework\DataObject\Factory $factory,
  47. \Magento\Backend\Model\Widget\Grid\Parser $parser
  48. ) {
  49. $this->_factory = $factory;
  50. $this->_parser = $parser;
  51. }
  52. /**
  53. * Count collection column sum based on column index
  54. *
  55. * @param string $index
  56. * @param \Magento\Framework\Data\Collection $collection
  57. * @return float|int
  58. * @abstract
  59. */
  60. abstract protected function _countSum($index, $collection);
  61. /**
  62. * Count collection column average based on column index
  63. *
  64. * @param string $index
  65. * @param \Magento\Framework\Data\Collection $collection
  66. * @return float|int
  67. * @abstract
  68. */
  69. abstract protected function _countAverage($index, $collection);
  70. /**
  71. * Count collection column sum based on column index and expression
  72. *
  73. * @param string $index
  74. * @param string $expr
  75. * @param \Magento\Framework\Data\Collection $collection
  76. * @return float|int
  77. */
  78. protected function _count($index, $expr, $collection)
  79. {
  80. switch ($expr) {
  81. case 'sum':
  82. $result = $this->_countSum($index, $collection);
  83. break;
  84. case 'avg':
  85. $result = $this->_countAverage($index, $collection);
  86. break;
  87. default:
  88. $result = $this->_countExpr($expr, $collection);
  89. break;
  90. }
  91. $this->_totals[$index] = $result;
  92. return $result;
  93. }
  94. /**
  95. * Return counted expression accorded parsed string
  96. *
  97. * @param string $expr
  98. * @param \Magento\Framework\Data\Collection $collection
  99. * @return float|int
  100. */
  101. protected function _countExpr($expr, $collection)
  102. {
  103. $parsedExpression = $this->_parser->parseExpression($expr);
  104. $result = $tmpResult = 0;
  105. $firstOperand = $secondOperand = null;
  106. foreach ($parsedExpression as $operand) {
  107. if ($this->_parser->isOperation($operand)) {
  108. $this->_checkOperandsSet($firstOperand, $secondOperand, $tmpResult, $result);
  109. $result = $this->_operate($firstOperand, $secondOperand, $operand, $tmpResult, $result);
  110. $firstOperand = $secondOperand = null;
  111. } else {
  112. if (null === $firstOperand) {
  113. $firstOperand = $this->_checkOperand($operand, $collection);
  114. } elseif (null === $secondOperand) {
  115. $secondOperand = $this->_checkOperand($operand, $collection);
  116. }
  117. }
  118. }
  119. return $result;
  120. }
  121. /**
  122. * Check if operands in not null and set operands values if they are empty
  123. *
  124. * @param float|int &$firstOperand
  125. * @param float|int &$secondOperand
  126. * @param float|int &$tmpResult
  127. * @param float|int $result
  128. * @return void
  129. */
  130. protected function _checkOperandsSet(&$firstOperand, &$secondOperand, &$tmpResult, $result)
  131. {
  132. if (null === $firstOperand && null === $secondOperand) {
  133. $firstOperand = $tmpResult;
  134. $secondOperand = $result;
  135. } elseif (null !== $firstOperand && null === $secondOperand) {
  136. $secondOperand = $result;
  137. } elseif (null !== $firstOperand && null !== $secondOperand) {
  138. $tmpResult = $result;
  139. }
  140. }
  141. /**
  142. * Get result of operation
  143. *
  144. * @param float|int $firstOperand
  145. * @param float|int $secondOperand
  146. * @param string $operation
  147. * @return float|int
  148. */
  149. protected function _operate($firstOperand, $secondOperand, $operation)
  150. {
  151. $result = 0;
  152. switch ($operation) {
  153. case '+':
  154. $result = $firstOperand + $secondOperand;
  155. break;
  156. case '-':
  157. $result = $firstOperand - $secondOperand;
  158. break;
  159. case '*':
  160. $result = $firstOperand * $secondOperand;
  161. break;
  162. case '/':
  163. $result = $secondOperand ? $firstOperand / $secondOperand : $secondOperand;
  164. break;
  165. }
  166. return $result;
  167. }
  168. /**
  169. * Check operand is numeric or has already counted
  170. *
  171. * @param string $operand
  172. * @param \Magento\Framework\Data\Collection $collection
  173. * @return float|int
  174. */
  175. protected function _checkOperand($operand, $collection)
  176. {
  177. if (!is_numeric($operand)) {
  178. if (isset($this->_totals[$operand])) {
  179. $operand = $this->_totals[$operand];
  180. } else {
  181. $operand = $this->_count($operand, $this->_columns[$operand], $collection);
  182. }
  183. } else {
  184. $operand *= 1;
  185. }
  186. return $operand;
  187. }
  188. /**
  189. * Fill columns
  190. *
  191. * @param string $index
  192. * @param string $totalExpr
  193. * @return $this
  194. */
  195. public function setColumn($index, $totalExpr)
  196. {
  197. $this->_columns[$index] = $totalExpr;
  198. return $this;
  199. }
  200. /**
  201. * Return columns set
  202. *
  203. * @return array
  204. */
  205. public function getColumns()
  206. {
  207. return $this->_columns;
  208. }
  209. /**
  210. * Count totals for all columns set
  211. *
  212. * @param \Magento\Framework\Data\Collection $collection
  213. * @return \Magento\Framework\DataObject
  214. */
  215. public function countTotals($collection)
  216. {
  217. foreach ($this->_columns as $index => $expr) {
  218. $this->_count($index, $expr, $collection);
  219. }
  220. return $this->getTotals();
  221. }
  222. /**
  223. * Get totals as object
  224. *
  225. * @return \Magento\Framework\DataObject
  226. */
  227. public function getTotals()
  228. {
  229. return $this->_factory->create($this->_totals);
  230. }
  231. /**
  232. * Reset totals and columns set
  233. *
  234. * @param bool $isFullReset
  235. * @return void
  236. */
  237. public function reset($isFullReset = false)
  238. {
  239. if ($isFullReset) {
  240. $this->_columns = [];
  241. }
  242. $this->_totals = [];
  243. }
  244. }