From 8752cf3405de3c3bee484c69d8922b3c1db4698d Mon Sep 17 00:00:00 2001
From: pbarroca <pbarroca@afi-sa.fr>
Date: Fri, 17 Jan 2014 18:36:37 +0100
Subject: [PATCH] =?UTF-8?q?fix=20#11822=20:=20Stats=20visu=20notices=20par?=
 =?UTF-8?q?=20mois=20d=C3=A9sormais=20dans=20des=20sections=20par=20an?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../admin/controllers/StatController.php      | 90 +++++++------------
 .../scripts/stat/reservationnotice.phtml      | 40 +++------
 .../admin/views/scripts/stat/visunotice.phtml | 57 ++++++------
 library/Class/StatsNotices.php                | 44 +++------
 .../ZendAfi/View/Helper/Admin/BlocStats.php   | 75 ++++++++++++++++
 .../admin/controllers/StatControllerTest.php  | 72 +++++++++++++++
 6 files changed, 230 insertions(+), 148 deletions(-)
 create mode 100644 library/ZendAfi/View/Helper/Admin/BlocStats.php

diff --git a/application/modules/admin/controllers/StatController.php b/application/modules/admin/controllers/StatController.php
index e23e2c59e0d..91459510d06 100644
--- a/application/modules/admin/controllers/StatController.php
+++ b/application/modules/admin/controllers/StatController.php
@@ -18,82 +18,58 @@
  * along with AFI-OPAC 2.0; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
