StatsDAOPGSQL.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
  3. /**
  4. * Calculates entry repartition for the selection.
  5. * The repartition includes:
  6. * - total entries
  7. * - read entries
  8. * - unread entries
  9. * - favorite entries
  10. *
  11. * @param null|integer $feed feed id
  12. * @param boolean $only_main
  13. * @return array
  14. */
  15. public function calculateEntryRepartitionPerFeed($feed = null, $only_main = false) {
  16. $filter = '';
  17. if ($only_main) {
  18. $filter .= 'AND f.priority = 10';
  19. }
  20. if (!is_null($feed)) {
  21. $filter .= "AND e.id_feed = {$feed}";
  22. }
  23. $sql = <<<SQL
  24. SELECT COUNT(1) AS total,
  25. COUNT(1) - SUM(case when e.is_read then 1 else 0 end) AS unread,
  26. SUM(case when e.is_read then 1 else 0 end) AS read,
  27. SUM(case when e.is_favorite then 1 else 0 end) AS favorite
  28. FROM "{$this->prefix}entry" AS e
  29. , "{$this->prefix}feed" AS f
  30. WHERE e.id_feed = f.id
  31. {$filter}
  32. SQL;
  33. $stm = $this->bd->prepare($sql);
  34. $stm->execute();
  35. $res = $stm->fetchAll(PDO::FETCH_ASSOC);
  36. return $res[0];
  37. }
  38. /**
  39. * Calculates entry count per day on a 30 days period.
  40. * Returns the result as a JSON string.
  41. *
  42. * @return string
  43. */
  44. public function calculateEntryCount() {
  45. $count = $this->initEntryCountArray();
  46. $period = self::ENTRY_COUNT_PERIOD;
  47. // Get stats per day for the last 30 days
  48. $sql = <<<SQL
  49. SELECT to_timestamp(e.date) - NOW() AS day,
  50. COUNT(1) AS count
  51. FROM "{$this->prefix}entry" AS e
  52. WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY'
  53. GROUP BY day
  54. ORDER BY day ASC
  55. SQL;
  56. $stm = $this->bd->prepare($sql);
  57. $stm->execute();
  58. $res = $stm->fetchAll(PDO::FETCH_ASSOC);
  59. foreach ($res as $value) {
  60. $count[$value['day']] = (int) $value['count'];
  61. }
  62. return $this->convertToSerie($count);
  63. }
  64. /**
  65. * Calculates entry average per day on a 30 days period.
  66. *
  67. * @return integer
  68. */
  69. public function calculateEntryAverage() {
  70. $period = self::ENTRY_COUNT_PERIOD;
  71. // Get stats per day for the last 30 days
  72. $sql = <<<SQL
  73. SELECT COUNT(1) / {$period} AS average
  74. FROM "{$this->prefix}entry" AS e
  75. WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY'
  76. SQL;
  77. $stm = $this->bd->prepare($sql);
  78. $stm->execute();
  79. $res = $stm->fetch(PDO::FETCH_NAMED);
  80. return round($res['average'], 2);
  81. }
  82. /**
  83. * Calculates the number of article per hour of the day per feed
  84. *
  85. * @param integer $feed id
  86. * @return string
  87. */
  88. public function calculateEntryRepartitionPerFeedPerHour($feed = null) {
  89. return $this->calculateEntryRepartitionPerFeedPerPeriod('hour', $feed);
  90. }
  91. /**
  92. * Calculates the number of article per day of week per feed
  93. *
  94. * @param integer $feed id
  95. * @return string
  96. */
  97. public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) {
  98. return $this->calculateEntryRepartitionPerFeedPerPeriod('day', $feed);
  99. }
  100. /**
  101. * Calculates the number of article per month per feed
  102. *
  103. * @param integer $feed
  104. * @return string
  105. */
  106. public function calculateEntryRepartitionPerFeedPerMonth($feed = null) {
  107. return $this->calculateEntryRepartitionPerFeedPerPeriod('month', $feed);
  108. }
  109. /**
  110. * Calculates the number of article per period per feed
  111. *
  112. * @param string $period format string to use for grouping
  113. * @param integer $feed id
  114. * @return string
  115. */
  116. protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) {
  117. $restrict = '';
  118. if ($feed) {
  119. $restrict = "WHERE e.id_feed = {$feed}";
  120. }
  121. $sql = <<<SQL
  122. SELECT extract( {$period} from to_timestamp(e.date)) AS period
  123. , COUNT(1) AS count
  124. FROM "{$this->prefix}entry" AS e
  125. {$restrict}
  126. GROUP BY period
  127. ORDER BY period ASC
  128. SQL;
  129. $stm = $this->bd->prepare($sql);
  130. $stm->execute();
  131. $res = $stm->fetchAll(PDO::FETCH_NAMED);
  132. foreach ($res as $value) {
  133. $repartition[(int) $value['period']] = (int) $value['count'];
  134. }
  135. return $this->convertToSerie($repartition);
  136. }
  137. /**
  138. * Calculates the average number of article per feed
  139. *
  140. * @param float $period number used to divide the number of day in the period
  141. * @param integer $feed id
  142. * @return integer
  143. */
  144. protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) {
  145. $restrict = '';
  146. if ($feed) {
  147. $restrict = "WHERE e.id_feed = {$feed}";
  148. }
  149. $sql = <<<SQL
  150. SELECT COUNT(1) AS count
  151. , MIN(date) AS date_min
  152. , MAX(date) AS date_max
  153. FROM "{$this->prefix}entry" AS e
  154. {$restrict}
  155. SQL;
  156. $stm = $this->bd->prepare($sql);
  157. $stm->execute();
  158. $res = $stm->fetch(PDO::FETCH_NAMED);
  159. $date_min = new \DateTime();
  160. $date_min->setTimestamp($res['date_min']);
  161. $date_max = new \DateTime();
  162. $date_max->setTimestamp($res['date_max']);
  163. $interval = $date_max->diff($date_min, true);
  164. $interval_in_days = $interval->format('%a');
  165. if ($interval_in_days <= 0) {
  166. // Surely only one article.
  167. // We will return count / (period/period) == count.
  168. $interval_in_days = $period;
  169. }
  170. return $res['count'] / ($interval_in_days / $period);
  171. }
  172. }