statsController.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. /**
  3. * Controller to handle application statistics.
  4. */
  5. class FreshRSS_stats_Controller extends FreshRSS_ActionController {
  6. /**
  7. * This action is called before every other action in that class. It is
  8. * the common boiler plate for every action. It is triggered by the
  9. * underlying framework.
  10. */
  11. public function firstAction() {
  12. if (!FreshRSS_Auth::hasAccess()) {
  13. Minz_Error::error(403);
  14. }
  15. $this->_csp([
  16. 'default-src' => "'self'",
  17. 'style-src' => "'self' 'unsafe-inline'",
  18. ]);
  19. FreshRSS_View::prependTitle(_t('admin.stats.title') . ' · ');
  20. }
  21. private function convertToSeries($data) {
  22. $series = array();
  23. foreach ($data as $key => $value) {
  24. $series[] = array($key, $value);
  25. }
  26. return $series;
  27. }
  28. private function convertToPieSeries($data) {
  29. $series = array();
  30. foreach ($data as $value) {
  31. $value['data'] = array(array(0, (int) $value['data']));
  32. $series[] = $value;
  33. }
  34. return $series;
  35. }
  36. /**
  37. * This action handles the statistic main page.
  38. *
  39. * It displays the statistic main page.
  40. * The values computed to display the page are:
  41. * - repartition of read/unread/favorite/not favorite (repartition)
  42. * - number of article per day (entryCount)
  43. * - number of feed by category (feedByCategory)
  44. * - number of article by category (entryByCategory)
  45. * - list of most prolific feed (topFeed)
  46. */
  47. public function indexAction() {
  48. $statsDAO = FreshRSS_Factory::createStatsDAO();
  49. FreshRSS_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
  50. $this->view->repartition = $statsDAO->calculateEntryRepartition();
  51. $entryCount = $statsDAO->calculateEntryCount();
  52. $this->view->entryCount = $entryCount;
  53. $this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2);
  54. $feedByCategory_calculated = $statsDAO->calculateFeedByCategory();
  55. $feedByCategory = [];
  56. for ($i = 0; $i < count($feedByCategory_calculated); $i++) {
  57. $feedByCategory['label'][$i] = $feedByCategory_calculated[$i]['label'];
  58. $feedByCategory['data'][$i] = $feedByCategory_calculated[$i]['data'];
  59. }
  60. $this->view->feedByCategory = $feedByCategory;
  61. $entryByCategory_calculated = $statsDAO->calculateEntryByCategory();
  62. $entryByCategory = [];
  63. for ($i = 0; $i < count($entryByCategory_calculated); $i++) {
  64. $entryByCategory['label'][$i] = $entryByCategory_calculated[$i]['label'];
  65. $entryByCategory['data'][$i] = $entryByCategory_calculated[$i]['data'];
  66. }
  67. $this->view->entryByCategory = $entryByCategory;
  68. $this->view->topFeed = $statsDAO->calculateTopFeed();
  69. $last30DaysLabels = [];
  70. for ($i = 0; $i < 30; $i++) {
  71. $last30DaysLabels[$i] = date('d.m.Y', strtotime((-30 + $i) . ' days'));
  72. }
  73. $this->view->last30DaysLabels = $last30DaysLabels;
  74. }
  75. /**
  76. * This action handles the idle feed statistic page.
  77. *
  78. * It displays the list of idle feed for different period. The supported
  79. * periods are:
  80. * - last 5 years
  81. * - last 3 years
  82. * - last 2 years
  83. * - last year
  84. * - last 6 months
  85. * - last 3 months
  86. * - last month
  87. * - last week
  88. */
  89. public function idleAction() {
  90. $statsDAO = FreshRSS_Factory::createStatsDAO();
  91. $feeds = $statsDAO->calculateFeedLastDate();
  92. $idleFeeds = array(
  93. 'last_5_year' => array(),
  94. 'last_3_year' => array(),
  95. 'last_2_year' => array(),
  96. 'last_year' => array(),
  97. 'last_6_month' => array(),
  98. 'last_3_month' => array(),
  99. 'last_month' => array(),
  100. 'last_week' => array(),
  101. );
  102. $now = new \DateTime();
  103. $feedDate = clone $now;
  104. $lastWeek = clone $now;
  105. $lastWeek->modify('-1 week');
  106. $lastMonth = clone $now;
  107. $lastMonth->modify('-1 month');
  108. $last3Month = clone $now;
  109. $last3Month->modify('-3 month');
  110. $last6Month = clone $now;
  111. $last6Month->modify('-6 month');
  112. $lastYear = clone $now;
  113. $lastYear->modify('-1 year');
  114. $last2Year = clone $now;
  115. $last2Year->modify('-2 year');
  116. $last3Year = clone $now;
  117. $last3Year->modify('-3 year');
  118. $last5Year = clone $now;
  119. $last5Year->modify('-5 year');
  120. foreach ($feeds as $feed) {
  121. $feedDate->setTimestamp($feed['last_date']);
  122. if ($feedDate >= $lastWeek) {
  123. continue;
  124. }
  125. if ($feedDate < $last5Year) {
  126. $idleFeeds['last_5_year'][] = $feed;
  127. } elseif ($feedDate < $last3Year) {
  128. $idleFeeds['last_3_year'][] = $feed;
  129. } elseif ($feedDate < $last2Year) {
  130. $idleFeeds['last_2_year'][] = $feed;
  131. } elseif ($feedDate < $lastYear) {
  132. $idleFeeds['last_year'][] = $feed;
  133. } elseif ($feedDate < $last6Month) {
  134. $idleFeeds['last_6_month'][] = $feed;
  135. } elseif ($feedDate < $last3Month) {
  136. $idleFeeds['last_3_month'][] = $feed;
  137. } elseif ($feedDate < $lastMonth) {
  138. $idleFeeds['last_month'][] = $feed;
  139. } elseif ($feedDate < $lastWeek) {
  140. $idleFeeds['last_week'][] = $feed;
  141. }
  142. }
  143. $this->view->idleFeeds = $idleFeeds;
  144. }
  145. /**
  146. * This action handles the article repartition statistic page.
  147. *
  148. * It displays the number of article and the average of article for the
  149. * following periods:
  150. * - hour of the day
  151. * - day of the week
  152. * - month
  153. *
  154. * @todo verify that the metrics used here make some sense. Especially
  155. * for the average.
  156. */
  157. public function repartitionAction() {
  158. $statsDAO = FreshRSS_Factory::createStatsDAO();
  159. $categoryDAO = FreshRSS_Factory::createCategoryDao();
  160. $feedDAO = FreshRSS_Factory::createFeedDao();
  161. FreshRSS_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
  162. $id = Minz_Request::param('id', null);
  163. $this->view->categories = $categoryDAO->listCategories();
  164. $this->view->feed = $feedDAO->searchById($id);
  165. $this->view->days = $statsDAO->getDays();
  166. $this->view->months = $statsDAO->getMonths();
  167. $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id);
  168. $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
  169. $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id);
  170. $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
  171. $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id);
  172. $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
  173. $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id);
  174. $hours24Labels = [];
  175. for ($i = 0; $i < 24; $i++) {
  176. $hours24Labels[$i] = $i . ':xx';
  177. }
  178. $this->view->hours24Labels = $hours24Labels;
  179. }
  180. }