-//-----------------------------------------------------------------------
-// OPAC3 - Statistiques notices
-//-----------------------------------------------------------------------
-class Admin_StatController extends Zend_Controller_Action
-{
-	private $cls_stat;											// Instance classe stat
 
-	function indexAction()
-	{
-		$this->_redirect('admin/index');
-	}
+class Admin_StatController extends Zend_Controller_Action {
+	private $cls_stat;											// Instance classe stat
 
-//-----------------------------------------------------------------------
-// Initialisation
-//-----------------------------------------------------------------------
-	function init()
-	{
-		$this->cls_stat=new Class_StatsNotices();
+	public function init() {
+		$this->cls_stat = new Class_StatsNotices();
 		$css = '<link rel="stylesheet" type="text/css" media="screen" href="'.URL_ADMIN_CSS.'statistique.css" />';
 		$this->getResponse()->setBody($css);
 	}
 
-//-----------------------------------------------------------------------
-// Visualisations de notices
-//-----------------------------------------------------------------------
-	function visunoticeAction()
-	{
+	
+	public function preDispatch() {
+		$this->view->periode = $this->cls_stat->getPeriode();
+	}
+
+
+	public function indexAction() {
+		$this->_redirect('admin/index');
+	}
+
+
+	public function visunoticeAction() {
 		$this->view->titre = 'Statistiques de visualisation des notices';
-		$this->view->periode=$this->cls_stat->getPeriode(0,0);
-		$this->view->table_stat=$this->cls_stat->getRecapVisu();
+		$this->view->table_stat = $this->cls_stat->getRecapVisu();
 	}
 	
-//-----------------------------------------------------------------------
-// Palmares Visualisations de notices
-//-----------------------------------------------------------------------
-	function palmaresvisunoticeAction()
-	{
+
+	public function palmaresvisunoticeAction() {
 		$this->view->titre = 'Palmarès des visualisations de notices';
-		$this->view->periode = $this->cls_stat->getPeriode(0,0);
-		$this->view->table_stat = $this->cls_stat->getPalmaresVisu($_REQUEST["type_doc"]);
+		$this->view->table_stat = $this->cls_stat->getPalmaresVisu($this->_getParam('type_doc'));
 	}
 	
-//-----------------------------------------------------------------------
-// Recherches infructueuses
-//-----------------------------------------------------------------------
-	function rechercheinfructueuseAction()
-	{
+
+	public function rechercheinfructueuseAction() {
 		$this->view->titre = 'Recherches infructueuses';
+		$page = $this->_getParam('page', 1);
 		$this->view->nb_par_page = 20;
-		$page = $this->_getParam('page');
-		if(!$page) $page=1;
-		$this->view->page=$page;
-		$limit=($page-1) * $this->view->nb_par_page;
-		$limit=" limit ".$limit.",".$this->view->nb_par_page;
-		$this->view->nombre_total=fetchOne("select count(*) from stats_recherche_echec");
-		$req="select * from stats_recherche_echec order by id desc ".$limit;
-		$this->view->liste = fetchAll($req);
+		$start = ($page-1) * $this->view->nb_par_page;
+		$this->view->liste = $this->cls_stat->getNotFoundByPage($page, $this->view->nb_par_page);
+		$this->view->nombre_total = $this->cls_stat->getTotalNotFound();
+		$this->view->page = $page;
 	}
 
-//-----------------------------------------------------------------------
-// Réservations de notices
-//-----------------------------------------------------------------------
-	function reservationnoticeAction()
-	{
+
+	public function reservationnoticeAction() {
 		$this->view->titre = 'Statistiques des réservations de notices';
-		$this->view->periode=$this->cls_stat->getPeriode(0,0);
-		$this->view->table_stat=$this->cls_stat->getRecapReservation();
+		$this->view->table_stat = $this->cls_stat->getRecapReservation();
 	}
 
-//-----------------------------------------------------------------------
-// Palmares Réservations de notices
-//-----------------------------------------------------------------------
-	function palmaresreservationnoticeAction()
-	{
+
+	public function palmaresreservationnoticeAction() {
 		$this->view->titre = 'Palmarès des réservations de notices';
-		$this->view->periode=$this->cls_stat->getPeriode(0,0);
-		$this->view->table_stat=$this->cls_stat->getPalmaresReservation($_REQUEST["type_doc"]);
+		$this->view->table_stat = $this->cls_stat->getPalmaresReservation($this->_getParam('type_doc'));
 	}
 }
\ No newline at end of file
diff --git a/application/modules/admin/views/scripts/stat/reservationnotice.phtml b/application/modules/admin/views/scripts/stat/reservationnotice.phtml
index ecc0ea3d1e6..b635c301e7e 100644
--- a/application/modules/admin/views/scripts/stat/reservationnotice.phtml
+++ b/application/modules/admin/views/scripts/stat/reservationnotice.phtml
@@ -1,33 +1,15 @@
+<h2 class="stat"><?php echo $this->periode;?>, 
+<?php echo number_format($this->table_stat["total"], 0, ',', ' ');?> 
+demandes de réservation ont été effectuées</h2>
+
+<h3 class="stat">Détail par années</h3>
 <?php 
-print('<h2 class="stat">'.$this->periode.", ".number_format($this->table_stat["total"], 0, ',', ' ').' demandes de réservation ont été effectuées</h2>');
-print('<h3 class="stat">Détail par années</h3>');
-printBlocStat("Année",$this->table_stat["annees"],$this->table_stat["graphes"]["annees"]);
-print('<h3 class="stat">Détail par mois</h3>');
-printBlocStat("Mois",$this->table_stat["mois"],$this->table_stat["graphes"]["mois"]);
+	 if (isset($this->table_stat['annees']))
+		 echo $this->blocStats('Année', $this->table_stat['annees']);?>
 
-// Bloc stat : tableau et graphe
-function printBlocStat($titre,$table,$graphe)
-{
-	// container principal
-	print('<table><tr><td valign="top">');
-	// Tableau
-	print('<table class="stat" style="width:180px;margin-left:10px"><tr>');
-	print('<th class="stat" width="70%">'.$titre.'</th>');
-	print('<th class="stat" width="30%">Nombre</th>');
-	print('</tr>');
-	foreach($table as $libelle => $nombre)
-	{
-		print('<tr>');
-		print('<td class="stat_libelle">'.$libelle.'</td>');
-		print('<td class="stat_nombre">'.$nombre.'</td>');
-		print('</tr>');
-	}
-	print('</table></td>');
-	// Graphe
-	print('<td>'.$graphe.'</td>');
-	// Fini
-	print('</tr></table>');
-}
-?>
+<h3 class="stat">Détail par mois</h3>
+<?php 
+	 if (isset($this->table_stat['mois']))
+		 echo $this->blocStats('Mois',	$this->table_stat['mois']);?>
 
 <br>
diff --git a/application/modules/admin/views/scripts/stat/visunotice.phtml b/application/modules/admin/views/scripts/stat/visunotice.phtml
index 78ef09b53ce..e9fdf4e3361 100644
--- a/application/modules/admin/views/scripts/stat/visunotice.phtml
+++ b/application/modules/admin/views/scripts/stat/visunotice.phtml
@@ -1,35 +1,28 @@
-<?php 
-print('<h2 class="stat">'.$this->periode.", ".number_format($this->table_stat["total"], 0, ',', ' ').' notices ont été visualisées</h2>');
-print('<h3 class="stat">Détail par années</h3>');
-printBlocStat("Année",$this->table_stat["annees"],$this->table_stat["graphes"]["annees"]);
-print('<h3 class="stat">Détail par mois</h3>');
-printBlocStat("Mois",$this->table_stat["mois"],$this->table_stat["graphes"]["mois"]);
+<h2 class="stat">
+<?php echo $this->periode;?>, 
+<?php echo number_format($this->table_stat["total"], 0, ',', ' ');?> notices ont été visualisées
+</h2>
+
+<script>
+	 $(function(){$('#accordion').accordion({autoHeight:false, collapsible:true});});
+</script>
 
-// Bloc stat : tableau et graphe
-function printBlocStat($titre,$table,$graphe)
-{
-	if (!$table)
-		return;
-	// container principal
-	print('<table><tr><td valign="top">');
-	// Tableau
-	print('<table class="stat" style="width:180px;margin-left:10px"><tr>');
-	print('<th class="stat" width="70%">'.$titre.'</th>');
-	print('<th class="stat" width="30%">Nombre</th>');
-	print('</tr>');
-	foreach($table as $libelle => $nombre)
-	{
-		print('<tr>');
-		print('<td class="stat_libelle">'.$libelle.'</td>');
-		print('<td class="stat_nombre">'.$nombre.'</td>');
-		print('</tr>');
-	}
-	print('</table></td>');
-	// Graphe
-	print('<td>'.$graphe.'</td>');
-	// Fini
-	print('</tr></table>');
-}
-?>
+<?php if (isset($this->table_stat)) { ?>
+<h3 class="stat">Détail par années</h3>
+<?php 
+$years = [];
+foreach ($this->table_stat as $label => $datas)
+	if (isset($datas['total']))
+		$years[$label] = $datas['total'];
+echo $this->blocStats('Année', $years);?>
 
+<h3 class="stat">Détail par mois</h3>
+<div id="accordion">
+<?php foreach ($this->table_stat as $label => $datas) { 
+if (!isset($datas['mois'])) continue;?>
+<h4><?php echo $label;?></h4>
+<?php echo $this->blocStats('Mois',	$datas['mois']);?>
+<?php } ?>
+</div>
+<?php } ?>
 <br>
diff --git a/library/Class/StatsNotices.php b/library/Class/StatsNotices.php
index 88f9d747b7d..629b241eff9 100644
--- a/library/Class/StatsNotices.php
+++ b/library/Class/StatsNotices.php
@@ -64,7 +64,7 @@ class Class_StatsNotices {
 			$msg = 'en ' . $msg;
 		} else {
 			if ($annee = fetchOne('select min(annee) from stats_notices'))
-				$mois = fetchOne("select min(mois) from stats_notices where annee=$annee");
+				$mois = fetchOne('select min(mois) from stats_notices where annee=' . $annee);
 			$msg = 'depuis ' . $this->lib_mois[$mois] . ' ' . $annee;
 		}
 		return $msg;
@@ -72,27 +72,24 @@ class Class_StatsNotices {
 
 
 	public function getRecapVisu() {
-		// Par années
-		$liste = fetchAll("Select annee, sum(nb_visu) from stats_notices group by 1");
+		$ret = ['total' => 0, 'annees' => [], 'mois' => [], 'graphes' => []];
+		$liste = fetchAll('Select annee, sum(nb_visu) from stats_notices group by 1 order by annee desc');
 		$total = 0;
 		foreach($liste as $stat) {
 			$annee = $stat["annee"];
 			$nombre = $stat["sum(nb_visu)"];
 			$total += $nombre;
-			$ret["annees"][$annee]=$nombre;
+			$ret[$annee] = ['total' => $nombre, 'mois' => []];
 		}
 		$ret["total"] = $total;
-		$ret["graphes"]["annees"] = $this->getGraphe($ret["annees"], $total);
 		
-		// Par mois
-		$liste = fetchAll("Select mois, sum(nb_visu) as cnt from stats_notices group by 1");
+		$liste = fetchAll("Select annee, mois, nb_visu as cnt from stats_notices order by annee desc, mois desc");
 		foreach ($liste as $stat) {
-			$mois = $this->lib_mois[$stat["mois"]];
-			$nombre = $stat["cnt"];
-			$ret["mois"][$mois] = $nombre;
+			$mois = $this->lib_mois[$stat['mois']];
+			$nombre = $stat['cnt'];
+			$ret[$stat['annee']]['mois'][$mois] = $nombre;
 		}
 
-		$ret["graphes"]["mois"] = $this->getGraphe($ret["mois"], $total);
 		return $ret;
 	}
 
@@ -168,27 +165,14 @@ class Class_StatsNotices {
 	}
 
 
-	public function getGraphe($data_graphe, $total) {
-		$nb_rubriques = count($data_graphe);
-		if (!$nb_rubriques)
-			return false;
-		
-		// Constituer les arguments pour google
-		$datas = $labels = [];
-		foreach($data_graphe as $label => $data) {
-			$datas[] = ($data and $total) ? (int)($data / $total * 100) : 0;
-			$labels[] = $label;
-		}
-
-		$chd = implode(',', $datas);
-		$chl = implode('|', $labels);
+	public function getTotalNotFound() {
+		return fetchOne('select count(*) from stats_recherche_echec');
+	}
 
-		$taille = ($nb_rubriques < 5) ? 
-			'chs=200x120&amp;cht=bvg': 
-			'chs=450x200&amp;cht=p3';
 
-		$url_google = $this->url_google . $taille . "&amp;chd=t:" . $chd . "&amp;chl=" . $chl;
-		return '<img src="' . $url_google . '" border="0">';
+	public function getNotFoundByPage($start, $count) {
+		return fetchAll(sprintf('select * from stats_recherche_echec order by id desc limit %s, %s',
+														$start, $count));
 	}
 
 
diff --git a/library/ZendAfi/View/Helper/Admin/BlocStats.php b/library/ZendAfi/View/Helper/Admin/BlocStats.php
new file mode 100644
index 00000000000..ed6d064fde7
--- /dev/null
+++ b/library/ZendAfi/View/Helper/Admin/BlocStats.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+class ZendAfi_View_Helper_Admin_BlocStats extends ZendAfi_View_Helper_BaseHelper {
+	const GOOGLE_URL = 'http://chart.apis.google.com/chart?';
+
+	public function blocStats($title, $datas) {
+		if (!$datas)
+			return;
+
+		$html = '<table><tr><td valign="top">' 
+			. '<table class="stat" style="width:180px;margin-left:10px"><tr>'
+			. '<th class="stat" width="70%">' . $title . '</th>'
+			. '<th class="stat" width="30%">Nombre</th>'
+			. '</tr>';
+
+		foreach ($datas as $label => $count)
+			$html .= $this->_dataFor($label, $count);
+		
+		$html .= '</table></td>'
+			. '<td>'. $this->_graph($datas) . '</td>'
+			. '</tr></table>';
+
+		return $html;
+	}
+
+
+	protected function _dataFor($label, $count) {
+		return '<tr>'
+			. '<td class="stat_libelle">' . $label . '</td>'
+			. '<td class="stat_nombre">' . $count . '</td>'
+			. '</tr>';
+	}
+
+
+	protected function _graph($graph_datas) {
+		if (empty($graph_datas))
+			return false;
+		
+		$total = 0;
+		array_walk($graph_datas, function($item) use (&$total) {$total += $item;});
+
+		$datas = $labels = [];
+		array_walk($graph_datas, function($data, $label) use ($total, &$datas, &$labels) {
+		  $datas[] = ($data and $total) ? (int)($data / $total * 100) : 0;
+			$labels[] = $label;						 
+	  });
+
+		$chd = implode(',', $datas);
+		$chl = implode('|', $labels);
+
+		$taille = (count($datas) < 5) ? 
+			'chs=200x120&amp;cht=bvg': 
+			'chs=450x200&amp;cht=p3';
+
+		return '<img src="' . self::GOOGLE_URL . $taille . "&amp;chd=t:" . $chd . "&amp;chl=" . $chl . '" border="0">';
+	}
+}
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/StatControllerTest.php b/tests/application/modules/admin/controllers/StatControllerTest.php
index a75b8bffa97..5cc95f27717 100644
--- a/tests/application/modules/admin/controllers/StatControllerTest.php
+++ b/tests/application/modules/admin/controllers/StatControllerTest.php
@@ -36,6 +36,30 @@ class Admin_StatControllerRecherchesInfructueusesTest extends Admin_AbstractCont
 class Admin_StatControllerVisunoticeTest extends Admin_AbstractControllerTestCase{
 	public function setUp() {
 		parent::setUp();
+		$this->sql = $this->mock()
+			->whenCalled('fetchAll')
+			->with('Select annee, sum(nb_visu) from stats_notices group by 1 order by annee desc', false)
+			->answers([['annee' => '2000', 'sum(nb_visu)' => 6000],])
+
+			->whenCalled('fetchAll')
+			->with('Select annee, mois, nb_visu as cnt from stats_notices order by annee desc, mois desc',
+						 false)
+			->answers([['annee' => '2000', 'mois' => 1, 'cnt' => 42],])
+			
+			->whenCalled('fetchOne')
+			->with('select min(annee) from stats_notices')
+			->answers('2000')
+			
+			->whenCalled('fetchOne')
+			->with("select min(mois) from stats_notices where annee=2000")
+			->answers('1')
+
+			->whenCalled('fetchOne')
+			->answers('1');
+
+
+		Zend_Registry::set('sql', $this->sql);
+
 		$this->dispatch('/admin/stat/visunotice', true);
 	}
 
@@ -44,6 +68,54 @@ class Admin_StatControllerVisunoticeTest extends Admin_AbstractControllerTestCas
 	public function titreShouldBeVisualisationNotice() {
 		$this->assertXPathContentContains('//h1', 'visualisation des notices');
 	}
+
+
+	/** @test */
+	public function shouldHaveYearDetails() {
+		$this->assertXPathContentContains('//h3', 'Détail par années');
+	}
+
+
+	/** @test */
+	public function shouldHaveYear2000Label() {
+		$this->assertXPathContentContains('//td', '2000');
+	}
+
+
+	/** @test */
+	public function shouldHaveYear2000Detail() {
+		$this->assertXPathContentContains('//td', '6000');
+	}
+
+
+	/** @test */
+	public function shouldHaveYearsGraph() {
+		$this->assertXPath('//img[contains(@src, "chl=2000")]');
+	}
+
+
+	/** @test */
+	public function shouldHaveMonthDetails() {
+		$this->assertXPathContentContains('//h3', 'Détail par mois');
+	}
+
+
+	/** @test */
+	public function shouldHaveMonth1DetailLabel() {
+		$this->assertXPathContentContains('//td', 'janvier');
+	}
+
+
+	/** @test */
+	public function shouldHaveMonth1DetailCount() {
+		$this->assertXPathContentContains('//td', '42');
+	}
+
+	/** @test */
+	public function shouldHaveMonthsGraph() {
+		$this->assertXPath('//img[contains(@src, "janvier")]',
+											 $this->_response->getBody());
+	}
 }
 
 ?>
\ No newline at end of file
-- 
GitLab