PageRenderTime 110ms CodeModel.GetById 47ms RepoModel.GetById 1ms app.codeStats 0ms

/app/code/core/Mage/Reports/Model/Resource/Report/Abstract.php

https://bitbucket.org/dnejedly/eaparts
PHP | 462 lines | 264 code | 51 blank | 147 comment | 40 complexity | e2b116eb05df75b1e4105cc0270b931d MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Reports
  23. * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Abstract report aggregate resource model
  28. *
  29. * @category Mage
  30. * @package Mage_Reports
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. abstract class Mage_Reports_Model_Resource_Report_Abstract extends Mage_Core_Model_Resource_Db_Abstract
  34. {
  35. /**
  36. * Flag object
  37. *
  38. * @var Mage_Reports_Model_Flag
  39. */
  40. protected $_flag = null;
  41. /**
  42. * Retrive flag object
  43. *
  44. * @return Mage_Reports_Model_Flag
  45. */
  46. protected function _getFlag()
  47. {
  48. if ($this->_flag === null) {
  49. $this->_flag = Mage::getModel('reports/flag');
  50. }
  51. return $this->_flag;
  52. }
  53. /**
  54. * Saves flag
  55. *
  56. * @param string $code
  57. * @param mixed $value
  58. * @return Mage_Reports_Model_Resource_Report_Abstract
  59. */
  60. protected function _setFlagData($code, $value = null)
  61. {
  62. $this->_getFlag()
  63. ->setReportFlagCode($code)
  64. ->unsetData()
  65. ->loadSelf();
  66. if ($value !== null) {
  67. $this->_getFlag()->setFlagData($value);
  68. }
  69. $time = Varien_Date::toTimestamp(true);
  70. // touch last_update
  71. $this->_getFlag()->setLastUpdate($this->formatDate($time));
  72. $this->_getFlag()->save();
  73. return $this;
  74. }
  75. /**
  76. * Retrieve flag data
  77. *
  78. * @param string $code
  79. * @return mixed
  80. */
  81. protected function _getFlagData($code)
  82. {
  83. $this->_getFlag()
  84. ->setReportFlagCode($code)
  85. ->unsetData()
  86. ->loadSelf();
  87. return $this->_getFlag()->getFlagData();
  88. }
  89. /**
  90. * Trancate table
  91. *
  92. * @param string $table
  93. * @return Mage_Reports_Model_Resource_Report_Abstract
  94. */
  95. protected function _truncateTable($table)
  96. {
  97. if ($this->_getWriteAdapter()->getTransactionLevel() > 0) {
  98. $this->_getWriteAdapter()->delete($table);
  99. } else {
  100. $this->_getWriteAdapter()->truncateTable($table);
  101. }
  102. return $this;
  103. }
  104. /**
  105. * Clear report table by specified date range.
  106. * If specified source table parameters,
  107. * condition will be generated by source table subselect.
  108. *
  109. * @param string $table
  110. * @param string|null $from
  111. * @param string|null $to
  112. * @param Zend_Db_Select|string|null $subSelect
  113. * @param unknown_type $doNotUseTruncate
  114. * @return Mage_Reports_Model_Resource_Report_Abstract
  115. */
  116. protected function _clearTableByDateRange($table, $from = null, $to = null, $subSelect = null,
  117. $doNotUseTruncate = false)
  118. {
  119. if ($from === null && $to === null && !$doNotUseTruncate) {
  120. $this->_truncateTable($table);
  121. return $this;
  122. }
  123. if ($subSelect !== null) {
  124. $deleteCondition = $this->_makeConditionFromDateRangeSelect($subSelect, 'period');
  125. } else {
  126. $condition = array();
  127. if ($from !== null) {
  128. $condition[] = $this->_getWriteAdapter()->quoteInto('period >= ?', $from);
  129. }
  130. if ($to !== null) {
  131. $condition[] = $this->_getWriteAdapter()->quoteInto('period <= ?', $to);
  132. }
  133. $deleteCondition = implode(' AND ', $condition);
  134. }
  135. $this->_getWriteAdapter()->delete($table, $deleteCondition);
  136. return $this;
  137. }
  138. /**
  139. * Generate table date range select
  140. *
  141. * @param string $table
  142. * @param string $column
  143. * @param string $whereColumn
  144. * @param string|null $from
  145. * @param string|null $to
  146. * @param array $additionalWhere
  147. * @param unknown_type $alias
  148. * @return Varien_Db_Select
  149. */
  150. protected function _getTableDateRangeSelect($table, $column, $whereColumn, $from = null, $to = null,
  151. $additionalWhere = array(), $alias = 'date_range_table')
  152. {
  153. $adapter = $this->_getReadAdapter();
  154. $select = $adapter->select()
  155. ->from(
  156. array($alias => $table),
  157. $adapter->getDatePartSql(
  158. $this->getStoreTZOffsetQuery(array($alias => $table), $alias . '.' . $column, $from, $to)
  159. )
  160. )
  161. ->distinct(true);
  162. if ($from !== null) {
  163. $select->where($alias . '.' . $whereColumn . ' >= ?', $from);
  164. }
  165. if ($to !== null) {
  166. $select->where($alias . '.' . $whereColumn . ' <= ?', $to);
  167. }
  168. if (!empty($additionalWhere)) {
  169. foreach ($additionalWhere as $condition) {
  170. if (is_array($condition) && count($condition) == 2) {
  171. $condition = $adapter->quoteInto($condition[0], $condition[1]);
  172. } elseif (is_array($condition)) { // Invalid condition
  173. continue;
  174. }
  175. $condition = str_replace('{{table}}', $adapter->quoteIdentifier($alias), $condition);
  176. $select->where($condition);
  177. }
  178. }
  179. return $select;
  180. }
  181. /**
  182. * Make condition for using in where section
  183. * from select statement with single date column
  184. *
  185. * @result string|false
  186. *
  187. * @param Varien_Db_Select $select
  188. * @param string $periodColumn
  189. * @return unknown
  190. */
  191. protected function _makeConditionFromDateRangeSelect($select, $periodColumn)
  192. {
  193. static $selectResultCache = array();
  194. $cacheKey = (string)$select;
  195. if (!array_key_exists($cacheKey, $selectResultCache)) {
  196. try {
  197. $selectResult = array();
  198. $query = $this->_getReadAdapter()->query($select);
  199. while ($date = $query->fetchColumn()) {
  200. $selectResult[] = $date;
  201. }
  202. } catch (Exception $e) {
  203. $selectResult = false;
  204. }
  205. $selectResultCache[$cacheKey] = $selectResult;
  206. } else {
  207. $selectResult = $selectResultCache[$cacheKey];
  208. }
  209. if ($selectResult === false) {
  210. return false;
  211. }
  212. $whereCondition = array();
  213. $adapter = $this->_getReadAdapter();
  214. foreach ($selectResult as $date) {
  215. $date = substr($date, 0, 10); // to fix differences in oracle
  216. $whereCondition[] = $adapter->prepareSqlCondition($periodColumn, array('like' => $date));
  217. }
  218. $whereCondition = implode(' OR ', $whereCondition);
  219. if ($whereCondition == '') {
  220. $whereCondition = '1=0'; // FALSE condition!
  221. }
  222. return $whereCondition;
  223. }
  224. /**
  225. * Generate table date range select
  226. *
  227. * @param string $table
  228. * @param string $relatedTable
  229. * @param array $joinCondition
  230. * @param string $column
  231. * @param string $whereColumn
  232. * @param string|null $from
  233. * @param string|null $to
  234. * @param array $additionalWhere
  235. * @param unknown_type $alias
  236. * @param unknown_type $relatedAlias
  237. * @return Varien_Db_Select
  238. */
  239. protected function _getTableDateRangeRelatedSelect($table, $relatedTable, $joinCondition, $column, $whereColumn,
  240. $from = null, $to = null, $additionalWhere = array(), $alias = 'date_range_table',
  241. $relatedAlias = 'related_date_range_table')
  242. {
  243. $adapter = $this->_getReadAdapter();
  244. $joinConditionSql = array();
  245. foreach ($joinCondition as $fkField => $pkField) {
  246. $joinConditionSql[] = sprintf('%s.%s = %s.%s', $alias, $fkField, $relatedAlias, $pkField);
  247. }
  248. $select = $adapter->select()
  249. ->from(
  250. array($alias => $table),
  251. $adapter->getDatePartSql(
  252. $adapter->quoteIdentifier($alias . '.' . $column)
  253. )
  254. )
  255. ->joinInner(
  256. array($relatedAlias => $relatedTable),
  257. implode(' AND ', $joinConditionSql),
  258. array()
  259. )
  260. ->distinct(true);
  261. if ($from !== null) {
  262. $select->where($relatedAlias . '.' . $whereColumn . ' >= ?', $from);
  263. }
  264. if ($to !== null) {
  265. $select->where($relatedAlias . '.' . $whereColumn . ' <= ?', $to);
  266. }
  267. if (!empty($additionalWhere)) {
  268. foreach ($additionalWhere as $condition) {
  269. if (is_array($condition) && count($condition) == 2) {
  270. $condition = $adapter->quoteInto($condition[0], $condition[1]);
  271. } elseif (is_array($condition)) { // Invalid condition
  272. continue;
  273. }
  274. $condition = str_replace(
  275. array('{{table}}', '{{related_table}}'),
  276. array(
  277. $adapter->quoteIdentifier($alias),
  278. $adapter->quoteIdentifier($relatedAlias)
  279. ),
  280. $condition
  281. );
  282. $select->where($condition);
  283. }
  284. }
  285. return $select;
  286. }
  287. /**
  288. * Check range dates and transforms it to strings
  289. *
  290. * @param mixed $from
  291. * @param mixed $to
  292. * @return Mage_Reports_Model_Resource_Report_Abstract
  293. */
  294. protected function _checkDates(&$from, &$to)
  295. {
  296. if ($from !== null) {
  297. $from = $this->formatDate($from);
  298. }
  299. if ($to !== null) {
  300. $to = $this->formatDate($to);
  301. }
  302. return $this;
  303. }
  304. /**
  305. * Retrieve query for attribute with timezone conversion
  306. *
  307. * @param string|array $table
  308. * @param string $column
  309. * @param mixed $from
  310. * @param mixed $to
  311. * @param int|string|Mage_Core_Model_Store|null $store
  312. * @return string
  313. */
  314. public function getStoreTZOffsetQuery($table, $column, $from = null, $to = null, $store = null)
  315. {
  316. $column = $this->_getWriteAdapter()->quoteIdentifier($column);
  317. if (is_null($from)) {
  318. $selectOldest = $this->_getWriteAdapter()->select()
  319. ->from(
  320. $table,
  321. array("MIN($column)")
  322. );
  323. $from = $this->_getWriteAdapter()->fetchOne($selectOldest);
  324. }
  325. $periods = $this->_getTZOffsetTransitions(
  326. Mage::app()->getLocale()->storeDate($store)->toString(Zend_Date::TIMEZONE_NAME), $from, $to
  327. );
  328. if (empty($periods)) {
  329. return $column;
  330. }
  331. $query = "";
  332. $periodsCount = count($periods);
  333. $i = 0;
  334. foreach ($periods as $offset => $timestamps) {
  335. $subParts = array();
  336. foreach ($timestamps as $ts) {
  337. $subParts[] = "($column between {$ts['from']} and {$ts['to']})";
  338. }
  339. $then = $this->_getWriteAdapter()
  340. ->getDateAddSql($column, $offset, Varien_Db_Adapter_Interface::INTERVAL_SECOND);
  341. $query .= (++$i == $periodsCount) ? $then : "CASE WHEN " . join(" OR ", $subParts) . " THEN $then ELSE ";
  342. }
  343. return $query . str_repeat('END ', count($periods) - 1);
  344. }
  345. /**
  346. * Retrieve transitions for offsets of given timezone
  347. *
  348. * @param string $timezone
  349. * @param mixed $from
  350. * @param mixed $to
  351. * @return array
  352. */
  353. protected function _getTZOffsetTransitions($timezone, $from = null, $to = null)
  354. {
  355. $tzTransitions = array();
  356. try {
  357. if (!empty($from)) {
  358. $from = new Zend_Date($from, Varien_Date::DATETIME_INTERNAL_FORMAT);
  359. $from = $from->getTimestamp();
  360. }
  361. $to = new Zend_Date($to, Varien_Date::DATETIME_INTERNAL_FORMAT);
  362. $nextPeriod = $this->_getWriteAdapter()->formatDate($to->toString(Varien_Date::DATETIME_INTERNAL_FORMAT));
  363. $to = $to->getTimestamp();
  364. $dtz = new DateTimeZone($timezone);
  365. $transitions = $dtz->getTransitions();
  366. $dateTimeObject = new Zend_Date('c');
  367. for ($i = count($transitions) - 1; $i >= 0; $i--) {
  368. $tr = $transitions[$i];
  369. if ($tr['ts'] > $to) {
  370. continue;
  371. }
  372. $dateTimeObject->set($tr['time']);
  373. $tr['time'] = $this->_getWriteAdapter()
  374. ->formatDate($dateTimeObject->toString(Varien_Date::DATETIME_INTERNAL_FORMAT));
  375. $tzTransitions[$tr['offset']][] = array('from' => $tr['time'], 'to' => $nextPeriod);
  376. if (!empty($from) && $tr['ts'] < $from) {
  377. break;
  378. }
  379. $nextPeriod = $tr['time'];
  380. }
  381. } catch (Exception $e) {
  382. Mage::logException($e);
  383. }
  384. return $tzTransitions;
  385. }
  386. /**
  387. * Retrieve store timezone offset from UTC in the form acceptable by SQL's CONVERT_TZ()
  388. *
  389. * @param unknown_type $store
  390. * @return string
  391. */
  392. protected function _getStoreTimezoneUtcOffset($store = null)
  393. {
  394. return Mage::app()->getLocale()->storeDate($store)->toString(Zend_Date::GMT_DIFF_SEP);
  395. }
  396. /**
  397. * Retrieve date in UTC timezone
  398. *
  399. * @param unknown_type $date
  400. * @return Zend_Date|null
  401. */
  402. protected function _dateToUtc($date)
  403. {
  404. if ($date === null) {
  405. return null;
  406. }
  407. $dateUtc = new Zend_Date($date);
  408. $dateUtc->setTimezone('Etc/UTC');
  409. return $dateUtc;
  410. }
  411. }