From 181fcd98893f65a2c5159158fbfc022b4661ea13 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 13 Jun 2014 01:00:27 -0400 Subject: Refactor statistics I made a new controller to handle statistics. The old statistics have been moved in that controller and a new action has been added to display idle feeds. I also added a menu in the left panel to navigate between the statistics pages. See #90 --- app/Models/StatsDAO.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 60cec7847..f9f4740fd 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -180,6 +180,26 @@ SQL; $stm->execute(); return $stm->fetchAll(PDO::FETCH_ASSOC); } + + /** + * Calculates the last publication date for each feed + * + * @return array + */ + public function calculateFeedLastDate() { + $sql = <<prefix}feed AS f, +{$this->prefix}entry AS e +WHERE f.id = e.id_feed +GROUP BY f.id +ORDER BY name +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + return $stm->fetchAll(PDO::FETCH_ASSOC); + } private function convertToSerie($data) { $serie = array(); -- cgit v1.2.3 From 60fe99344e1d87850f1a44791c1f0a675d13c756 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 15 Jun 2014 12:13:33 -0400 Subject: Refactor and formatting --- app/Controllers/statsController.php | 100 ++++++++++++++-------------- app/Models/StatsDAO.php | 24 +++---- app/i18n/en.php | 14 ++-- app/i18n/fr.php | 14 ++-- app/layout/aside_stats.phtml | 4 +- app/layout/header.phtml | 2 +- app/views/stats/idle.phtml | 24 +++---- app/views/stats/index.phtml | 127 ++++++++++++++++++++++++++++++++++++ app/views/stats/main.phtml | 127 ------------------------------------ 9 files changed, 216 insertions(+), 220 deletions(-) create mode 100644 app/views/stats/index.phtml delete mode 100644 app/views/stats/main.phtml (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index cbc67cac3..fb5609cb4 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -2,70 +2,66 @@ class FreshRSS_stats_Controller extends Minz_ActionController { - public function mainAction() { - $this->initAction(); - - $statsDAO = new FreshRSS_StatsDAO (); + public function indexAction() { + $statsDAO = new FreshRSS_StatsDAO (); Minz_View::appendScript (Minz_Url::display ('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); $this->view->count = ($statsDAO->calculateEntryCount()); $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); $this->view->topFeed = $statsDAO->calculateTopFeed(); - } - - public function idleAction() { - $this->initAction(); + } - $statsDAO = new FreshRSS_StatsDAO (); - $feeds = $statsDAO->calculateFeedLastDate(); - $idleFeeds = array(); - $now = new \DateTime(); - $feedDate = clone $now; - $lastWeek = clone $now; - $lastWeek->modify('-1 week'); - $lastMonth = clone $now; - $lastMonth->modify('-1 month'); - $last3Month = clone $now; - $last3Month->modify('-3 month'); - $last6Month = clone $now; - $last6Month->modify('-6 month'); - $lastYear = clone $now; - $lastYear->modify('-1 year'); + public function idleAction() { + $statsDAO = new FreshRSS_StatsDAO (); + $feeds = $statsDAO->calculateFeedLastDate(); + $idleFeeds = array(); + $now = new \DateTime(); + $feedDate = clone $now; + $lastWeek = clone $now; + $lastWeek->modify('-1 week'); + $lastMonth = clone $now; + $lastMonth->modify('-1 month'); + $last3Month = clone $now; + $last3Month->modify('-3 month'); + $last6Month = clone $now; + $last6Month->modify('-6 month'); + $lastYear = clone $now; + $lastYear->modify('-1 year'); - foreach ($feeds as $feed) { - $feedDate->setTimestamp($feed['last_date']); - if ($feedDate >= $lastWeek) { - continue; - } - if ($feedDate < $lastWeek) { - $idleFeeds['last_week'][] = $feed['name']; - } - if ($feedDate < $lastMonth) { - $idleFeeds['last_month'][] = $feed['name']; - } - if ($feedDate < $last3Month) { - $idleFeeds['last_3_month'][] = $feed['name']; - } - if ($feedDate < $last6Month) { - $idleFeeds['last_6_month'][] = $feed['name']; - } - if ($feedDate < $lastYear) { - $idleFeeds['last_year'][] = $feed['name']; - } - } + foreach ($feeds as $feed) { + $feedDate->setTimestamp($feed['last_date']); + if ($feedDate >= $lastWeek) { + continue; + } + if ($feedDate < $lastWeek) { + $idleFeeds['last_week'][] = $feed['name']; + } + if ($feedDate < $lastMonth) { + $idleFeeds['last_month'][] = $feed['name']; + } + if ($feedDate < $last3Month) { + $idleFeeds['last_3_month'][] = $feed['name']; + } + if ($feedDate < $last6Month) { + $idleFeeds['last_6_month'][] = $feed['name']; + } + if ($feedDate < $lastYear) { + $idleFeeds['last_year'][] = $feed['name']; + } + } - $this->view->idleFeeds = array_reverse($idleFeeds); - } + $this->view->idleFeeds = array_reverse($idleFeeds); + } - private function initAction() { + public function firstAction() { if (!$this->view->loginOk) { - Minz_Error::error( - 403, array('error' => array(Minz_Translate::t('access_denied'))) - ); - } + Minz_Error::error( + 403, array('error' => array(Minz_Translate::t('access_denied'))) + ); + } - Minz_View::prependTitle(Minz_Translate::t('stats') . ' · '); + Minz_View::prependTitle(Minz_Translate::t('stats') . ' · '); } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index f9f4740fd..eafe86407 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -180,14 +180,14 @@ SQL; $stm->execute(); return $stm->fetchAll(PDO::FETCH_ASSOC); } - - /** - * Calculates the last publication date for each feed - * - * @return array - */ - public function calculateFeedLastDate() { - $sql = <<prefix}feed AS f, @@ -196,10 +196,10 @@ WHERE f.id = e.id_feed GROUP BY f.id ORDER BY name SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - return $stm->fetchAll(PDO::FETCH_ASSOC); - } + $stm = $this->bd->prepare($sql); + $stm->execute(); + return $stm->fetchAll(PDO::FETCH_ASSOC); + } private function convertToSerie($data) { $serie = array(); diff --git a/app/i18n/en.php b/app/i18n/en.php index 8d5f305c0..19cf4a06d 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -46,14 +46,14 @@ return array ( 'no_query_filter' => 'No filter', 'about' => 'About', 'stats' => 'Statistics', - 'stats_idle' => 'Idle feeds', - 'stats_main' => 'Main statistics', + 'stats_idle' => 'Idle feeds', + 'stats_main' => 'Main statistics', - 'last_week' => 'Last week', - 'last_month' => 'Last month', - 'last_3_month' => 'Last three months', - 'last_6_month' => 'Last six months', - 'last_year' => 'Last year', + 'last_week' => 'Last week', + 'last_month' => 'Last month', + 'last_3_month' => 'Last three months', + 'last_6_month' => 'Last six months', + 'last_year' => 'Last year', 'your_rss_feeds' => 'Your RSS feeds', 'add_rss_feed' => 'Add a RSS feed', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 3441425df..54fe55ea0 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -46,14 +46,14 @@ return array ( 'no_query_filter' => 'Aucun filtre appliqué', 'about' => 'À propos', 'stats' => 'Statistiques', - 'stats_idle' => 'Flux inactifs', - 'stats_main' => 'Statistiques principales', + 'stats_idle' => 'Flux inactifs', + 'stats_main' => 'Statistiques principales', - 'last_week' => 'La dernière semaine', - 'last_month' => 'Le dernier mois', - 'last_3_month' => 'Les derniers trois mois', - 'last_6_month' => 'Les derniers six mois', - 'last_year' => 'La dernière année', + 'last_week' => 'La dernière semaine', + 'last_month' => 'Le dernier mois', + 'last_3_month' => 'Les derniers trois mois', + 'last_6_month' => 'Les derniers six mois', + 'last_year' => 'La dernière année', 'your_rss_feeds' => 'Vos flux RSS', 'add_rss_feed' => 'Ajouter un flux RSS', diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index bc1e85592..32a3f5dee 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -1,7 +1,7 @@ + diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml new file mode 100644 index 000000000..a48181fe4 --- /dev/null +++ b/app/views/stats/index.phtml @@ -0,0 +1,127 @@ +partial('aside_stats'); ?> + +
+ + +

+ +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
repartition['main_stream']['total']); ?>repartition['all_feeds']['total']); ?>
repartition['main_stream']['read']); ?>repartition['all_feeds']['read']); ?>
repartition['main_stream']['unread']); ?>repartition['all_feeds']['unread']); ?>
repartition['main_stream']['favorite']); ?>repartition['all_feeds']['favorite']); ?>
+
+ +
+

+
+
+ +
+

+
+
+
+ +
+

+
+
+
+ +
+

+ + + + + + + + + + topFeed as $feed): ?> + + + + + + + +
+
+
+ + diff --git a/app/views/stats/main.phtml b/app/views/stats/main.phtml deleted file mode 100644 index fe372e221..000000000 --- a/app/views/stats/main.phtml +++ /dev/null @@ -1,127 +0,0 @@ -partial('aside_stats'); ?> - -
- - -

- -
-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
repartition['main_stream']['total']); ?>repartition['all_feeds']['total']); ?>
repartition['main_stream']['read']); ?>repartition['all_feeds']['read']); ?>
repartition['main_stream']['unread']); ?>repartition['all_feeds']['unread']); ?>
repartition['main_stream']['favorite']); ?>repartition['all_feeds']['favorite']); ?>
-
- -
-

-
-
- -
-

-
-
-
- -
-

-
-
-
- -
-

- - - - - - - - - - topFeed as $feed): ?> - - - - - - - -
-
-
- - -- cgit v1.2.3 From 3bbd0e446f6a1a0c41a4db36d2841db36dc34004 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 6 Jul 2014 11:54:00 +0200 Subject: Prepare statistics for SQLite Temporarily disable 30-day statistics for SQLite https://github.com/marienfressinaud/FreshRSS/issues/100 https://github.com/marienfressinaud/FreshRSS/issues/90 --- app/Controllers/statsController.php | 4 ++-- app/Models/Factory.php | 10 ++++++++++ app/Models/StatsDAO.php | 4 ++-- app/Models/StatsDAOSQLite.php | 9 +++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 app/Models/StatsDAOSQLite.php (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index fb5609cb4..9009468bc 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -3,7 +3,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function indexAction() { - $statsDAO = new FreshRSS_StatsDAO (); + $statsDAO = FreshRSS_Factory::createStatsDAO(); Minz_View::appendScript (Minz_Url::display ('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); $this->view->count = ($statsDAO->calculateEntryCount()); @@ -13,7 +13,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { } public function idleAction() { - $statsDAO = new FreshRSS_StatsDAO (); + $statsDAO = FreshRSS_Factory::createStatsDAO(); $feeds = $statsDAO->calculateFeedLastDate(); $idleFeeds = array(); $now = new \DateTime(); diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 95d21a277..08569b2e2 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -19,4 +19,14 @@ class FreshRSS_Factory { return new FreshRSS_EntryDAO(); } } + + public static function createStatsDAO() { + $db = Minz_Configuration::dataBase(); + if ($db['type'] === 'sqlite') { + return new FreshRSS_StatsDAOSQLite(); + } else { + return new FreshRSS_StatsDAO(); + } + } + } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index eafe86407..62f238bd2 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -201,7 +201,7 @@ SQL; return $stm->fetchAll(PDO::FETCH_ASSOC); } - private function convertToSerie($data) { + protected function convertToSerie($data) { $serie = array(); foreach ($data as $key => $value) { @@ -211,7 +211,7 @@ SQL; return json_encode($serie); } - private function convertToPieSerie($data) { + protected function convertToPieSerie($data) { $serie = array(); foreach ($data as $value) { diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php new file mode 100644 index 000000000..c923e5fd0 --- /dev/null +++ b/app/Models/StatsDAOSQLite.php @@ -0,0 +1,9 @@ +convertToSerie(array()); //TODO: Implement 30-day statistics for SQLite + } + +} -- cgit v1.2.3 From 68c0a827d221eeb398774d558f3d23b6e1c9e76c Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 18 Jul 2014 20:35:03 -0400 Subject: Add statistics support for Sqlite Add statistics support for Sqlite by tweeking one query and rewrite an other. The rewrite implied a complete refactor of the MySql query as well. Now the code is more flexible and make less queries to the database. See #527 --- app/Models/StatsDAO.php | 68 ++++++++++++++++--------------------------- app/Models/StatsDAOSQLite.php | 30 ++++++++++++++++++- 2 files changed, 54 insertions(+), 44 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 62f238bd2..66f5104b3 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -2,6 +2,8 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { + const ENTRY_COUNT_PERIOD = 30; + /** * Calculates entry repartition for all feeds and for main stream. * The repartition includes: @@ -9,7 +11,7 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { * - read entries * - unread entries * - favorite entries - * + * * @return type */ public function calculateEntryRepartition() { @@ -50,50 +52,19 @@ SQL; /** * Calculates entry count per day on a 30 days period. * Returns the result as a JSON string. - * + * * @return string */ public function calculateEntryCount() { - $count = array(); + $count = $this->initEntryCountArray(); + $period = self::ENTRY_COUNT_PERIOD; - // Generates a list of 30 last day to be sure we always have 30 days. - // If we do not do that kind of thing, we'll end up with holes in the - // days if the user do not have a lot of feeds. - $sql = <<bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - foreach ($res as $value) { - $count[$value['day']] = 0; - } - - // Get stats per day for the last 30 days and applies the result on - // the array created with the last query. + // Get stats per day for the last 30 days $sql = <<prefix}entry AS e -WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -30 DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') +WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') GROUP BY day ORDER BY day ASC SQL; @@ -108,10 +79,21 @@ SQL; return $this->convertToSerie($count); } + /** + * Initialize an array for the entry count. + * + * @return array + */ + protected function initEntryCountArray() { + return array_map(function () { + return 0; + }, array_flip(range(-self::ENTRY_COUNT_PERIOD, -1))); + } + /** * Calculates feed count per category. * Returns the result as a JSON string. - * + * * @return string */ public function calculateFeedByCategory() { @@ -134,7 +116,7 @@ SQL; /** * Calculates entry count per category. * Returns the result as a JSON string. - * + * * @return string */ public function calculateEntryByCategory() { @@ -158,7 +140,7 @@ SQL; /** * Calculates the 10 top feeds based on their number of entries - * + * * @return array */ public function calculateTopFeed() { @@ -172,7 +154,7 @@ FROM {$this->prefix}category AS c, {$this->prefix}entry AS e WHERE c.id = f.category AND f.id = e.id_feed -GROUP BY id +GROUP BY f.id ORDER BY count DESC LIMIT 10 SQL; @@ -180,10 +162,10 @@ SQL; $stm->execute(); return $stm->fetchAll(PDO::FETCH_ASSOC); } - + /** * Calculates the last publication date for each feed - * + * * @return array */ public function calculateFeedLastDate() { diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index c923e5fd0..dea590c92 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -2,8 +2,36 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO { + /** + * Calculates entry count per day on a 30 days period. + * Returns the result as a JSON string. + * + * @return string + */ public function calculateEntryCount() { - return $this->convertToSerie(array()); //TODO: Implement 30-day statistics for SQLite + $count = $this->initEntryCountArray(); + $period = parent::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE strftime('%Y%m%d', e.date, 'unixepoch') + BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') + AND strftime('%Y%m%d', 'now', '-1 day') +GROUP BY day +ORDER BY day ASC +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + foreach ($res as $value) { + $count[(int)$value['day']] = (int) $value['count']; + } + + return $this->convertToSerie($count); } } -- cgit v1.2.3 From 937cb4b066f07888dabe8400b71be6633a19a1d6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 22 Jul 2014 13:41:31 +0200 Subject: Idle feeds: link to configuration page https://github.com/marienfressinaud/FreshRSS/issues/544 --- app/Controllers/statsController.php | 14 +++++++------- app/Models/StatsDAO.php | 3 ++- app/views/stats/idle.phtml | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 9009468bc..be58dd0eb 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -4,9 +4,9 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function indexAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); - Minz_View::appendScript (Minz_Url::display ('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); + Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); - $this->view->count = ($statsDAO->calculateEntryCount()); + $this->view->count = $statsDAO->calculateEntryCount(); $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); $this->view->topFeed = $statsDAO->calculateTopFeed(); @@ -35,19 +35,19 @@ class FreshRSS_stats_Controller extends Minz_ActionController { continue; } if ($feedDate < $lastWeek) { - $idleFeeds['last_week'][] = $feed['name']; + $idleFeeds['last_week'][] = $feed; } if ($feedDate < $lastMonth) { - $idleFeeds['last_month'][] = $feed['name']; + $idleFeeds['last_month'][] = $feed; } if ($feedDate < $last3Month) { - $idleFeeds['last_3_month'][] = $feed['name']; + $idleFeeds['last_3_month'][] = $feed; } if ($feedDate < $last6Month) { - $idleFeeds['last_6_month'][] = $feed['name']; + $idleFeeds['last_6_month'][] = $feed; } if ($feedDate < $lastYear) { - $idleFeeds['last_year'][] = $feed['name']; + $idleFeeds['last_year'][] = $feed; } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 66f5104b3..9a88a4fcf 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -170,7 +170,8 @@ SQL; */ public function calculateFeedLastDate() { $sql = <<prefix}feed AS f, {$this->prefix}entry AS e diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 356fea20f..f62fa8d8b 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -11,7 +11,7 @@
    -
  • +
-- cgit v1.2.3 From d049c1bc806dc0677a4b2b17faf06080600c372f Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 24 Jul 2014 21:57:59 -0400 Subject: Add article repartition in stats Add article repartition per hour, per day of week, per month for all feeds but also for individual feeds. --- app/Controllers/statsController.php | 15 ++++- app/Models/StatsDAO.php | 129 +++++++++++++++++++++++++++++++++++- app/i18n/en.php | 47 +++++++++---- app/i18n/fr.php | 23 +++++++ app/layout/aside_flux.phtml | 1 + app/layout/aside_stats.phtml | 3 + app/views/stats/main.phtml | 127 ----------------------------------- app/views/stats/repartition.phtml | 100 ++++++++++++++++++++++++++++ 8 files changed, 304 insertions(+), 141 deletions(-) delete mode 100644 app/views/stats/main.phtml create mode 100644 app/views/stats/repartition.phtml (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 45d13e043..06a20c2a6 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -55,7 +55,20 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->idleFeeds = $idleFeeds; } - + + public function repartitionAction() { + $statsDAO = FreshRSS_Factory::createStatsDAO(); + $feedDAO = FreshRSS_Factory::createFeedDao(); + Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); + $id = Minz_Request::param ('id', null); + $this->view->feed = $feedDAO->searchById($id); + $this->view->days = $statsDAO->getDays(); + $this->view->months = $statsDAO->getMonths(); + $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); + $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); + $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); + } + public function firstAction() { if (!$this->view->loginOk) { Minz_Error::error( diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 9a88a4fcf..ee8d0d663 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -85,9 +85,83 @@ SQL; * @return array */ protected function initEntryCountArray() { + return $this->initStatsArray(-self::ENTRY_COUNT_PERIOD, -1); + } + + /** + * Calculates the number of article per hour of the day per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerHour($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('%k', $feed); + } + + /** + * Calculates the number of article per day of week per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('%w', $feed); + } + + /** + * Calculates the number of article per month per feed + * + * @param integer $feed + * @return string + */ + public function calculateEntryRepartitionPerFeedPerMonth($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('%m', $feed); + } + + /** + * Calculates the number of article per period per feed + * + * @param string $period format string to use for grouping + * @param integer $feed id + * @return string + */ + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } else { + $restrict = ''; + } + $sql = <<prefix}entry AS e +{$restrict} +GROUP BY period +ORDER BY period ASC +SQL; + + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_NAMED); + + foreach ($res as $value) { + $repartition[(int) $value['period']] = (int) $value['count']; + } + + return $this->convertToSerie($repartition); + } + + /** + * Initialize an array for statistics depending on a range + * + * @param integer $min + * @param integer $max + * @return array + */ + protected function initStatsArray($min, $max) { return array_map(function () { return 0; - }, array_flip(range(-self::ENTRY_COUNT_PERIOD, -1))); + }, array_flip(range($min, $max))); } /** @@ -205,4 +279,57 @@ SQL; return json_encode($serie); } + /** + * Gets days ready for graphs + * + * @return string + */ + public function getDays() { + return $this->convertToTranslatedJson(array( + 'sun', + 'mon', + 'tue', + 'wed', + 'thu', + 'fri', + 'sat', + )); + } + + /** + * Gets months ready for graphs + * + * @return string + */ + public function getMonths() { + return $this->convertToTranslatedJson(array( + 'jan', + 'feb', + 'mar', + 'apr', + 'may', + 'jun', + 'jul', + 'aug', + 'sep', + 'oct', + 'nov', + 'dec', + )); + } + + /** + * Translates array content and encode it as JSON + * + * @param array $data + * @return string + */ + private function convertToTranslatedJson($data = array()) { + $translated = array_map(function ($a) { + return Minz_Translate::t($a); + }, $data); + + return json_encode($translated); + } + } diff --git a/app/i18n/en.php b/app/i18n/en.php index 8634f99b5..10327c7f5 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -48,6 +48,10 @@ return array ( 'stats' => 'Statistics', 'stats_idle' => 'Idle feeds', 'stats_main' => 'Main statistics', + 'stats_repartition' => 'Articles repartition', + 'stats_entry_per_hour' => 'Per hour', + 'stats_entry_per_day_of_week' => 'Per day of week', + 'stats_entry_per_month' => 'Per month', 'last_week' => 'Last week', 'last_month' => 'Last month', @@ -341,18 +345,37 @@ return array ( 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', // DATE - 'january' => 'january', - 'february' => 'february', - 'march' => 'march', - 'april' => 'april', - 'may' => 'may', - 'june' => 'june', - 'july' => 'july', - 'august' => 'august', - 'september' => 'september', - 'october' => 'october', - 'november' => 'november', - 'december' => 'december', + 'january' => 'January', + 'february' => 'February', + 'march' => 'March', + 'april' => 'April', + 'may' => 'May', + 'june' => 'June', + 'july' => 'July', + 'august' => 'August', + 'september' => 'September', + 'october' => 'October', + 'november' => 'November', + 'december' => 'December', + 'january' => 'Jan', + 'february' => 'Feb', + 'march' => 'Mar', + 'april' => 'Apr', + 'may' => 'May', + 'june' => 'Jun', + 'july' => 'Jul', + 'august' => 'Aug', + 'september' => 'Sep', + 'october' => 'Oct', + 'november' => 'Nov', + 'december' => 'Dec', + 'sun' => 'Sun', + 'mon' => 'Mon', + 'tue' => 'Tue', + 'wed' => 'Wed', + 'thu' => 'Thu', + 'fri' => 'Fri', + 'sat' => 'Sat', // special format for date() function 'Jan' => '\J\a\n\u\a\r\y', 'Feb' => '\F\e\b\r\u\a\r\y', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index e04078dba..6ab3d7335 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -48,6 +48,10 @@ return array ( 'stats' => 'Statistiques', 'stats_idle' => 'Flux inactifs', 'stats_main' => 'Statistiques principales', + 'stats_repartition' => 'Répartition des articles', + 'stats_entry_per_hour' => 'Par heure', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine', + 'stats_entry_per_month' => 'Par mois', 'last_week' => 'La dernière semaine', 'last_month' => 'Le dernier mois', @@ -353,6 +357,25 @@ return array ( 'october' => 'octobre', 'november' => 'novembre', 'december' => 'décembre', + 'jan' => 'jan.', + 'feb' => 'fév.', + 'mar' => 'mar.', + 'apr' => 'avr.', + 'may' => 'mai.', + 'jun' => 'juin', + 'jul' => 'jui.', + 'aug' => 'août', + 'sep' => 'sep.', + 'oct' => 'oct.', + 'nov' => 'nov.', + 'dec' => 'déc.', + 'sun' => 'dim.', + 'mon' => 'lun.', + 'tue' => 'mar.', + 'wed' => 'mer.', + 'thu' => 'jeu.', + 'fri' => 'ven.', + 'sat' => 'sam.', // format spécial pour la fonction date() 'Jan' => '\j\a\n\v\i\e\r', 'Feb' => '\f\é\v\r\i\e\r', diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 817dae676..5fbb36730 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -83,6 +83,7 @@
  • +
  • diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index 32a3f5dee..fbfb9d84d 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -6,4 +6,7 @@
  • +
  • + +
  • diff --git a/app/views/stats/main.phtml b/app/views/stats/main.phtml deleted file mode 100644 index fe372e221..000000000 --- a/app/views/stats/main.phtml +++ /dev/null @@ -1,127 +0,0 @@ -partial('aside_stats'); ?> - -
    - - -

    - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     
    repartition['main_stream']['total']); ?>repartition['all_feeds']['total']); ?>
    repartition['main_stream']['read']); ?>repartition['all_feeds']['read']); ?>
    repartition['main_stream']['unread']); ?>repartition['all_feeds']['unread']); ?>
    repartition['main_stream']['favorite']); ?>repartition['all_feeds']['favorite']); ?>
    -
    - -
    -

    -
    -
    - -
    -

    -
    -
    -
    - -
    -

    -
    -
    -
    - -
    -

    - - - - - - - - - - topFeed as $feed): ?> - - - - - - - -
    -
    -
    - - diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml new file mode 100644 index 000000000..4455abe2a --- /dev/null +++ b/app/views/stats/repartition.phtml @@ -0,0 +1,100 @@ +partial('aside_stats'); ?> + +
    + + + feed) {?> +

    + + + feed->name(); ?> + +

    + +

    + + +
    +

    +
    +
    + +
    +

    +
    +
    + +
    +

    +
    +
    +
    + + \ No newline at end of file -- cgit v1.2.3 From aa317eb2948b5caa5472bf307099efe850f7b314 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 24 Jul 2014 22:57:31 -0400 Subject: Add repartition statistic support in Sqlite --- app/Models/StatsDAO.php | 2 +- app/Models/StatsDAOSQLite.php | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index ee8d0d663..89be76a26 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -95,7 +95,7 @@ SQL; * @return string */ public function calculateEntryRepartitionPerFeedPerHour($feed = null) { - return $this->calculateEntryRepartitionPerFeedPerPeriod('%k', $feed); + return $this->calculateEntryRepartitionPerFeedPerPeriod('%H', $feed); } /** diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index dea590c92..6cb54ddf6 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -28,10 +28,36 @@ SQL; $res = $stm->fetchAll(PDO::FETCH_ASSOC); foreach ($res as $value) { - $count[(int)$value['day']] = (int) $value['count']; + $count[(int) $value['day']] = (int) $value['count']; } return $this->convertToSerie($count); } + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } else { + $restrict = ''; + } + $sql = <<prefix}entry AS e +{$restrict} +GROUP BY period +ORDER BY period ASC +SQL; + + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_NAMED); + + foreach ($res as $value) { + $repartition[(int) $value['period']] = (int) $value['count']; + } + + return $this->convertToSerie($repartition); + } + } -- cgit v1.2.3 From f002dbe4ceb8505b237bd67b66365d636bddd4b2 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 1 Sep 2014 20:58:05 -0400 Subject: Add average on repartition charts. It needs some verification on the value used to calculate the averages. --- app/Controllers/statsController.php | 3 ++ app/Models/StatsDAO.php | 62 +++++++++++++++++++++++++++++++++++++ app/views/stats/repartition.phtml | 48 ++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 6 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 98f46f0d2..000b41dd2 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -67,8 +67,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); + $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); + $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id); $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); + $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } public function firstAction() { diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 89be76a26..bd4271ba8 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -151,6 +151,68 @@ SQL; return $this->convertToSerie($repartition); } + /** + * Calculates the average number of article per hour per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerHour($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); + } + + /** + * Calculates the average number of article per day of week per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerDayOfWeek($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(7, $feed); + } + + /** + * Calculates the average number of article per month per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerMonth($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(30, $feed); + } + + /** + * Calculates the average number of article per feed + * + * @param float $period number used to divide the number of day in the period + * @param integer $feed id + * @return integer + */ + protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) { + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } else { + $restrict = ''; + } + $sql = <<prefix}entry AS e +{$restrict} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + $date_min = new \DateTime(); + $date_min->setTimestamp($res['date_min']); + $date_max = new \DateTime(); + $date_max->setTimestamp($res['date_max']); + $interval = $date_max->diff($date_min, true); + + return round($res['count'] / ($interval->format('%a') / ($period)), 2); + } + /** * Initialize an array for statistics depending on a range * diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 9d2eb28e4..2331db78c 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -56,11 +56,22 @@ function initStats() { return; } // Entry per hour + var avg_h = []; + for (var i = -1; i <= 24; i++) { + avg_h.push([i, averageHour?>]); + } Flotr.draw(document.getElementById('statsEntryPerHour'), - [repartitionHour ?>], + [{ + data: repartitionHour ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_h, + lines: {show: true}, + label: averageHour?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 23, tickFormatter: function(x) { var x = parseInt(x); @@ -70,14 +81,26 @@ function initStats() { max: 23.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per day of week + var avg_dow = []; + for (var i = -1; i <= 7; i++) { + avg_dow.push([i, averageDayOfWeek?>]); + } Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'), - [repartitionDayOfWeek ?>], + [{ + data: repartitionDayOfWeek ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_dow, + lines: {show: true}, + label: averageDayOfWeek?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 6, tickFormatter: function(x) { var x = parseInt(x), @@ -88,14 +111,26 @@ function initStats() { max: 6.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per month + var avg_m = []; + for (var i = 0; i <= 13; i++) { + avg_m.push([i, averageMonth?>]); + } Flotr.draw(document.getElementById('statsEntryPerMonth'), - [repartitionMonth ?>], + [{ + data: repartitionMonth ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_m, + lines: {show: true}, + label: averageMonth?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 12, tickFormatter: function(x) { var x = parseInt(x), @@ -106,6 +141,7 @@ function initStats() { max: 12.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From 8731de5c3ad4eea8ae30d1f6435c569ed31b8828 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 10:37:29 +0200 Subject: Fix repartition stats with 0 or 1 article. --- app/Models/StatsDAO.php | 8 +++++++- app/Models/StatsDAOSQLite.php | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index bd4271ba8..b8dc40592 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -209,8 +209,14 @@ SQL; $date_max = new \DateTime(); $date_max->setTimestamp($res['date_max']); $interval = $date_max->diff($date_min, true); + $interval_in_days = $interval->format('%a'); + if ($interval_in_days <= 0) { + // Surely only one article. + // We will return count / (period/period) == count. + $interval_in_days = $period; + } - return round($res['count'] / ($interval->format('%a') / ($period)), 2); + return round($res['count'] / ($interval_in_days / $period), 2); } /** diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 6cb54ddf6..3b1256de1 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -53,6 +53,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_NAMED); + $repartition = array(); foreach ($res as $value) { $repartition[(int) $value['period']] = (int) $value['count']; } -- cgit v1.2.3 From 55843ff7a59f058e54046a3c2f85e2b476522c9d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 16:45:16 +0200 Subject: Few fixes about statistics --- app/Models/StatsDAO.php | 1 + app/Models/Themes.php | 1 + app/i18n/de.php | 2 +- app/i18n/en.php | 2 +- app/i18n/fr.php | 2 +- app/views/configure/feed.phtml | 23 +++++++++++++---------- app/views/stats/idle.phtml | 4 +++- app/views/stats/repartition.phtml | 4 ++-- p/themes/icons/stats.svg | 31 +++++++++++++++++++++++++++++++ 9 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 p/themes/icons/stats.svg (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index b8dc40592..40505ab3e 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -315,6 +315,7 @@ SQL; SELECT MAX(f.id) as id , MAX(f.name) AS name , MAX(date) AS last_date +, COUNT(*) AS nb_articles FROM {$this->prefix}feed AS f, {$this->prefix}entry AS e WHERE f.id = e.id_feed diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 538eb6554..68fc17a2b 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -96,6 +96,7 @@ class FreshRSS_Themes extends Minz_Model { 'search' => '🔍', 'share' => '♺', 'starred' => '★', + 'stats' => '%', 'tag' => '⚐', 'up' => '△', 'view-normal' => '☰', diff --git a/app/i18n/de.php b/app/i18n/de.php index 3dc1536de..6caa3cd84 100644 --- a/app/i18n/de.php +++ b/app/i18n/de.php @@ -150,7 +150,7 @@ return array ( 'website_url' => 'Webseiten-Adresse URL', 'feed_url' => 'Feed URL', 'articles' => 'Artikel', - 'number_articles' => 'Anzahl der Artikel', + 'number_articles' => '%d Artikel', 'by_feed' => 'per Feed', 'by_default' => 'Als Vorgabe', 'keep_history' => 'Kleinste Anzahl der Artikel, die behalten werden', diff --git a/app/i18n/en.php b/app/i18n/en.php index e84787508..b9588c8b8 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -215,7 +215,7 @@ return array ( 'website_url' => 'Website URL', 'feed_url' => 'Feed URL', 'articles' => 'articles', - 'number_articles' => 'Number of articles', + 'number_articles' => '%d articles', 'by_feed' => 'by feed', 'by_default' => 'By default', 'keep_history' => 'Minimum number of articles to keep', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index fab5c3470..4cc9c8598 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -215,7 +215,7 @@ return array ( 'website_url' => 'URL du site', 'feed_url' => 'URL du flux', 'articles' => 'articles', - 'number_articles' => 'Nombre d’articles', + 'number_articles' => '%d articles', 'by_feed' => 'par flux', 'by_default' => 'Par défaut', 'keep_history' => 'Nombre minimum d’articles à conserver', diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index a8dd9a8cb..aa653e585 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -70,6 +70,13 @@ +
    +
    + + + +
    +
    @@ -80,17 +87,13 @@
    - -
    - - - -
    -
    -
    -
    - +
    + + + + +
    diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 608e2d33c..14b83ae95 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -23,7 +23,9 @@
    -
  • +
  • + () +
  • diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index ead275696..b425c1458 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -24,8 +24,8 @@ feed) {?> - - + + diff --git a/p/themes/icons/stats.svg b/p/themes/icons/stats.svg new file mode 100644 index 000000000..408d9e67f --- /dev/null +++ b/p/themes/icons/stats.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + -- cgit v1.2.3 From cd88414abcffd94cfce933cf578ecc640b691381 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 29 Sep 2014 18:54:03 -0400 Subject: Add an average per day for the 30 day period --- app/Controllers/statsController.php | 1 + app/Models/StatsDAO.php | 27 ++++++++++++++++++++++++--- app/Models/StatsDAOSQLite.php | 23 +++++++++++++++++++++++ app/views/stats/index.phtml | 16 +++++++++++++--- 4 files changed, 61 insertions(+), 6 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 256543f37..3069be34d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -21,6 +21,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); $this->view->count = $statsDAO->calculateEntryCount(); + $this->view->average = $statsDAO->calculateEntryAverage(); $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); $this->view->topFeed = $statsDAO->calculateTopFeed(); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 40505ab3e..08dd4cd5c 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -79,6 +79,27 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + /** * Initialize an array for the entry count. * @@ -160,7 +181,7 @@ SQL; public function calculateEntryAveragePerFeedPerHour($feed = null) { return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); } - + /** * Calculates the average number of article per day of week per feed * @@ -180,10 +201,10 @@ SQL; public function calculateEntryAveragePerFeedPerMonth($feed = null) { return $this->calculateEntryAveragePerFeedPerPeriod(30, $feed); } - + /** * Calculates the average number of article per feed - * + * * @param float $period number used to divide the number of day in the period * @param integer $feed id * @return integer diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 3b1256de1..bb2336532 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -34,6 +34,29 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE strftime('%Y%m%d', e.date, 'unixepoch') + BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') + AND strftime('%Y%m%d', 'now', '-1 day') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 31185fbe3..9b19cb560 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -93,12 +93,22 @@ function initStats() { return; } // Entry per day + var avg = []; + for (var i = -31; i <= 0; i++) { + avg.push([i, average?>]); + } Flotr.draw(document.getElementById('statsEntryPerDay'), - [count ?>], + [{ + data: count ?>, + bars: {horizontal: false, show: true} + },{ + data: avg, + lines: {show: true}, + label: average?> + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, - xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0}, + xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0, min: -30.75, max: -0.25}, yaxis: {min: 0}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From 6c8b36f04ea1bc2c022c331bb0980b6c9dccb83c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 15:55:20 +0200 Subject: Let's begin the big refactoring! Minz_Translate::t\s? replaces by _t See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/entryController.php | 8 ++-- app/Controllers/errorController.php | 4 +- app/Controllers/feedController.php | 30 ++++++------- app/Controllers/indexController.php | 22 +++++----- app/Controllers/statsController.php | 4 +- app/Controllers/usersController.php | 8 ++-- app/FreshRSS.php | 2 +- app/Models/CategoryDAO.php | 2 +- app/Models/StatsDAO.php | 2 +- app/Models/UserDAO.php | 4 +- app/layout/aside_stats.phtml | 14 +++--- app/views/configure/archiving.phtml | 36 ++++++++-------- app/views/configure/display.phtml | 44 +++++++++---------- app/views/configure/reading.phtml | 64 +++++++++++++-------------- app/views/configure/sharing.phtml | 24 +++++------ app/views/configure/users.phtml | 74 ++++++++++++++++---------------- app/views/error/index.phtml | 2 +- app/views/feed/add.phtml | 34 +++++++-------- app/views/helpers/feed/update.phtml | 60 +++++++++++++------------- app/views/helpers/javascript_vars.phtml | 8 ++-- app/views/helpers/logs_pagination.phtml | 8 ++-- app/views/helpers/view/normal_view.phtml | 14 +++--- app/views/helpers/view/reader_view.phtml | 2 +- app/views/helpers/view/rss_view.phtml | 2 +- app/views/index/about.phtml | 26 +++++------ app/views/index/logs.phtml | 8 ++-- lib/lib_rss.php | 8 ++-- 27 files changed, 256 insertions(+), 258 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index ab66d9198..048ac1c69 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -5,7 +5,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if (!$this->view->loginOk) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } @@ -75,7 +75,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_marked_read') + 'content' => _t('feeds_marked_read') ); Minz_Session::_param ('notification', $notif); } else { @@ -111,7 +111,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('optimization_complete') + 'content' => _t('optimization_complete') ); Minz_Session::_param ('notification', $notif); } @@ -155,7 +155,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array( 'type' => 'good', - 'content' => Minz_Translate::t('purge_completed', $nbTotal) + 'content' => _t('purge_completed', $nbTotal) ); Minz_Session::_param('notification', $notif); diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index 922650b3d..64a5c06fd 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -24,11 +24,11 @@ class FreshRSS_error_Controller extends Minz_ActionController { if ($this->view->errorMessage == '') { switch(Minz_Request::param('code')) { case 403: - $this->view->errorMessage = Minz_Translate::t('forbidden_access'); + $this->view->errorMessage = _t('forbidden_access'); break; case 404: default: - $this->view->errorMessage = Minz_Translate::t('page_not_found'); + $this->view->errorMessage = _t('page_not_found'); break; } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 92ce40634..029f9fa68 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -15,7 +15,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { ) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } } @@ -84,7 +84,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on est déjà abonné à ce flux $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) + 'content' => _t('already_subscribed', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -93,7 +93,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // problème au niveau de la base de données $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) + 'content' => _t('feed_not_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -131,7 +131,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ok, ajout terminé $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_added', $feed->name ()) + 'content' => _t('feed_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); @@ -143,14 +143,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('invalid_url', $url) + 'content' => _t('invalid_url', $url) ); Minz_Session::_param ('notification', $notif); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } catch (Minz_FileNotExistException $e) { @@ -158,7 +158,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } @@ -170,7 +170,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // GET request so we must ask confirmation to user - Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · '); + Minz_View::prependTitle(_t('add_rss_feed') . ' · '); $this->view->categories = $this->catDAO->listCategories(false); $this->view->feed = new FreshRSS_Feed($url); try { @@ -186,9 +186,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Already subscribe so we redirect to the feed configuration page $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t( - 'already_subscribed', $feed->name() - ) + 'content' => _t('already_subscribed', $feed->name()) ); Minz_Session::_param('notification', $notif); @@ -210,7 +208,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $n = $feedDAO->truncate($id); $notif = array( 'type' => $n === false ? 'bad' : 'good', - 'content' => Minz_Translate::t ('n_entries_deleted', $n) + 'content' => _t('n_entries_deleted', $n) ); Minz_Session::_param ('notification', $notif); invalidateHttpCache(); @@ -336,19 +334,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed = reset ($feeds); $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) + 'content' => _t('feed_actualized', $feed->name ()) ); } elseif ($flux_update > 1) { // plusieurs flux on été mis à jour $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) + 'content' => _t('n_feeds_actualized', $flux_update) ); } else { // aucun flux n'a été mis à jour, oups $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('no_feed_to_refresh') + 'content' => _t('no_feed_to_refresh') ); } @@ -370,7 +368,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ressenti utilisateur $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_actualized') + 'content' => _t('feeds_actualized') ); Minz_Session::_param ('notification', $notif); // et on désactive le layout car ne sert à rien diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 1b6563bb3..346739523 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -14,7 +14,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($output === 'rss' && !$token_is_ok) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); return; } elseif ($output !== 'rss') { @@ -62,7 +62,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); return; } @@ -145,7 +145,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); } } @@ -158,12 +158,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { private function checkAndProcessType ($getType, $getId) { switch ($getType) { case 'a': - $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); + $this->view->currentName = _t('your_rss_feeds'); $this->nb_not_read_cat = $this->view->nb_not_read; $this->view->get_c = $getType; return true; case 's': - $this->view->currentName = Minz_Translate::t ('your_favorites'); + $this->view->currentName = _t('your_favorites'); $this->nb_not_read_cat = $this->view->nb_favorites['unread']; $this->view->get_c = $getType; return true; @@ -202,18 +202,18 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function aboutAction () { - Minz_View::prependTitle (Minz_Translate::t ('about') . ' · '); + Minz_View::prependTitle (_t('about') . ' · '); } public function logsAction () { if (!$this->view->loginOk) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } - Minz_View::prependTitle (Minz_Translate::t ('logs') . ' · '); + Minz_View::prependTitle (_t('logs') . ' · '); if (Minz_Request::isPost ()) { FreshRSS_LogDAO::truncate(); @@ -279,7 +279,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + $res['reason'] = $reason == '' ? _t('invalid_login') : $reason; Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } @@ -368,7 +368,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (!$ok) { $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t('invalid_login') + 'content' => _t('invalid_login') ); Minz_Session::_param('notification', $notif); } @@ -403,7 +403,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } elseif (!Minz_Configuration::canLogIn()) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } invalidateHttpCache(); diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 3069be34d..4adb5e75d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -120,11 +120,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function firstAction() { if (!$this->view->loginOk) { Minz_Error::error( - 403, array('error' => array(Minz_Translate::t('access_denied'))) + 403, array('error' => array(_t('access_denied'))) ); } - Minz_View::prependTitle(Minz_Translate::t('stats') . ' · '); + Minz_View::prependTitle(_t('stats') . ' · '); } } diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index a9e6c32bc..8eb82f5d5 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -8,7 +8,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (!$this->view->loginOk) { Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied'))) + array('error' => array(_t('access_denied'))) ); } } @@ -90,7 +90,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'configuration_updated' : 'error_occurred') + 'content' => _t($ok ? 'configuration_updated' : 'error_occurred') ); Minz_Session::_param('notification', $notif); } @@ -162,7 +162,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_created' : 'error_occurred', $new_user_name) + 'content' => _t($ok ? 'user_created' : 'error_occurred', $new_user_name) ); Minz_Session::_param('notification', $notif); } @@ -194,7 +194,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) + 'content' => _t($ok ? 'user_deleted' : 'error_occurred', $username) ); Minz_Session::_param('notification', $notif); } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 58aac4059..16f64fd8b 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -10,7 +10,7 @@ class FreshRSS extends Minz_FrontController { $loginOk = false; //Basic protection against XSRF attacks Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied') . ' [HTTP_REFERER=' . + array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' . htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) ); } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index f11f87f47..5def50a26 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -134,7 +134,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $def_cat = $this->searchById (1); if ($def_cat == null) { - $cat = new FreshRSS_Category (Minz_Translate::t ('default_category')); + $cat = new FreshRSS_Category (_t('default_category')); $cat->_id (1); $values = array ( diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 08dd4cd5c..113944508 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -416,7 +416,7 @@ SQL; */ private function convertToTranslatedJson($data = array()) { $translated = array_map(function ($a) { - return Minz_Translate::t($a); + return _t($a); }, $data); return json_encode($translated); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 9f64fb4a7..0c96d7175 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -9,7 +9,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $ok = false; if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); + $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { //E.g. SQLite @@ -17,7 +17,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { if (is_array($SQL_CREATE_TABLES)) { $ok = true; foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, '', Minz_Translate::t('default_category')); + $sql = sprintf($instruction, '', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok &= ($stm && $stm->execute()); } diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index fbfb9d84d..1cd31a99c 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -1,12 +1,12 @@ diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index c9cc7fe02..3180fe933 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -1,31 +1,31 @@ partial('aside_configure'); ?>
    - +
    - -

    + +

    - +
    - -   + +  
    - +
    () + ?> ()
    - +
    () + ?> ()
    - - + +
    - +
    -

    +

    -

    nb_total), ' ', Minz_Translate::t('articles'), ', ', formatBytes($this->size_user); ?>

    +

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    - - + +
    -

    +

    size_total); ?>

    diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 8eb3a156b..f1b80ab15 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - + - +
    - +
    themes as $theme) { ?>conf->content_width; ?>
    - +
    - + - - - - - + + + + + - + @@ -80,7 +80,7 @@ - + @@ -93,16 +93,16 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 8b2da2a28..7e4efc264 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - +
    - +
    - +
    @@ -15,22 +15,22 @@
    - +
    - +
    @@ -50,7 +50,7 @@
    @@ -59,8 +59,8 @@
    @@ -69,8 +69,8 @@
    @@ -79,8 +79,8 @@
    @@ -89,8 +89,8 @@
    @@ -99,8 +99,8 @@
    @@ -109,48 +109,48 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index 02ce331da..ee276a94e 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -1,7 +1,7 @@ partial ('aside_configure'); ?>
    - + @@ -9,28 +9,28 @@ data-advanced='
    - - + +
    - +
    '> - + conf->sharing as $key => $sharing): ?> conf->shares[$sharing['type']]; ?>
    ' />
    - - + +
    - + @@ -42,7 +42,7 @@
    @@ -51,8 +51,8 @@
    - - + +
    diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 272896fb2..04e662fa3 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -1,36 +1,36 @@ partial('aside_configure'); ?>
    - +
    - +
    - +
    - +
    />
    - +
    - +
    /> @@ -41,36 +41,36 @@
    - + conf->mail_login; ?>
    placeholder="alice@example.net" /> - +
    - - + +
    - +
    - +
    @@ -80,7 +80,7 @@
    @@ -90,7 +90,7 @@
    @@ -100,7 +100,7 @@
    @@ -108,12 +108,12 @@
    - + conf->token; ?>
    - /> - +
    @@ -123,24 +123,24 @@
    - - + +
    - +
    - +
    conf->availableLanguages (); ?> @@ -173,25 +173,25 @@
    - +
    - +
    - +
    - + conf->mail_login; ?>
    @@ -200,8 +200,8 @@
    - - + +
    diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml index ef4fbd39d..5e1949800 100644 --- a/app/views/error/index.phtml +++ b/app/views/error/index.phtml @@ -3,7 +3,7 @@

    code; ?>

    errorMessage; ?>
    - +

    diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index 849dacac6..17e52a571 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -1,16 +1,16 @@ feed) { ?>
    -

    +

    load_ok) { ?> -

    +

    - + load_ok) { ?>
    - +
    @@ -18,7 +18,7 @@ feed->description(); if ($desc != '') { ?>
    - +
    @@ -26,7 +26,7 @@
    - +
    feed->website(); ?> @@ -35,17 +35,17 @@
    - +
    - +
    - +
    - +
    - + feed->httpAuth(false); ?>
    - +
    - +
    - +
    - - + +
    diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 678c5f132..8bd645d11 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -12,27 +12,27 @@ feed->nbEntries (); ?> feed->inError ()) { ?> -

    +

    -

    +

    - +
    - +
    - +
    - +
    @@ -41,18 +41,18 @@
    - +
    - +
    - +
    feed->priority () > 0 ? ' checked="checked"' : ''; ?> /> - +
    @@ -83,7 +83,7 @@
    - +
    @@ -96,21 +96,21 @@
    - +
    - +
    - +
    - +
    @@ -150,24 +150,24 @@
    - - + +
    - +
    - +
    - - + +
    - - + +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 4f7e3db0c..ba02b9fad 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -52,10 +52,10 @@ echo 'authType="', $authType, '",', 'url_login="', _url ('index', 'login'), '",', 'url_logout="', _url ('index', 'logout'), '",'; -echo 'str_confirmation_default="', Minz_Translate::t('confirm_action'), '"', ",\n"; -echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\n"; -echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n"; -echo 'str_category_empty="', Minz_Translate::t('category_empty'), '"', ",\n"; +echo 'str_confirmation_default="', _t('confirm_action'), '"', ",\n"; +echo 'str_notif_title_articles="', _t('notif_title_new_articles'), '"', ",\n"; +echo 'str_notif_body_articles="', _t('notif_body_new_articles'), '"', ",\n"; +echo 'str_category_empty="', _t('category_empty'), '"', ",\n"; echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml index e3d14810e..191cfa8de 100755 --- a/app/views/helpers/logs_pagination.phtml +++ b/app/views/helpers/logs_pagination.phtml @@ -9,14 +9,14 @@
  • currentPage > 1) { ?> - « + «
  • currentPage - 1; ?>
  • currentPage > 1) { ?> - +
  • @@ -34,13 +34,13 @@ currentPage + 1; ?>
  • currentPage < $this->nbPage) { ?> - +
  • nbPage; ?>
  • currentPage < $this->nbPage) { ?> - » + »
  • diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index e469edf58..ee745144f 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -30,12 +30,12 @@ if (!empty($this->entries)) {
    - +
    entries as $item) { if ($display_today && $item->isDay (FreshRSS_Days::TODAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_yesterday && $item->isDay (FreshRSS_Days::YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_others && $item->isDay (FreshRSS_Days::BEFORE_YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) {

    title (); ?>

    author(); - echo $author != '' ? '
    ' . Minz_Translate::t('by_author', $author) . '
    ' : '', + echo $author != '' ? '
    ' . _t('by_author', $author) . '
    ' : '', $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); ?>
    @@ -133,7 +133,7 @@ if (!empty($this->entries)) { - +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 31c9cdbc1..4f6beb9fd 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -77,11 +77,11 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { } function timestamptodate ($t, $hour = true) { - $month = Minz_Translate::t (date('M', $t)); + $month = _t(date('M', $t)); if ($hour) { - $date = Minz_Translate::t ('format_date_hour', $month); + $date = _t('format_date_hour', $month); } else { - $date = Minz_Translate::t ('format_date', $month); + $date = _t('format_date', $month); } return @date ($date, $t); @@ -107,7 +107,7 @@ function html_only_entity_decode($text) { function customSimplePie() { $simplePie = new SimplePie(); - $simplePie->set_useragent(Minz_Translate::t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_useragent(_t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $simplePie->set_cache_location(CACHE_PATH); $simplePie->set_cache_duration(800); $simplePie->strip_htmltags(array( -- cgit v1.2.3 From b5dee73ea0ab3cc24c4857ac102e9e78cf20ab92 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 18:51:08 +0200 Subject: Coding style Remove spaces before parenthesis bis See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Exceptions/BadUrlException.php | 4 +- app/Exceptions/EntriesGetterException.php | 4 +- app/Exceptions/FeedException.php | 4 +- app/Models/Category.php | 42 ++++---- app/Models/CategoryDAO.php | 164 +++++++++++++++--------------- app/Models/Configuration.php | 36 +++---- app/Models/Entry.php | 138 ++++++++++++------------- app/Models/EntryDAO.php | 42 ++++---- app/Models/Log.php | 12 +-- app/Models/LogDAO.php | 10 +- app/Models/StatsDAO.php | 2 +- 11 files changed, 229 insertions(+), 229 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Exceptions/BadUrlException.php b/app/Exceptions/BadUrlException.php index 7d1fe110e..59574e1e5 100644 --- a/app/Exceptions/BadUrlException.php +++ b/app/Exceptions/BadUrlException.php @@ -1,6 +1,6 @@ _name ($name); - if (isset ($feeds)) { - $this->_feeds ($feeds); + public function __construct($name = '', $feeds = null) { + $this->_name($name); + if (isset($feeds)) { + $this->_feeds($feeds); $this->nbFeed = 0; $this->nbNotRead = 0; foreach ($feeds as $feed) { $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); + $this->nbNotRead += $feed->nbNotRead(); } } } - public function id () { + public function id() { return $this->id; } - public function name () { + public function name() { return $this->name; } - public function nbFeed () { + public function nbFeed() { if ($this->nbFeed < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbFeed = $catDAO->countFeed ($this->id ()); + $catDAO = new FreshRSS_CategoryDAO(); + $this->nbFeed = $catDAO->countFeed($this->id()); } return $this->nbFeed; } - public function nbNotRead () { + public function nbNotRead() { if ($this->nbNotRead < 0) { - $catDAO = new FreshRSS_CategoryDAO (); - $this->nbNotRead = $catDAO->countNotRead ($this->id ()); + $catDAO = new FreshRSS_CategoryDAO(); + $this->nbNotRead = $catDAO->countNotRead($this->id()); } return $this->nbNotRead; } - public function feeds () { + public function feeds() { if ($this->feeds === null) { $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->feeds = $feedDAO->listByCategory ($this->id ()); + $this->feeds = $feedDAO->listByCategory($this->id()); $this->nbFeed = 0; $this->nbNotRead = 0; foreach ($this->feeds as $feed) { $this->nbFeed++; - $this->nbNotRead += $feed->nbNotRead (); + $this->nbNotRead += $feed->nbNotRead(); } } return $this->feeds; } - public function _id ($value) { + public function _id($value) { $this->id = $value; } - public function _name ($value) { + public function _name($value) { $this->name = substr(trim($value), 0, 255); } - public function _feeds ($values) { - if (!is_array ($values)) { - $values = array ($values); + public function _feeds($values) { + if (!is_array($values)) { + $values = array($values); } $this->feeds = $values; diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 5def50a26..ce1babfdd 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -1,15 +1,15 @@ prefix . 'category` (name) VALUES(?)'; - $stm = $this->bd->prepare ($sql); + public function addCategory($valuesTmp) { + $sql = 'INSERT INTO `' . $this->prefix . 'category`(name) VALUES(?)'; + $stm = $this->bd->prepare($sql); - $values = array ( + $values = array( substr($valuesTmp['name'], 0, 255), ); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); @@ -31,16 +31,16 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $cat->id(); } - public function updateCategory ($id, $valuesTmp) { + public function updateCategory($id, $valuesTmp) { $sql = 'UPDATE `' . $this->prefix . 'category` SET name=? WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ( + $values = array( $valuesTmp['name'], $id ); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); @@ -49,13 +49,13 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } } - public function deleteCategory ($id) { + public function deleteCategory($id) { $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($id); + $values = array($id); - if ($stm && $stm->execute ($values)) { + if ($stm && $stm->execute($values)) { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); @@ -64,40 +64,40 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } } - public function searchById ($id) { + public function searchById($id) { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($id); + $values = array($id); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return null; } } - public function searchByName ($name) { + public function searchByName($name) { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE name=?'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $values = array ($name); + $values = array($name); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return null; } } - public function listCategories ($prePopulateFeeds = true, $details = false) { + public function listCategories($prePopulateFeeds = true, $details = false) { if ($prePopulateFeeds) { $sql = 'SELECT c.id AS c_id, c.name AS c_name, ' . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ') @@ -105,80 +105,80 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category=c.id ' . 'GROUP BY f.id ' . 'ORDER BY c.name, f.name'; - $stm = $this->bd->prepare ($sql); - $stm->execute (); - return self::daoToCategoryPrepopulated ($stm->fetchAll (PDO::FETCH_ASSOC)); + $stm = $this->bd->prepare($sql); + $stm->execute(); + return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC)); } else { $sql = 'SELECT * FROM `' . $this->prefix . 'category` ORDER BY name'; - $stm = $this->bd->prepare ($sql); - $stm->execute (); - return self::daoToCategory ($stm->fetchAll (PDO::FETCH_ASSOC)); + $stm = $this->bd->prepare($sql); + $stm->execute(); + return self::daoToCategory($stm->fetchAll(PDO::FETCH_ASSOC)); } } - public function getDefault () { + public function getDefault() { $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=1'; - $stm = $this->bd->prepare ($sql); + $stm = $this->bd->prepare($sql); - $stm->execute (); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); - $cat = self::daoToCategory ($res); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + $cat = self::daoToCategory($res); - if (isset ($cat[0])) { + if (isset($cat[0])) { return $cat[0]; } else { return false; } } - public function checkDefault () { - $def_cat = $this->searchById (1); + public function checkDefault() { + $def_cat = $this->searchById(1); if ($def_cat == null) { - $cat = new FreshRSS_Category (_t('default_category')); - $cat->_id (1); + $cat = new FreshRSS_Category(_t('default_category')); + $cat->_id(1); - $values = array ( - 'id' => $cat->id (), - 'name' => $cat->name (), + $values = array( + 'id' => $cat->id(), + 'name' => $cat->name(), ); - $this->addCategory ($values); + $this->addCategory($values); } } - public function count () { + public function count() { $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'category`'; - $stm = $this->bd->prepare ($sql); - $stm->execute (); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); return $res[0]['count']; } - public function countFeed ($id) { + public function countFeed($id) { $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'feed` WHERE category=?'; - $stm = $this->bd->prepare ($sql); - $values = array ($id); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $stm = $this->bd->prepare($sql); + $values = array($id); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); return $res[0]['count']; } - public function countNotRead ($id) { + public function countNotRead($id) { $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id WHERE category=? AND e.is_read=0'; - $stm = $this->bd->prepare ($sql); - $values = array ($id); - $stm->execute ($values); - $res = $stm->fetchAll (PDO::FETCH_ASSOC); + $stm = $this->bd->prepare($sql); + $values = array($id); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); return $res[0]['count']; } public static function findFeed($categories, $feed_id) { foreach ($categories as $category) { - foreach ($category->feeds () as $feed) { - if ($feed->id () === $feed_id) { + foreach ($category->feeds() as $feed) { + if ($feed->id() === $feed_id) { return $feed; } } @@ -189,8 +189,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { public static function CountUnreads($categories, $minPriority = 0) { $n = 0; foreach ($categories as $category) { - foreach ($category->feeds () as $feed) { - if ($feed->priority () >= $minPriority) { + foreach ($category->feeds() as $feed) { + if ($feed->priority() >= $minPriority) { $n += $feed->nbNotRead(); } } @@ -198,11 +198,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $n; } - public static function daoToCategoryPrepopulated ($listDAO) { - $list = array (); + public static function daoToCategoryPrepopulated($listDAO) { + $list = array(); - if (!is_array ($listDAO)) { - $listDAO = array ($listDAO); + if (!is_array($listDAO)) { + $listDAO = array($listDAO); } $previousLine = null; @@ -210,11 +210,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { foreach ($listDAO as $line) { if ($previousLine['c_id'] != null && $line['c_id'] !== $previousLine['c_id']) { // End of the current category, we add it to the $list - $cat = new FreshRSS_Category ( + $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) ); - $cat->_id ($previousLine['c_id']); + $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; $feedsDao = array(); //Prepare for next category @@ -226,29 +226,29 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { // add the last category if ($previousLine != null) { - $cat = new FreshRSS_Category ( + $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id']) + FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) ); - $cat->_id ($previousLine['c_id']); + $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; } return $list; } - public static function daoToCategory ($listDAO) { - $list = array (); + public static function daoToCategory($listDAO) { + $list = array(); - if (!is_array ($listDAO)) { - $listDAO = array ($listDAO); + if (!is_array($listDAO)) { + $listDAO = array($listDAO); } foreach ($listDAO as $key => $dao) { - $cat = new FreshRSS_Category ( + $cat = new FreshRSS_Category( $dao['name'] ); - $cat->_id ($dao['id']); + $cat->_id($dao['id']); $list[$key] = $cat; } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index feba3d2f6..2f208e509 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -140,18 +140,18 @@ class FreshRSS_Configuration { } $this->data['language'] = $value; } - public function _posts_per_page ($value) { + public function _posts_per_page($value) { $value = intval($value); $this->data['posts_per_page'] = $value > 0 ? $value : 10; } - public function _view_mode ($value) { + public function _view_mode($value) { if ($value === 'global' || $value === 'reader') { $this->data['view_mode'] = $value; } else { $this->data['view_mode'] = 'normal'; } } - public function _default_view ($value) { + public function _default_view($value) { switch ($value) { case FreshRSS_Entry::STATE_ALL: // left blank on purpose @@ -165,19 +165,19 @@ class FreshRSS_Configuration { break; } } - public function _display_posts ($value) { + public function _display_posts($value) { $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; } - public function _display_categories ($value) { + public function _display_categories($value) { $this->data['display_categories'] = ((bool)$value) && $value !== 'no'; } public function _hide_read_feeds($value) { $this->data['hide_read_feeds'] = (bool)$value; } - public function _onread_jump_next ($value) { + public function _onread_jump_next($value) { $this->data['onread_jump_next'] = ((bool)$value) && $value !== 'no'; } - public function _lazyload ($value) { + public function _lazyload($value) { $this->data['lazyload'] = ((bool)$value) && $value !== 'no'; } public function _sticky_post($value) { @@ -186,7 +186,7 @@ class FreshRSS_Configuration { public function _reading_confirm($value) { $this->data['reading_confirm'] = ((bool)$value) && $value !== 'no'; } - public function _sort_order ($value) { + public function _sort_order($value) { $this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; } public function _old_entries($value) { @@ -201,20 +201,20 @@ class FreshRSS_Configuration { $value = intval($value); $this->data['ttl_default'] = $value >= -1 ? $value : 3600; } - public function _shortcuts ($values) { + public function _shortcuts($values) { foreach ($values as $key => $value) { if (isset($this->data['shortcuts'][$key])) { $this->data['shortcuts'][$key] = $value; } } } - public function _passwordHash ($value) { + public function _passwordHash($value) { $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; } - public function _apiPasswordHash ($value) { + public function _apiPasswordHash($value) { $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; } - public function _mail_login ($value) { + public function _mail_login($value) { $value = filter_var($value, FILTER_VALIDATE_EMAIL); if ($value) { $this->data['mail_login'] = $value; @@ -222,17 +222,17 @@ class FreshRSS_Configuration { $this->data['mail_login'] = ''; } } - public function _anon_access ($value) { + public function _anon_access($value) { $this->data['anon_access'] = ((bool)$value) && $value !== 'no'; } - public function _mark_when ($values) { + public function _mark_when($values) { foreach ($values as $key => $value) { if (isset($this->data['mark_when'][$key])) { $this->data['mark_when'][$key] = ((bool)$value) && $value !== 'no'; } } } - public function _sharing ($values) { + public function _sharing($values) { $this->data['sharing'] = array(); $unique = array(); foreach ($values as $value) { @@ -243,7 +243,7 @@ class FreshRSS_Configuration { // Verify URL and add default value when needed if (isset($value['url'])) { $is_url = ( - filter_var ($value['url'], FILTER_VALIDATE_URL) || + filter_var($value['url'], FILTER_VALIDATE_URL) || (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && ($value === filter_var($value, FILTER_SANITIZE_URL))) @@ -267,7 +267,7 @@ class FreshRSS_Configuration { } } } - public function _queries ($values) { + public function _queries($values) { $this->data['queries'] = array(); foreach ($values as $value) { $value = array_filter($value); @@ -292,7 +292,7 @@ class FreshRSS_Configuration { } } - public function _html5_notif_timeout ($value) { + public function _html5_notif_timeout($value) { $value = intval($value); $this->data['html5_notif_timeout'] = $value >= 0 ? $value : 0; } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 9d7dd5dc4..ee94d1110 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -20,134 +20,134 @@ class FreshRSS_Entry extends Minz_Model { private $feed; private $tags; - public function __construct ($feed = '', $guid = '', $title = '', $author = '', $content = '', - $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { - $this->_guid ($guid); - $this->_title ($title); - $this->_author ($author); - $this->_content ($content); - $this->_link ($link); - $this->_date ($pubdate); - $this->_isRead ($is_read); - $this->_isFavorite ($is_favorite); - $this->_feed ($feed); - $this->_tags (preg_split('/[\s#]/', $tags)); + public function __construct($feed = '', $guid = '', $title = '', $author = '', $content = '', + $link = '', $pubdate = 0, $is_read = false, $is_favorite = false, $tags = '') { + $this->_guid($guid); + $this->_title($title); + $this->_author($author); + $this->_content($content); + $this->_link($link); + $this->_date($pubdate); + $this->_isRead($is_read); + $this->_isFavorite($is_favorite); + $this->_feed($feed); + $this->_tags(preg_split('/[\s#]/', $tags)); } - public function id () { + public function id() { return $this->id; } - public function guid () { + public function guid() { return $this->guid; } - public function title () { + public function title() { return $this->title; } - public function author () { + public function author() { return $this->author === null ? '' : $this->author; } - public function content () { + public function content() { return $this->content; } - public function link () { + public function link() { return $this->link; } - public function date ($raw = false) { + public function date($raw = false) { if ($raw) { return $this->date; } else { - return timestamptodate ($this->date); + return timestamptodate($this->date); } } - public function dateAdded ($raw = false) { + public function dateAdded($raw = false) { $date = intval(substr($this->id, 0, -6)); if ($raw) { return $date; } else { - return timestamptodate ($date); + return timestamptodate($date); } } - public function isRead () { + public function isRead() { return $this->is_read; } - public function isFavorite () { + public function isFavorite() { return $this->is_favorite; } - public function feed ($object = false) { + public function feed($object = false) { if ($object) { $feedDAO = FreshRSS_Factory::createFeedDao(); - return $feedDAO->searchById ($this->feed); + return $feedDAO->searchById($this->feed); } else { return $this->feed; } } - public function tags ($inString = false) { + public function tags($inString = false) { if ($inString) { - return empty ($this->tags) ? '' : '#' . implode(' #', $this->tags); + return empty($this->tags) ? '' : '#' . implode(' #', $this->tags); } else { return $this->tags; } } - public function _id ($value) { + public function _id($value) { $this->id = $value; } - public function _guid ($value) { + public function _guid($value) { $this->guid = $value; } - public function _title ($value) { + public function _title($value) { $this->title = $value; } - public function _author ($value) { + public function _author($value) { $this->author = $value; } - public function _content ($value) { + public function _content($value) { $this->content = $value; } - public function _link ($value) { + public function _link($value) { $this->link = $value; } - public function _date ($value) { + public function _date($value) { $value = intval($value); $this->date = $value > 1 ? $value : time(); } - public function _isRead ($value) { + public function _isRead($value) { $this->is_read = $value; } - public function _isFavorite ($value) { + public function _isFavorite($value) { $this->is_favorite = $value; } - public function _feed ($value) { + public function _feed($value) { $this->feed = $value; } - public function _tags ($value) { - if (!is_array ($value)) { - $value = array ($value); + public function _tags($value) { + if (!is_array($value)) { + $value = array($value); } foreach ($value as $key => $t) { if (!$t) { - unset ($value[$key]); + unset($value[$key]); } } $this->tags = $value; } - public function isDay ($day, $today) { + public function isDay($day, $today) { $date = $this->dateAdded(true); switch ($day) { - case FreshRSS_Days::TODAY: - $tomorrow = $today + 86400; - return $date >= $today && $date < $tomorrow; - case FreshRSS_Days::YESTERDAY: - $yesterday = $today - 86400; - return $date >= $yesterday && $date < $today; - case FreshRSS_Days::BEFORE_YESTERDAY: - $yesterday = $today - 86400; - return $date < $yesterday; - default: - return false; + case FreshRSS_Days::TODAY: + $tomorrow = $today + 86400; + return $date >= $today && $date < $tomorrow; + case FreshRSS_Days::YESTERDAY: + $yesterday = $today - 86400; + return $date >= $yesterday && $date < $today; + case FreshRSS_Days::BEFORE_YESTERDAY: + $yesterday = $today - 86400; + return $date < $yesterday; + default: + return false; } } @@ -158,7 +158,7 @@ class FreshRSS_Entry extends Minz_Model { $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $entryDAO->searchByGuid($this->feed, $this->guid); - if($entry) { + if ($entry) { // l'article existe déjà en BDD, en se contente de recharger ce contenu $this->content = $entry->content(); } else { @@ -168,25 +168,25 @@ class FreshRSS_Entry extends Minz_Model { htmlspecialchars_decode($this->link(), ENT_QUOTES), $pathEntries ); } catch (Exception $e) { - // rien à faire, on garde l'ancien contenu (requête a échoué) + // rien à faire, on garde l'ancien contenu(requête a échoué) } } } } - public function toArray () { - return array ( - 'id' => $this->id (), - 'guid' => $this->guid (), - 'title' => $this->title (), - 'author' => $this->author (), - 'content' => $this->content (), - 'link' => $this->link (), - 'date' => $this->date (true), - 'is_read' => $this->isRead (), - 'is_favorite' => $this->isFavorite (), - 'id_feed' => $this->feed (), - 'tags' => $this->tags (true), + public function toArray() { + return array( + 'id' => $this->id(), + 'guid' => $this->guid(), + 'title' => $this->title(), + 'author' => $this->author(), + 'content' => $this->content(), + 'link' => $this->link(), + 'date' => $this->date(true), + 'is_read' => $this->isRead(), + 'is_favorite' => $this->isFavorite(), + 'id_feed' => $this->feed(), + 'tags' => $this->tags(true), ); } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 751ee6da7..34717123c 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -307,27 +307,27 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $joinFeed = false; $values = array(); switch ($type) { - case 'a': - $where .= 'f.priority > 0 '; - $joinFeed = true; - break; - case 's': //Deprecated: use $state instead - $where .= 'e1.is_favorite=1 '; - break; - case 'c': - $where .= 'f.category=? '; - $values[] = intval($id); - $joinFeed = true; - break; - case 'f': - $where .= 'e1.id_feed=? '; - $values[] = intval($id); - break; - case 'A': - $where .= '1 '; - break; - default: - throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); + case 'a': + $where .= 'f.priority > 0 '; + $joinFeed = true; + break; + case 's': //Deprecated: use $state instead + $where .= 'e1.is_favorite=1 '; + break; + case 'c': + $where .= 'f.category=? '; + $values[] = intval($id); + $joinFeed = true; + break; + case 'f': + $where .= 'e1.id_feed=? '; + $values[] = intval($id); + break; + case 'A': + $where .= '1 '; + break; + default: + throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); } if ($state & FreshRSS_Entry::STATE_NOT_READ) { diff --git a/app/Models/Log.php b/app/Models/Log.php index d2794458b..df2de72ac 100644 --- a/app/Models/Log.php +++ b/app/Models/Log.php @@ -5,22 +5,22 @@ class FreshRSS_Log extends Minz_Model { private $level; private $information; - public function date () { + public function date() { return $this->date; } - public function level () { + public function level() { return $this->level; } - public function info () { + public function info() { return $this->information; } - public function _date ($date) { + public function _date($date) { $this->date = $date; } - public function _level ($level) { + public function _level($level) { $this->level = $level; } - public function _info ($information) { + public function _info($information) { $this->information = $information; } } diff --git a/app/Models/LogDAO.php b/app/Models/LogDAO.php index d1e515200..21593435d 100644 --- a/app/Models/LogDAO.php +++ b/app/Models/LogDAO.php @@ -2,15 +2,15 @@ class FreshRSS_LogDAO { public static function lines() { - $logs = array (); + $logs = array(); $handle = @fopen(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log', 'r'); if ($handle) { while (($line = fgets($handle)) !== false) { - if (preg_match ('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) { + if (preg_match('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) { $myLog = new FreshRSS_Log (); - $myLog->_date ($matches[1]); - $myLog->_level ($matches[2]); - $myLog->_info ($matches[3]); + $myLog->_date($matches[1]); + $myLog->_level($matches[2]); + $myLog->_info($matches[3]); $logs[] = $myLog; } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 113944508..99d4e2148 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -415,7 +415,7 @@ SQL; * @return string */ private function convertToTranslatedJson($data = array()) { - $translated = array_map(function ($a) { + $translated = array_map(function($a) { return _t($a); }, $data); -- cgit v1.2.3 From eb40dbccdb1e0830fcad96d333b242870cc0d0a7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 9 Oct 2014 21:44:44 -0400 Subject: Change statistic average I was using the stats and it feels that the stat average was useless in that form since the line is always at the same position no matter what is the value. So I deleted that line and added the average in the title. It is way more useful this way. I updated some translations both on i18n files and on http://i18n.freshrss.org --- app/Models/StatsDAO.php | 2 +- app/i18n/en.php | 6 +++--- app/i18n/fr.php | 6 +++--- app/views/stats/repartition.phtml | 36 +++--------------------------------- 4 files changed, 10 insertions(+), 40 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 99d4e2148..283d5dcb1 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -237,7 +237,7 @@ SQL; $interval_in_days = $period; } - return round($res['count'] / ($interval_in_days / $period), 2); + return $res['count'] / ($interval_in_days / $period); } /** diff --git a/app/i18n/en.php b/app/i18n/en.php index 9e968998a..ebc25ba0c 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Entry count', 'stats_entry_per_category' => 'Entries per category', 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week', - 'stats_entry_per_hour' => 'Per hour', - 'stats_entry_per_month' => 'Per month', + 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', + 'stats_entry_per_month' => 'Per month (average: %.2f messages)', 'stats_entry_repartition' => 'Entries repartition', 'stats_feed_per_category' => 'Feeds per category', 'stats_idle' => 'Idle feeds', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 072094026..220f8b12d 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Nombre d’articles', 'stats_entry_per_category' => 'Articles par catégorie', 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine', - 'stats_entry_per_hour' => 'Par heure', - 'stats_entry_per_month' => 'Par mois', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', 'stats_entry_repartition' => 'Répartition des articles', 'stats_feed_per_category' => 'Flux par catégorie', 'stats_idle' => 'Flux inactifs', diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index a181ae251..670714707 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -30,17 +30,17 @@
    -

    +

    averageHour); ?>

    -

    +

    averageDayOfWeek); ?>

    -

    +

    averageMonth); ?>

    @@ -56,19 +56,10 @@ function initStats() { return; } // Entry per hour - var avg_h = []; - for (var i = -1; i <= 24; i++) { - avg_h.push([i, averageHour?>]); - } Flotr.draw(document.getElementById('statsEntryPerHour'), [{ data: repartitionHour ?>, bars: {horizontal: false, show: true} - }, { - data: avg_h, - lines: {show: true}, - label: "averageHour?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -81,23 +72,13 @@ function initStats() { max: 23.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per day of week - var avg_dow = []; - for (var i = -1; i <= 7; i++) { - avg_dow.push([i, averageDayOfWeek?>]); - } Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'), [{ data: repartitionDayOfWeek ?>, bars: {horizontal: false, show: true} - }, { - data: avg_dow, - lines: {show: true}, - label: "averageDayOfWeek?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -111,23 +92,13 @@ function initStats() { max: 6.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per month - var avg_m = []; - for (var i = 0; i <= 13; i++) { - avg_m.push([i, averageMonth?>]); - } Flotr.draw(document.getElementById('statsEntryPerMonth'), [{ data: repartitionMonth ?>, bars: {horizontal: false, show: true} - }, { - data: avg_m, - lines: {show: true}, - label: "averageMonth?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -141,7 +112,6 @@ function initStats() { max: 12.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From 38cf7a109ee80cc03edfd420b641676ecd1dfae6 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 8 Nov 2014 09:26:01 -0500 Subject: Add more info in article repartition page I added the same information than on the main stat page (total, read, unread and favorite) on the repartition page. Some refactoring was needed. --- app/Controllers/statsController.php | 1 + app/Models/StatsDAO.php | 48 ++++++++++++++++++++----------------- app/views/stats/repartition.phtml | 17 +++++++++++++ 3 files changed, 44 insertions(+), 22 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 18fbca6df..578df9434 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -117,6 +117,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->feed = $feedDAO->searchById($id); $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); + $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id); $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 283d5dcb1..0ca251228 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -6,18 +6,36 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { /** * Calculates entry repartition for all feeds and for main stream. + * + * @return array + */ + public function calculateEntryRepartition() { + return array( + 'main_stream' => $this->calculateEntryRepartitionPerFeed(null, true), + 'all_feeds' => $this->calculateEntryRepartitionPerFeed(null, false), + ); + } + + /** + * Calculates entry repartition for the selection. * The repartition includes: * - total entries * - read entries * - unread entries * - favorite entries * - * @return type + * @param null|integer $feed feed id + * @param boolean $only_main + * @return array */ - public function calculateEntryRepartition() { - $repartition = array(); - - // Generates the repartition for the main stream of entry + public function calculateEntryRepartitionPerFeed($feed = null, $only_main = false) { + $filter = ''; + if ($only_main) { + $filter .= 'AND f.priority = 10'; + } + if (!is_null($feed)) { + $filter .= "AND e.id_feed = {$feed}"; + } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id -AND f.priority = 10 -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['main_stream'] = $res[0]; - - // Generates the repartition for all entries - $sql = <<prefix}entry AS e +{$filter} SQL; $stm = $this->bd->prepare($sql); $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['all_feeds'] = $res[0]; - return $repartition; + return $res[0]; } /** @@ -179,7 +183,7 @@ SQL; * @return integer */ public function calculateEntryAveragePerFeedPerHour($feed = null) { - return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); + return $this->calculateEntryAveragePerFeedPerPeriod(1 / 24, $feed); } /** diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 32268a546..85a750bd0 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -29,6 +29,23 @@ +
    +
     
    conf->topline_read ? ' checked="checked"' : ''; ?> /> conf->topline_favorite ? ' checked="checked"' : ''; ?> /> conf->topline_date ? ' checked="checked"' : ''; ?> /> conf->topline_link ? ' checked="checked"' : ''; ?> />
    conf->bottomline_read ? ' checked="checked"' : ''; ?> /> conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /> conf->bottomline_sharing ? ' checked="checked"' : ''; ?> />
    + + + + + + + + + + + + +
    repartition['total']; ?>repartition['read']; ?>repartition['unread']; ?>repartition['favorite']; ?>
    +
    +

    averageHour); ?>

    -- cgit v1.2.3 From 960abfcc6558d8421423a42b7781184dad0d9bc7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 8 Nov 2014 09:29:51 -0500 Subject: Refactor some if statements --- app/Models/StatsDAO.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 0ca251228..255a2b1ff 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -151,10 +151,9 @@ SQL; * @return string */ protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + $restrict = ''; if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; - } else { - $restrict = ''; } $sql = << Date: Thu, 11 Dec 2014 16:10:39 +0100 Subject: Update i18n for statistics --- app/Controllers/statsController.php | 2 +- app/Models/StatsDAO.php | 2 +- app/i18n/en/admin.php | 27 +++++++++++ app/i18n/en/gen.php | 88 +++++++++++++++--------------------- app/i18n/fr/admin.php | 27 +++++++++++ app/i18n/fr/gen.php | 89 +++++++++++++++---------------------- app/layout/aside_stats.phtml | 6 +-- app/views/stats/idle.phtml | 16 +++---- app/views/stats/index.phtml | 34 +++++++------- app/views/stats/repartition.phtml | 22 ++++----- 10 files changed, 167 insertions(+), 146 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 578df9434..4a597ae7d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -15,7 +15,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { Minz_Error::error(403); } - Minz_View::prependTitle(_t('stats') . ' · '); + Minz_View::prependTitle(_t('admin.stats.title') . ' · '); } /** diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 255a2b1ff..80caccc49 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -418,7 +418,7 @@ SQL; */ private function convertToTranslatedJson($data = array()) { $translated = array_map(function($a) { - return _t($a); + return _t('gen.date.' . $a); }, $data); return json_encode($translated); diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index cf8d8bd00..3ac36a914 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -87,9 +87,36 @@ return array( ), ), 'stats' => array( + '_' => 'Statistics', + 'all_feeds' => 'All feeds', + 'category' => 'Category', + 'entry_count' => 'Entry count', + 'entry_per_category' => 'Entries per category', + 'entry_per_day' => 'Entries per day (last 30 days)', + 'entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'entry_per_hour' => 'Per hour (average: %.2f messages)', + 'entry_per_month' => 'Per month (average: %.2f messages)', + 'entry_repartition' => 'Entries repartition', + 'feed' => 'Feed', + 'feed_per_category' => 'Feeds per category', 'idle' => 'Idle feeds', 'main' => 'Main statistics', + 'main_stream' => 'Main stream', + 'menu' => array( + 'idle' => 'Idle feeds', + 'main' => 'Main statistics', + 'repartition' => 'Articles repartition', + ), + 'no_idle' => 'There is no idle feed!', + 'number_articles' => '%d articles', + 'percent_of_total' => '%% of total', 'repartition' => 'Articles repartition', + 'status_favorites' => 'Favourites', + 'status_read' => 'Read', + 'status_total' => 'Total', + 'status_unread' => 'Unread', + 'title' => 'Statistics', + 'top_feed' => 'Top ten feeds', ), 'users' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 18e63a335..17fef12c7 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -5,6 +5,7 @@ return array( 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'disable' => 'Disable', 'enable' => 'Enable', + 'filter' => 'Filtrer', 'manage' => 'Manage', 'remove' => 'Remove', ), @@ -25,10 +26,45 @@ return array( 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'apr' => 'apr', + 'april' => 'Apr', + 'aug' => 'aug', + 'august' => 'Aug', 'before_yesterday' => 'Before yesterday', + 'dec' => 'dec', + 'december' => 'Dec', + 'feb' => 'feb', + 'february' => 'Feb', 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'fri' => 'Fri', + 'jan' => 'jan', + 'january' => 'Jan', + 'jul' => 'jul', + 'july' => 'Jul', + 'jun' => 'jun', + 'june' => 'Jun', + 'last_3_month' => 'Last three months', + 'last_6_month' => 'Last six months', + 'last_month' => 'Last month', + 'last_week' => 'Last week', + 'last_year' => 'Last year', + 'mar' => 'mar', + 'march' => 'Mar', + 'may' => 'May', + 'mon' => 'Mon', + 'nov' => 'nov', + 'november' => 'Nov', + 'oct' => 'oct', + 'october' => 'Oct', + 'sat' => 'Sat', + 'sep' => 'sep', + 'september' => 'Sep', + 'sun' => 'Sun', + 'thu' => 'Thu', 'today' => 'Today', + 'tue' => 'Tue', + 'wed' => 'Wed', 'yesterday' => 'Yesterday', ), 'js' => array( @@ -83,13 +119,10 @@ return array( 'administration' => 'Manage', 'advanced' => 'Advanced', 'after_onread' => 'After “mark all as read”,', - 'all_feeds' => 'All feeds', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', 'already_subscribed' => 'You have already subscribed to %s', 'api_enabled' => 'Allow API access (required for mobile apps)', - 'apr' => 'apr', - 'april' => 'Apr', 'archiving_configuration_help' => 'More options are available in the individual stream settings', 'article' => 'Article', 'article_icons' => 'Article icons', @@ -102,8 +135,6 @@ return array( 'articles_to_display' => 'Articles to display', 'ask_empty' => 'Clear?', 'attention' => 'Attention!', - 'aug' => 'aug', - 'august' => 'Aug', 'auth_form' => 'Web form (traditional, requires JavaScript)', 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', 'auth_form_set' => 'Form is now your default authentication system.', @@ -169,8 +200,6 @@ return array( 'current_user' => 'Current user', 'damn' => 'Damn!', 'data_is_ok' => 'Permissions on data directory are good', - 'dec' => 'dec', - 'december' => 'Dec', 'default_category' => 'Uncategorized', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', 'default_view' => 'Default view', @@ -190,8 +219,6 @@ return array( 'export_opml' => 'Export list of feeds (OPML)', 'export_starred' => 'Export your favourites', 'favicons_is_ok' => 'Permissions on favicons directory are good', - 'feb' => 'feb', - 'february' => 'Feb', 'feed' => 'Feed', 'feed_actualized' => '%s has been updated', 'feed_added' => 'RSS feed %s has been added', @@ -219,7 +246,6 @@ return array( 'fix_errors_before' => 'Fix errors before skip to the next step.', 'focus_search' => 'Access search box', 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'Fri', 'general_conf_is_ok' => 'General configuration has been saved.', 'general_configuration' => 'General configuration', 'help' => 'Display documentation', @@ -242,40 +268,25 @@ return array( 'invalid_login' => 'Login is invalid', 'invalid_url' => 'URL %s is invalid', 'is_admin' => 'is administrator', - 'jan' => 'jan', - 'january' => 'Jan', 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_should_be_activated' => 'JavaScript must be enabled', - 'jul' => 'jul', - 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', - 'jun' => 'jun', - 'june' => 'Jun', 'keep_history' => 'Minimum number of articles to keep', 'keep_logged_in' => 'Keep me logged in (1 month)', 'language' => 'Language', 'language_defined' => 'Language has been defined.', - 'last_3_month' => 'Last three months', - 'last_6_month' => 'Last six months', 'last_article' => 'Skip to the last article', - 'last_month' => 'Last month', - 'last_week' => 'Last week', - 'last_year' => 'Last year', 'log_is_ok' => 'Permissions on logs directory are good', 'login_configuration' => 'Login', 'login_persona_problem' => 'Connection problem with Persona?', 'login_required' => 'Login required:', 'login_with_persona' => 'Login with Persona', - 'mar' => 'mar', - 'march' => 'Mar', 'mark_cat_read' => 'Mark category as read', 'mark_favorite' => 'Mark as favourite', 'mark_feed_read' => 'Mark feed as read', - 'may' => 'May', 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'minz_is_ok' => 'You have the Minz framework', - 'mon' => 'Mon', 'month' => 'months', 'more_information' => 'More information', 'n_entries_deleted' => '%d articles have been deleted', @@ -296,13 +307,8 @@ return array( 'not_read' => '%d unread', 'not_reads' => '%d unread', 'not_yet_implemented' => 'Not yet implemented', - 'nov' => 'nov', - 'november' => 'Nov', - 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divided by 2 in the reading view.', 'number_feeds' => '%d feeds', - 'oct' => 'oct', - 'october' => 'Oct', 'ok' => 'Ok!', 'oops' => 'Oops!', 'optimization_complete' => 'Optimization complete', @@ -360,13 +366,10 @@ return array( 'refresh' => 'Refresh', 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', 'rss_feed_management' => 'RSS feeds management', - 'sat' => 'Sat', 'save' => 'Save', 'scroll' => 'while scrolling', 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'see_on_website' => 'See on original website', - 'sep' => 'sep', - 'september' => 'Sep', 'share_name' => 'Share name to display', 'share_url' => 'Share URL to use', 'sharing_management' => 'Sharing options management', @@ -381,32 +384,14 @@ return array( 'show_in_all_flux' => 'Show in main stream', 'sort_order' => 'Sort order', 'starred_list' => 'List of favourite articles', - 'stats_entry_count' => 'Entry count', - 'stats_entry_per_category' => 'Entries per category', - 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', - 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', - 'stats_entry_per_month' => 'Per month (average: %.2f messages)', - 'stats_entry_repartition' => 'Entries repartition', - 'stats_feed_per_category' => 'Feeds per category', - 'stats_no_idle' => 'There is no idle feed!', - 'stats_percent_of_total' => '%% of total', - 'stats_top_feed' => 'Top ten feeds', - 'status_favorites' => 'Favourites', - 'status_read' => 'Read', - 'status_total' => 'Total', - 'status_unread' => 'Unread', 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', 'submit' => 'Submit', - 'sun' => 'Sun', 'theme' => 'Theme', 'this_is_the_end' => 'This is the end', - 'thu' => 'Thu', 'top_line' => 'Top line', 'truncate' => 'Delete all articles', 'ttl' => 'Do not automatically refresh more often than', - 'tue' => 'Tue', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', 'update_apply' => 'Apply', 'update_can_apply' => 'An update is available.', @@ -431,7 +416,6 @@ return array( 'users_list' => 'List of users', 'version_update' => 'Update', 'website_url' => 'Website URL', - 'wed' => 'Wed', 'width_large' => 'Large', 'width_medium' => 'Medium', 'width_no_limit' => 'No limit', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index 3d7201439..1e9eb03af 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -87,9 +87,36 @@ return array( ), ), 'stats' => array( + '_' => 'Statistiques', + 'all_feeds' => 'Tous les flux', + 'category' => 'Catégorie', + 'entry_count' => 'Nombre d’articles', + 'entry_per_category' => 'Articles par catégorie', + 'entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', + 'entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'entry_per_month' => 'Par mois (moyenne : %.2f messages)', + 'entry_repartition' => 'Répartition des articles', + 'feed' => 'Flux', + 'feed_per_category' => 'Flux par catégorie', 'idle' => 'Flux inactifs', 'main' => 'Statistiques principales', + 'main_stream' => 'Flux principal', + 'menu' => array( + 'idle' => 'Flux inactifs', + 'main' => 'Statistiques principales', + 'repartition' => 'Répartition des articles', + ), + 'no_idle' => 'Il n’y a aucun flux inactif !', + 'number_articles' => '%d articles', + 'percent_of_total' => '%% du total', 'repartition' => 'Répartition des articles', + 'status_favorites' => 'favoris', + 'status_read' => 'lus', + 'status_total' => 'total', + 'status_unread' => 'non lus', + 'title' => 'Statistiques', + 'top_feed' => 'Les dix plus gros flux', ), 'users' => array( 'articles_and_size' => '%s articles (%s)', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index e7c1c0d09..af595c20b 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -5,6 +5,7 @@ return array( 'back_to_rss_feeds' => '← Retour à vos flux RSS', 'disable' => 'Désactiver', 'enable' => 'Activer', + 'filter' => 'Filtrer', 'manage' => 'Gérer', 'remove' => 'Supprimer', ), @@ -25,10 +26,45 @@ return array( 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'apr' => 'avr.', + 'april' => 'avril', + 'aug' => 'août', + 'august' => 'août', 'before_yesterday' => 'À partir d’avant-hier', + 'dec' => 'déc.', + 'december' => 'décembre', + 'feb' => 'fév.', + 'february' => 'février', + 'fri' => 'ven.', + 'jan' => 'jan.', + 'january' => 'janvier', + 'jul' => 'jui.', + 'july' => 'juillet', + 'jun' => 'juin', + 'june' => 'juin', 'format_date' => 'j %s Y', 'format_date_hour' => 'j %s Y \\à H\\:i', + 'last_3_month' => 'Depuis les trois derniers mois', + 'last_6_month' => 'Depuis les six derniers mois', + 'last_month' => 'Depuis le mois dernier', + 'last_week' => 'Depuis la semaine dernière', + 'last_year' => 'Depuis l’année dernière', + 'mar' => 'mar.', + 'march' => 'mars', + 'may' => 'mai.', + 'mon' => 'lun.', + 'nov' => 'nov.', + 'november' => 'novembre', + 'oct' => 'oct.', + 'october' => 'octobre', + 'sat' => 'sam.', + 'sep' => 'sep.', + 'september' => 'septembre', + 'sun' => 'dim.', + 'thu' => 'jeu.', 'today' => 'Aujourd’hui', + 'tue' => 'mar.', + 'wed' => 'mer.', 'yesterday' => 'Hier', ), 'js' => array( @@ -71,7 +107,6 @@ return array( '_' => 'Titre', 'authentication' => 'Authentification', 'check_install' => 'Vérification de l’installation', - 'global_view' => 'Vue globale', 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', ), @@ -84,13 +119,10 @@ return array( 'administration' => 'Gérer', 'advanced' => 'Avancé', 'after_onread' => 'Après “marquer tout comme lu”,', - 'all_feeds' => 'Tous les flux', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'apr' => 'avr.', - 'april' => 'avril', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', 'article' => 'Article', 'article_icons' => 'Icônes d’article', @@ -103,8 +135,6 @@ return array( 'articles_to_display' => 'Articles à afficher', 'ask_empty' => 'Vider ?', 'attention' => 'Attention !', - 'aug' => 'août', - 'august' => 'août', 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', @@ -170,8 +200,6 @@ return array( 'current_user' => 'Utilisateur actuel', 'damn' => 'Arf !', 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'dec' => 'déc.', - 'december' => 'décembre', 'default_category' => 'Sans catégorie', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', 'default_view' => 'Vue par défaut', @@ -191,8 +219,6 @@ return array( 'export_opml' => 'Exporter la liste des flux (OPML)', 'export_starred' => 'Exporter les favoris', 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', - 'feb' => 'fév.', - 'february' => 'février', 'feed' => 'Flux', 'feed_actualized' => '%s a été mis à jour.', 'feed_added' => 'Le flux %s a bien été ajouté.', @@ -220,7 +246,6 @@ return array( 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', 'focus_search' => 'Accéder à la recherche', 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'ven.', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'general_configuration' => 'Configuration générale', 'help' => 'Afficher la documentation', @@ -243,40 +268,25 @@ return array( 'invalid_login' => 'L’identifiant est invalide !', 'invalid_url' => 'L’url %s est invalide.', 'is_admin' => 'est administrateur', - 'jan' => 'jan.', - 'january' => 'janvier', 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', - 'jul' => 'jui.', - 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'jun' => 'juin', - 'june' => 'juin', 'keep_history' => 'Nombre minimum d’articles à conserver', 'keep_logged_in' => 'Rester connecté (1 mois)', 'language' => 'Langue', 'language_defined' => 'La langue a bien été définie.', - 'last_3_month' => 'Depuis les trois derniers mois', - 'last_6_month' => 'Depuis les six derniers mois', 'last_article' => 'Passer au dernier article', - 'last_month' => 'Depuis le mois dernier', - 'last_week' => 'Depuis la semaine dernière', - 'last_year' => 'Depuis l’année dernière', 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'login_configuration' => 'Identification', 'login_persona_problem' => 'Problème de connexion à Persona ?', 'login_required' => 'Accès protégé par mot de passe :', 'login_with_persona' => 'Connexion avec Persona', - 'mar' => 'mar.', - 'march' => 'mars', 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_favorite' => 'Mettre en favori', 'mark_feed_read' => 'Marquer le flux comme lu', - 'may' => 'mai.', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'minz_is_ok' => 'Vous disposez du framework Minz', - 'mon' => 'lun.', 'month' => 'mois', 'more_information' => 'Plus d’informations', 'n_entries_deleted' => '%d articles ont été supprimés.', @@ -297,13 +307,8 @@ return array( 'not_read' => '%d non lu', 'not_reads' => '%d non lus', 'not_yet_implemented' => 'Pas encore implémenté', - 'nov' => 'nov.', - 'november' => 'novembre', - 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', 'number_feeds' => '%d flux', - 'oct' => 'oct.', - 'october' => 'octobre', 'ok' => 'Ok !', 'oops' => 'Oups !', 'optimization_complete' => 'Optimisation terminée.', @@ -361,13 +366,10 @@ return array( 'refresh' => 'Actualisation', 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', 'rss_feed_management' => 'Gestion des flux RSS', - 'sat' => 'sam.', 'save' => 'Enregistrer', 'scroll' => 'au défilement de la page', 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', 'see_on_website' => 'Voir sur le site d’origine', - 'sep' => 'sep.', - 'september' => 'septembre', 'share_name' => 'Nom du partage à afficher', 'share_url' => 'URL du partage à utiliser', 'sharing_management' => 'Gestion des options de partage', @@ -382,32 +384,14 @@ return array( 'show_in_all_flux' => 'Afficher dans le flux principal', 'sort_order' => 'Ordre de tri', 'starred_list' => 'Liste des articles favoris', - 'stats_entry_count' => 'Nombre d’articles', - 'stats_entry_per_category' => 'Articles par catégorie', - 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', - 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', - 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', - 'stats_entry_repartition' => 'Répartition des articles', - 'stats_feed_per_category' => 'Flux par catégorie', - 'stats_no_idle' => 'Il n’y a aucun flux inactif !', - 'stats_percent_of_total' => '%% du total', - 'stats_top_feed' => 'Les dix plus gros flux', - 'status_favorites' => 'favoris', - 'status_read' => 'lus', - 'status_total' => 'total', - 'status_unread' => 'non lus', 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', 'submit' => 'Valider', - 'sun' => 'dim.', 'theme' => 'Thème', 'this_is_the_end' => 'This is the end', - 'thu' => 'jeu.', 'top_line' => 'Ligne du haut', 'truncate' => 'Supprimer tous les articles', 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', - 'tue' => 'mar.', 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', 'update_apply' => 'Appliquer la mise à jour', 'update_can_apply' => 'Une mise à jour est disponible.', @@ -432,7 +416,6 @@ return array( 'users_list' => 'Liste des utilisateurs', 'version_update' => 'Mise à jour', 'website_url' => 'URL du site', - 'wed' => 'mer.', 'width_large' => 'Large', 'width_medium' => 'Moyenne', 'width_no_limit' => 'Pas de limite', diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index 559087df1..4bdaf7165 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -1,12 +1,12 @@ diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 75cba1081..bfee4366c 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -1,9 +1,9 @@ partial('aside_stats'); ?>
    - + -

    +

    -

    +

    @@ -24,13 +24,13 @@
    • - - - + + +
    • - () + ()
    @@ -42,7 +42,7 @@ if ($nothing) { ?>

    - +

    diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 1300cb2c7..c13c5d26c 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -1,38 +1,38 @@ partial('aside_stats'); ?>
    - + -

    +

    -

    +

    - - + + - + - + - + - + @@ -41,14 +41,14 @@
    -

    +

     
    repartition['main_stream']['total']); ?> repartition['all_feeds']['total']); ?>
    repartition['main_stream']['read']); ?> repartition['all_feeds']['read']); ?>
    repartition['main_stream']['unread']); ?> repartition['all_feeds']['unread']); ?>
    repartition['main_stream']['favorite']); ?> repartition['all_feeds']['favorite']); ?>
    - - - - + + + + @@ -65,18 +65,18 @@
    -

    +

    -

    +

    -

    +

    diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 4ea71cfb5..b20d9bbd0 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -1,12 +1,12 @@ partial('aside_stats'); ?>
    - + -

    +

    - - - - + + + + @@ -47,17 +47,17 @@
    -

    averageHour); ?>

    +

    averageHour); ?>

    -

    averageDayOfWeek); ?>

    +

    averageDayOfWeek); ?>

    -

    averageMonth); ?>

    +

    averageMonth); ?>

    -- cgit v1.2.3 From 264d05297c72e87b114a8e930db7eae7affe5690 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 21 Feb 2016 17:26:37 +0100 Subject: CSP for statistics https://github.com/FreshRSS/FreshRSS/issues/1075 --- app/Models/StatsDAO.php | 20 ++++---- app/Models/StatsDAOSQLite.php | 4 +- app/views/stats/index.phtml | 64 ++++------------------- app/views/stats/repartition.phtml | 103 ++++++++------------------------------ p/scripts/repartition.js | 72 ++++++++++++++++++++++++++ p/scripts/stats.js | 56 +++++++++++++++++++++ 6 files changed, 169 insertions(+), 150 deletions(-) create mode 100644 p/scripts/repartition.js create mode 100644 p/scripts/stats.js (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 80caccc49..5ca333396 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -55,9 +55,9 @@ SQL; /** * Calculates entry count per day on a 30 days period. - * Returns the result as a JSON string. + * Returns the result as a JSON object. * - * @return string + * @return JSON object */ public function calculateEntryCount() { $count = $this->initEntryCountArray(); @@ -257,9 +257,9 @@ SQL; /** * Calculates feed count per category. - * Returns the result as a JSON string. + * Returns the result as a JSON object. * - * @return string + * @return JSON object */ public function calculateFeedByCategory() { $sql = <<initEntryCountArray(); diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 18bcd4d99..c11b88999 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -82,58 +82,12 @@ - + + diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index b20d9bbd0..980b26a3d 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -30,20 +30,20 @@
    -
    repartition['total']; ?>
    +
    - - - - + + + + - - - - + + + + -
    repartition['total']; ?>repartition['read']; ?>repartition['unread']; ?>repartition['favorite']; ?>repartition['total']; ?>repartition['read']; ?>repartition['unread']; ?>repartition['favorite']; ?>
    +
    @@ -62,76 +62,13 @@
    - + + diff --git a/p/scripts/repartition.js b/p/scripts/repartition.js new file mode 100644 index 000000000..a391de2f2 --- /dev/null +++ b/p/scripts/repartition.js @@ -0,0 +1,72 @@ +"use strict"; +function initStats() { + if (!window.Flotr) { + if (window.console) { + console.log('FreshRSS waiting for Flotr…'); + } + window.setTimeout(initStats, 50); + return; + } + var jsonRepartition = document.getElementById('jsonRepartition'), + stats = JSON.parse(jsonRepartition.innerHTML); + jsonRepartition.outerHTML = ''; + // Entry per hour + Flotr.draw(document.getElementById('statsEntryPerHour'), + [{ + data: stats.repartitionHour, + bars: {horizontal: false, show: true} + }], + { + grid: {verticalLines: false}, + xaxis: {noTicks: 23, + tickFormatter: function(x) { + var x = parseInt(x); + return x + 1; + }, + min: -0.9, + max: 23.9, + tickDecimals: 0}, + yaxis: {min: 0}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} + }); + // Entry per day of week + Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'), + [{ + data: stats.repartitionDayOfWeek, + bars: {horizontal: false, show: true} + }], + { + grid: {verticalLines: false}, + xaxis: {noTicks: 6, + tickFormatter: function(x) { + var x = parseInt(x); + return stats.days[x]; + }, + min: -0.9, + max: 6.9, + tickDecimals: 0}, + yaxis: {min: 0}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} + }); + // Entry per month + Flotr.draw(document.getElementById('statsEntryPerMonth'), + [{ + data: stats.repartitionMonth, + bars: {horizontal: false, show: true} + }], + { + grid: {verticalLines: false}, + xaxis: {noTicks: 12, + tickFormatter: function(x) { + var x = parseInt(x); + return stats.months[(x - 1)]; + }, + min: 0.1, + max: 12.9, + tickDecimals: 0}, + yaxis: {min: 0}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} + }); + +} +initStats(); diff --git a/p/scripts/stats.js b/p/scripts/stats.js new file mode 100644 index 000000000..2e8ab6e27 --- /dev/null +++ b/p/scripts/stats.js @@ -0,0 +1,56 @@ +"use strict"; +function initStats() { + if (!window.Flotr) { + if (window.console) { + console.log('FreshRSS waiting for Flotr…'); + } + window.setTimeout(initStats, 50); + return; + } + var jsonStats = document.getElementById('jsonStats'), + stats = JSON.parse(jsonStats.innerHTML); + jsonStats.outerHTML = ''; + // Entry per day + var avg = []; + for (var i = -31; i <= 0; i++) { + avg.push([i, stats.average]); + } + Flotr.draw(document.getElementById('statsEntryPerDay'), + [{ + data: stats.dataCount, + bars: {horizontal: false, show: true} + },{ + data: avg, + lines: {show: true}, + label: stats.average, + }], + { + grid: {verticalLines: false}, + xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0, min: -30.75, max: -0.25}, + yaxis: {min: 0}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} + }); + // Feed per category + Flotr.draw(document.getElementById('statsFeedPerCategory'), + stats.feedByCategory, + { + grid: {verticalLines: false, horizontalLines: false}, + pie: {explode: 10, show: true, labelFormatter: function(){return '';}}, + xaxis: {showLabels: false}, + yaxis: {showLabels: false}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}}, + legend: {container: document.getElementById('statsFeedPerCategoryLegend'), noColumns: 3} + }); + // Entry per category + Flotr.draw(document.getElementById('statsEntryPerCategory'), + stats.entryByCategory, + { + grid: {verticalLines: false, horizontalLines: false}, + pie: {explode: 10, show: true, labelFormatter: function(){return '';}}, + xaxis: {showLabels: false}, + yaxis: {showLabels: false}, + mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return obj.series.label + ' - '+ numberFormat(obj.y) + ' ('+ (obj.fraction * 100).toFixed(1) + '%)';}}, + legend: {container: document.getElementById('statsEntryPerCategoryLegend'), noColumns: 3} + }); +} +initStats(); -- cgit v1.2.3 From 7c1b5e322cca0134f57b3a436129985ba9170b9f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 22:49:35 +0200 Subject: PostgreSQL draft https://github.com/FreshRSS/FreshRSS/issues/416 Based on @Damstre work https://github.com/FreshRSS/FreshRSS/pull/1071 Not tested --- app/Models/CategoryDAO.php | 7 +- app/Models/ConfigurationSetter.php | 1 + app/Models/EntryDAO.php | 2 +- app/Models/EntryDAOPGSQL.php | 92 ++++++++++++++++++ app/Models/Factory.php | 42 ++++---- app/Models/FeedDAO.php | 2 +- app/Models/StatsDAO.php | 8 +- app/Models/StatsDAOPGSQL.php | 192 +++++++++++++++++++++++++++++++++++++ app/SQL/install.sql.mysql.php | 2 + app/SQL/install.sql.pgsql.php | 91 ++++++++++++++++++ app/install.php | 31 +++++- lib/Minz/ModelPdo.php | 77 +++++++++------ p/scripts/install.js | 6 +- 13 files changed, 495 insertions(+), 58 deletions(-) create mode 100644 app/Models/EntryDAOPGSQL.php create mode 100644 app/Models/StatsDAOPGSQL.php create mode 100644 app/SQL/install.sql.pgsql.php (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index fc431553e..a44edb0f6 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -10,7 +10,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId(); + return $this->bd->lastInsertId('"' . parent::prefix . 'category_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addCategory: ' . $info[2]); @@ -207,12 +207,13 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable $previousLine = null; $feedsDao = array(); + $feedDao = FreshRSS_Factory::createFeedDAO(); foreach ($listDAO as $line) { if ($previousLine['c_id'] != null && $line['c_id'] !== $previousLine['c_id']) { // End of the current category, we add it to the $list $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) + $feedDao->daoToFeed($feedsDao, $previousLine['c_id']) ); $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; @@ -228,7 +229,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable if ($previousLine != null) { $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) + $feedDao->daoToFeed($feedsDao, $previousLine['c_id']) ); $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index e472b1e7f..988e83356 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -287,6 +287,7 @@ class FreshRSS_ConfigurationSetter { switch ($value['type']) { case 'mysql': + case 'pgsql': if (empty($value['host']) || empty($value['user']) || empty($value['base']) || diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c9e6f9742..ba52d3f15 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -3,7 +3,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function isCompressed() { - return parent::$sharedDbType !== 'sqlite'; + return parent::$sharedDbType === 'mysql'; } public function hasNativeHex() { diff --git a/app/Models/EntryDAOPGSQL.php b/app/Models/EntryDAOPGSQL.php new file mode 100644 index 000000000..95c12ff5d --- /dev/null +++ b/app/Models/EntryDAOPGSQL.php @@ -0,0 +1,92 @@ +bd->beginTransaction(); + + $sql = 'UPDATE "' . $this->prefix . 'entry" ' + . 'SET is_read=:is_read ' + . 'WHERE id_feed=:id_feed AND NOT is_read AND id <= :idmax'; + $values = array($id_feed, $idMax); + $stm = $this->bd->prepare($sql); + $stm->bindValue(':is_read', true, PDO::PARAM_BOOL); + $stm->bindValue(':id_feed', $id_feed); + $stm->bindValue(':idmax', $idMax); + + if (!($stm && $stm->execute())) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); + $this->bd->rollBack(); + return false; + } + $affected = $stm->rowCount(); + + $this->bd->commit(); + return $affected; + } + + public function listHashForFeedGuids($id_feed, $guids) { + if (count($guids) < 1) { + return array(); + } + $sql = 'SELECT guid, hash AS hexHash FROM "' . $this->prefix . 'entry" WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; + $stm = $this->bd->prepare($sql); + $values = array($id_feed); + $values = array_merge($values, $guids); + if ($stm && $stm->execute($values)) { + $result = array(); + $rows = $stm->fetchAll(PDO::FETCH_ASSOC); + foreach ($rows as $row) { + $result[$row['guid']] = $row['hexHash']; + } + return $result; + } else { + $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo(); + if ($this->autoAddColumn($info)) { + return $this->listHashForFeedGuids($id_feed, $guids); + } + Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while querying feed ' . $id_feed); + return false; + } + } + + public function optimizeTable() { + return null; + } + + public function size($all = true) { + $db = FreshRSS_Context::$system_conf->db; + $sql = 'SELECT pg_size_pretty(pg_database_size(?))'; + $values = array($db['base']); + $stm = $this->bd->prepare($sql); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } + +} diff --git a/app/Models/Factory.php b/app/Models/Factory.php index db09d155d..764987c46 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -4,37 +4,47 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_FeedDAOSQLite($username); - } else { - return new FreshRSS_FeedDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_FeedDAOSQLite($username); + default: + return new FreshRSS_FeedDAO($username); } } public static function createEntryDao($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_EntryDAOSQLite($username); - } else { - return new FreshRSS_EntryDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_EntryDAOSQLite($username); + case 'pgsql': + return new FreshRSS_EntryDAOPGSQL($username); + default: + return new FreshRSS_EntryDAO($username); } } public static function createStatsDAO($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_StatsDAOSQLite($username); - } else { - return new FreshRSS_StatsDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_StatsDAOSQLite($username); + case 'pgsql': + return new FreshRSS_StatsDAOPGSQL($username); + default: + return new FreshRSS_StatsDAO($username); } } public static function createDatabaseDAO($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_DatabaseDAOSQLite($username); - } else { - return new FreshRSS_DatabaseDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_DatabaseDAOSQLite($username); + case 'pgsql': + return new FreshRSS_DatabaseDAOPGSQL($username); + default: + return new FreshRSS_DatabaseDAO($username); } } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 475d39286..f29dac9c0 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -16,7 +16,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId(); + return $this->bd->lastInsertId('"' . parent::prefix . 'feed_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addFeed: ' . $info[2]); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 5ca333396..e18ba4748 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -37,10 +37,10 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { $filter .= "AND e.id_feed = {$feed}"; } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id diff --git a/app/Models/StatsDAOPGSQL.php b/app/Models/StatsDAOPGSQL.php new file mode 100644 index 000000000..0bde72e58 --- /dev/null +++ b/app/Models/StatsDAOPGSQL.php @@ -0,0 +1,192 @@ +prefix}entry" AS e +, "{$this->prefix}feed" AS f +WHERE e.id_feed = f.id +{$filter} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + return $res[0]; + } + + /** + * Calculates entry count per day on a 30 days period. + * Returns the result as a JSON string. + * + * @return string + */ + public function calculateEntryCount() { + $count = $this->initEntryCountArray(); + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry" AS e +WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' +GROUP BY day +ORDER BY day ASC +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + foreach ($res as $value) { + $count[$value['day']] = (int) $value['count']; + } + + return $this->convertToSerie($count); + } + + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry" AS e +WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + + /** + * Calculates the number of article per hour of the day per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerHour($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('hour', $feed); + } + + /** + * Calculates the number of article per day of week per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('day', $feed); + } + + /** + * Calculates the number of article per month per feed + * + * @param integer $feed + * @return string + */ + public function calculateEntryRepartitionPerFeedPerMonth($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('month', $feed); + } + + /** + * Calculates the number of article per period per feed + * + * @param string $period format string to use for grouping + * @param integer $feed id + * @return string + */ + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + $restrict = ''; + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } + $sql = <<prefix}entry" AS e +{$restrict} +GROUP BY period +ORDER BY period ASC +SQL; + + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_NAMED); + + foreach ($res as $value) { + $repartition[(int) $value['period']] = (int) $value['count']; + } + + return $this->convertToSerie($repartition); + } + + /** + * Calculates the average number of article per feed + * + * @param float $period number used to divide the number of day in the period + * @param integer $feed id + * @return integer + */ + protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) { + $restrict = ''; + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } + $sql = <<prefix}entry" AS e +{$restrict} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + $date_min = new \DateTime(); + $date_min->setTimestamp($res['date_min']); + $date_max = new \DateTime(); + $date_max->setTimestamp($res['date_max']); + $interval = $date_max->diff($date_min, true); + $interval_in_days = $interval->format('%a'); + if ($interval_in_days <= 0) { + // Surely only one article. + // We will return count / (period/period) == count. + $interval_in_days = $period; + } + + return $res['count'] / ($interval_in_days / $period); + } + +} diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index c78839ef7..92a00aecc 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -1,4 +1,6 @@ $curl ? 'ok' : 'ko', 'pdo-mysql' => $pdo_mysql ? 'ok' : 'ko', 'pdo-sqlite' => $pdo_sqlite ? 'ok' : 'ko', + 'pdo-pgsql' => $pdo_pgsql ? 'ok' : 'ko', 'pdo' => $pdo ? 'ok' : 'ko', 'pcre' => $pcre ? 'ok' : 'ko', 'ctype' => $ctype ? 'ok' : 'ko', @@ -435,6 +438,22 @@ function checkBD() { PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ); break; + case 'pgsql': + $driver_options = array( + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + + try { // on ouvre une connexion juste pour créer la base si elle n'existe pas + $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';'; + $c = new PDO($str, $_SESSION['bd_user'], $_SESSION['bd_password'], $driver_options); + $sql = sprintf(SQL_CREATE_DB, $_SESSION['bd_base']); + $res = $c->query($sql); + } catch (PDOException $e) { + } + + // on écrase la précédente connexion en sélectionnant la nouvelle BDD + $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';dbname=' . $_SESSION['bd_base']; + break; default: return false; } @@ -708,6 +727,12 @@ function printStep3() { SQLite + + +
    diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 845aecaae..b98a26d06 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -55,36 +55,36 @@ class Minz_ModelPdo { $driver_options = isset($conf->db['pdo_options']) && is_array($conf->db['pdo_options']) ? $conf->db['pdo_options'] : array(); try { - $type = $db['type']; - if ($type === 'mysql') { - $string = 'mysql:host=' . $db['host'] - . ';dbname=' . $db['base'] - . ';charset=utf8mb4'; - $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8mb4'; - $this->prefix = $db['prefix'] . $currentUser . '_'; - } elseif ($type === 'sqlite') { - $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite'); - //$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; - $this->prefix = ''; - } else { - throw new Minz_PDOConnectionException( - 'Invalid database type!', - $db['user'], Minz_Exception::ERROR - ); - } - self::$sharedDbType = $type; - self::$sharedPrefix = $this->prefix; - - $this->bd = new MinzPDO( - $string, - $db['user'], - $db['password'], - $driver_options - ); - if ($type === 'sqlite') { - $this->bd->exec('PRAGMA foreign_keys = ON;'); + switch ($db['type']) { + case 'mysql': + $string = 'mysql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8mb4'; + $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8mb4'; + $this->prefix = $db['prefix'] . $currentUser . '_'; + $this->bd = new MinzPDO($string, $db['user'], $db['password'], $driver_options); + //TODO Consider: $this->bd->exec("SET SESSION sql_mode = 'ANSI_QUOTES';"); + break; + case 'sqlite': + $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite'); + $this->prefix = ''; + $this->bd = new MinzPDO($string, $db['user'], $db['password'], $driver_options); + $this->bd->exec('PRAGMA foreign_keys = ON;'); + break; + case 'pgsql': + $string = 'pgsql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8'; + $this->prefix = $db['prefix'] . $currentUser . '_'; + $this->bd = new MinzPDOPGSQL($string, $db['user'], $db['password'], $driver_options); + $this->bd->exec("SET NAMES 'UTF8';"); + break; + default: + throw new Minz_PDOConnectionException( + 'Invalid database type!', + $db['user'], Minz_Exception::ERROR + ); + break; } self::$sharedBd = $this->bd; + self::$sharedDbType = $db['type']; + self::$sharedPrefix = $this->prefix; } catch (Exception $e) { throw new Minz_PDOConnectionException( $string, @@ -119,18 +119,39 @@ class MinzPDO extends PDO { } } + protected function compatibility($statement) { + return $statement; + } + public function prepare($statement, $driver_options = array()) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::prepare($statement, $driver_options); } public function exec($statement) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::exec($statement); } public function query($statement) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::query($statement); } + + public function lastInsertId($name = null) { + return parent::lastInsertId(); //We discard the name, only used by PostgreSQL + } +} + +class MinzPDOPGSQL extends MinzPDO { + protected function compatibility($statement) { + return str_replace(array('`', " X'"), array('"', " E'\\x"), $statement); + } + + public function lastInsertId($name = null) { + return parent::lastInsertId($name); + } } diff --git a/p/scripts/install.js b/p/scripts/install.js index 57fc2450a..3e1db57b5 100644 --- a/p/scripts/install.js +++ b/p/scripts/install.js @@ -42,13 +42,15 @@ if (auth_type) { function mySqlShowHide() { var mysql = document.getElementById('mysql'); if (mysql) { - mysql.style.display = document.getElementById('type').value === 'mysql' ? 'block' : 'none'; - if (document.getElementById('type').value !== 'mysql') { + if (document.getElementById('type').value === 'sqlite') { document.getElementById('host').value = ''; document.getElementById('user').value = ''; document.getElementById('pass').value = ''; document.getElementById('base').value = ''; document.getElementById('prefix').value = ''; + mysql.style.display = 'none'; + } else { + mysql.style.display = 'block'; } } } -- cgit v1.2.3 From bee833bf524e58ea9cf5309fb89f6f8b30005720 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 7 Aug 2016 00:54:49 +0200 Subject: Problematic MySQL reserved keyword `read` and `reads` are reserved keywords --- app/Models/StatsDAO.php | 6 +++--- app/views/stats/index.phtml | 12 ++++++------ app/views/stats/repartition.phtml | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index e18ba4748..3f5bf8515 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -38,9 +38,9 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 0a2fbdb10..a36f812a8 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -23,18 +23,18 @@ - repartition['main_stream']['read']); ?> - repartition['all_feeds']['read']); ?> + repartition['main_stream']['count_reads']); ?> + repartition['all_feeds']['count_reads']); ?> - repartition['main_stream']['unread']); ?> - repartition['all_feeds']['unread']); ?> + repartition['main_stream']['count_unreads']); ?> + repartition['all_feeds']['count_unreads']); ?> - repartition['main_stream']['favorite']); ?> - repartition['all_feeds']['favorite']); ?> + repartition['main_stream']['count_favorites']); ?> + repartition['all_feeds']['count_favorites']); ?> diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index ffb2c361e..5ebcdce5a 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -12,7 +12,7 @@ if (!empty($feeds)) { echo ''; foreach ($feeds as $feed) { - if ($this->feed && $feed->id() == $this->feed->id()){ + if ($this->feed && $feed->id() == $this->feed->id()) { echo ''; } else { echo ''; @@ -39,9 +39,9 @@ repartition['total']; ?> - repartition['read']; ?> - repartition['unread']; ?> - repartition['favorite']; ?> + repartition['count_reads']; ?> + repartition['count_unreads']; ?> + repartition['count_favorites']; ?>
    -- cgit v1.2.3 From 961407b4e0546dd38a696a650898fcefbe2d6c8c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 28 Aug 2016 13:36:11 +0200 Subject: Variable initialization PHP warning when not feed is iddle https://github.com/FreshRSS/FreshRSS/issues/1227#issuecomment-242702464 --- app/Models/StatsDAO.php | 1 + 1 file changed, 1 insertion(+) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 5ca333396..4f83ff577 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -168,6 +168,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_NAMED); + $repartition = array(); foreach ($res as $value) { $repartition[(int) $value['period']] = (int) $value['count']; } -- cgit v1.2.3 From ccb56bcbf3ef69228ae4147a76cf3059f519bbf3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 11 Sep 2016 11:24:32 +0200 Subject: Simplify SQL in statistics Reduce the use of product-specific date functions. Improve performances. Remove redundant functions. --- app/Controllers/statsController.php | 36 +++++++++++++++++----- app/Models/StatsDAO.php | 61 ++++++------------------------------- app/Models/StatsDAOSQLite.php | 55 --------------------------------- 3 files changed, 39 insertions(+), 113 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 4a597ae7d..5d1dee72c 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -18,6 +18,27 @@ class FreshRSS_stats_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('admin.stats.title') . ' · '); } + private function convertToSerie($data) { + $serie = array(); + + foreach ($data as $key => $value) { + $serie[] = array($key, $value); + } + + return $serie; + } + + private function convertToPieSerie($data) { + $serie = array(); + + foreach ($data as $value) { + $value['data'] = array(array(0, (int) $value['data'])); + $serie[] = $value; + } + + return $serie; + } + /** * This action handles the statistic main page. * @@ -33,10 +54,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $statsDAO = FreshRSS_Factory::createStatsDAO(); Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); - $this->view->count = $statsDAO->calculateEntryCount(); - $this->view->average = $statsDAO->calculateEntryAverage(); - $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); - $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); + $entryCount = $statsDAO->calculateEntryCount(); + $this->view->count = $this->convertToSerie($entryCount); + $this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2); + $this->view->feedByCategory = $this->convertToPieSerie($statsDAO->calculateFeedByCategory()); + $this->view->entryByCategory = $this->convertToPieSerie($statsDAO->calculateEntryByCategory()); $this->view->topFeed = $statsDAO->calculateTopFeed(); } @@ -118,11 +140,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id); - $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); + $this->view->repartitionHour = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerHour($id)); $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); - $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); + $this->view->repartitionDayOfWeek = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id)); $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id); - $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); + $this->view->repartitionMonth = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerMonth($id)); $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 4f83ff577..28882baab 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -61,14 +61,15 @@ SQL; */ public function calculateEntryCount() { $count = $this->initEntryCountArray(); - $period = self::ENTRY_COUNT_PERIOD; + $midnight = mktime(0, 0, 0); + $oldest = $midnight - (self::ENTRY_COUNT_PERIOD * 86400); // Get stats per day for the last 30 days $sql = <<prefix}entry AS e -WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') +SELECT FLOOR((date - {$midnight}) / 86400) AS day, +COUNT(*) as count +FROM {$this->prefix}entry +WHERE date >= {$oldest} AND date < {$midnight} GROUP BY day ORDER BY day ASC SQL; @@ -80,28 +81,7 @@ SQL; $count[$value['day']] = (int) $value['count']; } - return $this->convertToSerie($count); - } - - /** - * Calculates entry average per day on a 30 days period. - * - * @return integer - */ - public function calculateEntryAverage() { - $period = self::ENTRY_COUNT_PERIOD; - - // Get stats per day for the last 30 days - $sql = <<prefix}entry AS e -WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetch(PDO::FETCH_NAMED); - - return round($res['average'], 2); + return $count; } /** @@ -173,7 +153,7 @@ SQL; $repartition[(int) $value['period']] = (int) $value['count']; } - return $this->convertToSerie($repartition); + return $repartition; } /** @@ -276,7 +256,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - return $this->convertToPieSerie($res); + return $res; } /** @@ -301,7 +281,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - return $this->convertToPieSerie($res); + return $res; } /** @@ -351,27 +331,6 @@ SQL; return $stm->fetchAll(PDO::FETCH_ASSOC); } - protected function convertToSerie($data) { - $serie = array(); - - foreach ($data as $key => $value) { - $serie[] = array($key, $value); - } - - return $serie; - } - - protected function convertToPieSerie($data) { - $serie = array(); - - foreach ($data as $value) { - $value['data'] = array(array(0, (int) $value['data'])); - $serie[] = $value; - } - - return $serie; - } - /** * Gets days ready for graphs * diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 9bfe8b20a..e09d18c77 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -2,61 +2,6 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO { - /** - * Calculates entry count per day on a 30 days period. - * Returns the result as a JSON object. - * - * @return JSON object - */ - public function calculateEntryCount() { - $count = $this->initEntryCountArray(); - $period = parent::ENTRY_COUNT_PERIOD; - - // Get stats per day for the last 30 days - $sql = <<prefix}entry AS e -WHERE strftime('%Y%m%d', e.date, 'unixepoch') - BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') - AND strftime('%Y%m%d', 'now', '-1 day') -GROUP BY day -ORDER BY day ASC -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - - foreach ($res as $value) { - $count[(int) $value['day']] = (int) $value['count']; - } - - return $this->convertToSerie($count); - } - - /** - * Calculates entry average per day on a 30 days period. - * - * @return integer - */ - public function calculateEntryAverage() { - $period = self::ENTRY_COUNT_PERIOD; - - // Get stats per day for the last 30 days - $sql = <<prefix}entry AS e -WHERE strftime('%Y%m%d', e.date, 'unixepoch') - BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') - AND strftime('%Y%m%d', 'now', '-1 day') -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetch(PDO::FETCH_NAMED); - - return round($res['average'], 2); - } - protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; -- cgit v1.2.3 From dbc68590da1d95c249f780e2d3ff4707f6f504e9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 27 Sep 2016 23:35:39 +0200 Subject: A bit more PostgreSQL Simplified statistics https://github.com/FreshRSS/FreshRSS/pull/1250 --- CHANGELOG.md | 2 + README.fr.md | 2 +- README.md | 2 +- app/Models/StatsDAO.php | 30 +++++----- app/Models/StatsDAOPGSQL.php | 125 ------------------------------------------ app/Models/StatsDAOSQLite.php | 2 +- app/install.php | 2 +- 7 files changed, 21 insertions(+), 144 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/CHANGELOG.md b/CHANGELOG.md index f13922837..e88daba93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * API * Support for editing feeds and categories from client applications [#1254](https://github.com/FreshRSS/FreshRSS/issues/1254) +* Compatibility: + * Experimental support for PostgreSQL [#1195](https://github.com/FreshRSS/FreshRSS/pull/1195) * Features * Better control of number of entries per page or RSS feed [#1249](https://github.com/FreshRSS/FreshRSS/issues/1249) * Since X hours: `https://freshrss.example/i/?a=rss&hours=3` diff --git a/README.fr.md b/README.fr.md index 8dc0f6fec..65cef544f 100644 --- a/README.fr.md +++ b/README.fr.md @@ -35,7 +35,7 @@ Nous sommes une communauté amicale. * PHP 5.3.3+ (PHP 5.4+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) * Requis : [DOM](http://php.net/dom), [XML](http://php.net/xml), [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite) ou [PDO_PGSQL](http://php.net/pdo-pgsql), [cURL](http://php.net/curl) * Recommandés : [JSON](http://php.net/json), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](http://php.net/mbstring) et/ou [iconv](http://php.net/iconv) (pour conversion d’encodages), [Zip](http://php.net/zip) (pour import/export), [zlib](http://php.net/zlib) (pour les flux compressés) -* MySQL 5.5.3+ (recommandé), ou SQLite 3.7.4+, ou PostgreSQL +* MySQL 5.5.3+ (recommandé), ou SQLite 3.7.4+, ou PostgreSQL (experimental) * Un navigateur Web récent tel Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Fonctionne aussi sur mobile diff --git a/README.md b/README.md index fc2c6fdb9..505a1d970 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ We are a friendly community. * PHP 5.3.3+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) * Required extensions: [DOM](http://php.net/dom), [XML](http://php.net/xml), [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite) or [PDO_PGSQL](http://php.net/pdo-pgsql), [cURL](http://php.net/curl) * Recommended extensions: [JSON](http://php.net/json), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names), [mbstring](http://php.net/mbstring) and/or [iconv](http://php.net/iconv) (for charset conversion), [Zip](http://php.net/zip) (for import/export), [zlib](http://php.net/zlib) (for compressed feeds) -* MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL +* MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL (experimental) * A recent browser like Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Works on mobile diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index e6998a6d7..fa682f488 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -41,8 +41,8 @@ SELECT COUNT(1) AS total, COUNT(1) - SUM(e.is_read) AS count_unreads, SUM(e.is_read) AS count_reads, SUM(e.is_favorite) AS count_favorites -FROM {$this->prefix}entry AS e -, {$this->prefix}feed AS f +FROM `{$this->prefix}entry` AS e +, `{$this->prefix}feed` AS f WHERE e.id_feed = f.id {$filter} SQL; @@ -68,7 +68,7 @@ SQL; $sql = <<prefix}entry +FROM `{$this->prefix}entry` WHERE date >= {$oldest} AND date < {$midnight} GROUP BY day ORDER BY day ASC @@ -138,7 +138,7 @@ SQL; $sql = <<prefix}entry AS e +FROM `{$this->prefix}entry` AS e {$restrict} GROUP BY period ORDER BY period ASC @@ -202,7 +202,7 @@ SQL; SELECT COUNT(1) AS count , MIN(date) AS date_min , MAX(date) AS date_max -FROM {$this->prefix}entry AS e +FROM `{$this->prefix}entry` AS e {$restrict} SQL; $stm = $this->bd->prepare($sql); @@ -246,8 +246,8 @@ SQL; $sql = <<prefix}category AS c, -{$this->prefix}feed AS f +FROM `{$this->prefix}category` AS c, +`{$this->prefix}feed` AS f WHERE c.id = f.category GROUP BY label ORDER BY data DESC @@ -269,9 +269,9 @@ SQL; $sql = <<prefix}category AS c, -{$this->prefix}feed AS f, -{$this->prefix}entry AS e +FROM `{$this->prefix}category` AS c, +`{$this->prefix}feed` AS f, +`{$this->prefix}entry` AS e WHERE c.id = f.category AND f.id = e.id_feed GROUP BY label @@ -295,9 +295,9 @@ SELECT f.id AS id , MAX(f.name) AS name , MAX(c.name) AS category , COUNT(e.id) AS count -FROM {$this->prefix}category AS c, -{$this->prefix}feed AS f, -{$this->prefix}entry AS e +FROM `{$this->prefix}category` AS c, +`{$this->prefix}feed` AS f, +`{$this->prefix}entry` AS e WHERE c.id = f.category AND f.id = e.id_feed GROUP BY f.id @@ -320,8 +320,8 @@ SELECT MAX(f.id) as id , MAX(f.name) AS name , MAX(date) AS last_date , COUNT(*) AS nb_articles -FROM {$this->prefix}feed AS f, -{$this->prefix}entry AS e +FROM `{$this->prefix}feed` AS f, +`{$this->prefix}entry` AS e WHERE f.id = e.id_feed GROUP BY f.id ORDER BY name diff --git a/app/Models/StatsDAOPGSQL.php b/app/Models/StatsDAOPGSQL.php index 0bde72e58..649dfa8b5 100644 --- a/app/Models/StatsDAOPGSQL.php +++ b/app/Models/StatsDAOPGSQL.php @@ -2,94 +2,6 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO { - /** - * Calculates entry repartition for the selection. - * The repartition includes: - * - total entries - * - read entries - * - unread entries - * - favorite entries - * - * @param null|integer $feed feed id - * @param boolean $only_main - * @return array - */ - public function calculateEntryRepartitionPerFeed($feed = null, $only_main = false) { - $filter = ''; - if ($only_main) { - $filter .= 'AND f.priority = 10'; - } - if (!is_null($feed)) { - $filter .= "AND e.id_feed = {$feed}"; - } - $sql = <<prefix}entry" AS e -, "{$this->prefix}feed" AS f -WHERE e.id_feed = f.id -{$filter} -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - - return $res[0]; - } - - /** - * Calculates entry count per day on a 30 days period. - * Returns the result as a JSON string. - * - * @return string - */ - public function calculateEntryCount() { - $count = $this->initEntryCountArray(); - $period = self::ENTRY_COUNT_PERIOD; - - // Get stats per day for the last 30 days - $sql = <<prefix}entry" AS e -WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' -GROUP BY day -ORDER BY day ASC -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - - foreach ($res as $value) { - $count[$value['day']] = (int) $value['count']; - } - - return $this->convertToSerie($count); - } - - /** - * Calculates entry average per day on a 30 days period. - * - * @return integer - */ - public function calculateEntryAverage() { - $period = self::ENTRY_COUNT_PERIOD; - - // Get stats per day for the last 30 days - $sql = <<prefix}entry" AS e -WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetch(PDO::FETCH_NAMED); - - return round($res['average'], 2); - } - /** * Calculates the number of article per hour of the day per feed * @@ -152,41 +64,4 @@ SQL; return $this->convertToSerie($repartition); } - /** - * Calculates the average number of article per feed - * - * @param float $period number used to divide the number of day in the period - * @param integer $feed id - * @return integer - */ - protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) { - $restrict = ''; - if ($feed) { - $restrict = "WHERE e.id_feed = {$feed}"; - } - $sql = <<prefix}entry" AS e -{$restrict} -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetch(PDO::FETCH_NAMED); - $date_min = new \DateTime(); - $date_min->setTimestamp($res['date_min']); - $date_max = new \DateTime(); - $date_max->setTimestamp($res['date_max']); - $interval = $date_max->diff($date_min, true); - $interval_in_days = $interval->format('%a'); - if ($interval_in_days <= 0) { - // Surely only one article. - // We will return count / (period/period) == count. - $interval_in_days = $period; - } - - return $res['count'] / ($interval_in_days / $period); - } - } diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index e09d18c77..ec0cfa81a 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -11,7 +11,7 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO { $sql = <<prefix}entry AS e +FROM `{$this->prefix}entry` AS e {$restrict} GROUP BY period ORDER BY period ASC diff --git a/app/install.php b/app/install.php index 7f4e65034..1972379e5 100644 --- a/app/install.php +++ b/app/install.php @@ -714,7 +714,7 @@ function printStep3() { -- cgit v1.2.3 From c35111fe53ba2081abc735cb61e83987ade5ce86 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 29 Sep 2016 23:36:25 +0200 Subject: Fix SQLite --- app/Models/StatsDAO.php | 7 ++++++- app/Models/StatsDAOSQLite.php | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index fa682f488..2ce4f2944 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -4,6 +4,10 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { const ENTRY_COUNT_PERIOD = 30; + protected function sqlFloor($s) { + return "FLOOR($s)"; + } + /** * Calculates entry repartition for all feeds and for main stream. * @@ -65,8 +69,9 @@ SQL; $oldest = $midnight - (self::ENTRY_COUNT_PERIOD * 86400); // Get stats per day for the last 30 days + $sqlDay = $this->sqlFloor("(date - $midnight) / 86400"); $sql = <<prefix}entry` WHERE date >= {$oldest} AND date < {$midnight} diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index ec0cfa81a..6cfc20463 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -2,6 +2,10 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO { + protected function sqlFloor($s) { + return "CAST(($s) AS INT)"; + } + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; @@ -26,7 +30,7 @@ SQL; $repartition[(int) $value['period']] = (int) $value['count']; } - return $this->convertToSerie($repartition); + return $repartition; } } -- cgit v1.2.3