[Piwik-svn] r506 - in trunk: . modules modules/API modules/Archive modules/Archive/Array modules/DataTable modules/DataTable/Renderer plugins/UsersManager plugins/VisitFrequency plugins/VisitorInterest tests/modules tests/modules/DataTable

svnmaster at piwik.org svnmaster at piwik.org
Fri Jun 6 03:18:48 CEST 2008


Author: matt
Date: 2008-06-06 03:18:47 +0200 (Fri, 06 Jun 2008)
New Revision: 506

Added:
   trunk/modules/Archive/Array/
   trunk/modules/Archive/Array/IndexedByDate.php
   trunk/modules/Archive/Array/IndexedBySite.php
Modified:
   trunk/TODO
   trunk/modules/API/Request.php
   trunk/modules/Access.php
   trunk/modules/Archive.php
   trunk/modules/Archive/Array.php
   trunk/modules/Archive/Single.php
   trunk/modules/DataTable/Array.php
   trunk/modules/DataTable/Renderer.php
   trunk/modules/DataTable/Renderer/Csv.php
   trunk/modules/DataTable/Renderer/Html.php
   trunk/modules/DataTable/Renderer/Json.php
   trunk/modules/DataTable/Renderer/Php.php
   trunk/modules/DataTable/Renderer/Rss.php
   trunk/modules/DataTable/Renderer/Xml.php
   trunk/modules/Date.php
   trunk/modules/Site.php
   trunk/modules/ViewDataTable.php
   trunk/plugins/UsersManager/API.php
   trunk/plugins/VisitFrequency/API.php
   trunk/plugins/VisitFrequency/Controller.php
   trunk/plugins/VisitFrequency/VisitFrequency.php
   trunk/plugins/VisitorInterest/API.php
   trunk/plugins/VisitorInterest/Controller.php
   trunk/plugins/VisitorInterest/VisitorInterest.php
   trunk/tests/modules/DataTable/Renderer.test.php
   trunk/tests/modules/Database.test.php
   trunk/tests/modules/UsersManager.test.php
Log:
Adding new feature: you can now use comma separated idsite in all the APIs methods. Examples:
?module=API&method=VisitsSummary.getVisits&idSite=1,2,3,15&period=day&date=last2&format=xml 

Adding a new magic keyword "all" that will give stats for all the websites for which the requesting user (or token_auth) has view access
?module=API&method=VisitsSummary.getVisits&idSite=all&period=day&date=last2&format=xml

- Expanding the concept of Piwik_Archive_Array
- Adding tests for rendering Array of Array
- Cleaning the renderer structure, but still work to do to make the code clearer (it's becoming quite complex...)

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/TODO	2008-06-06 01:18:47 UTC (rev 506)
@@ -1,3 +1,13 @@
+ECLIPSE WINDOWS LINE BREAKS
+rename $renderExpanded name
+test that fresh archive doesn't show expanding when not requested
+
+see if can remove translationAvailable in all plugins
+
+deactivate online logs
+ARCHIVE ALL SITES
+http://piwik.org/demo/?module=API&method=SitesManager.getAllSitesId&format=csv&token_auth=0b809661490d605bfd77f57ed11f0b14
+
 commenting remaining core files 6 hours
 review all TODO from code + create tickets OR fix
 
@@ -6,6 +16,9 @@
 loading recursive
 appels call API examples 
 
+
+api examples strings in light grey
+
 execute unit tests
 
 tickets next roadmap 
@@ -34,41 +47,52 @@
 - write beginners tutorials medium level user http://producingoss.com/en/funding-non-programming.html
 
 
+http://piwik.org/demo/?module=API&method=VisitsSummary.getVisits&idSite=1&period=week&date=last2&format=xml
+add xml dateFrom dateTo to result to pragmatically useful
 
+
 simple fix
 ====
+Ouais ca serait mieux, mais ca me parait toujours pas logique... En gros le mode "donner les accès à tous" sera utilisé pour créer un compte "super user" dans la majorité des cas. Je trouve ca plus logique de donner les accès par défaut. Et pourquoi pas plutot un message "Vos chagements affecteront les sites enregistrés ultérieurement ?" :) 
 
+johan> Est ce que tu pourrais faire en sorte que le piwik.php fonctionne toujours si le serveur sql derrière déconne ? (genre mettre un timeout de 2 sec sur la cxion sql ?)
+
+make sure with token auth no DB access
+
+First, knowing that I run "Piwik  # open source analytics" is great the first time, but the next ones it's just loosing space. I would replace that by the name of the website and a little something that would let me choose another website.
+I would also split the "Admin | API | Widget | send us feedback" bar. Moving the admin link to the user bar at the top, and the rest at the very bottom of the page, with a link to piwik.org.
+
+
+config file defined:
+when archiving from CLI ==> @set_time_limit(0); 
+==> set memory_limit high from config file
+
+
 regarder pour error_reporting
 admin sites css overwrite
 Review all english strings, make them more explicit
-
-En fait, j'ai affich� le lien complet dans ma page, et j'ai cliqu� dessus pour voir ce qu'il disait, et j'ai re�u deux erreurs un peu plus claire, la premi�re, c'est qu'il a r�clam� sur la premi�re visite que la colonne LOCATION_PROVIDER (piwik_log_visit) n'avait pas de default value, j'en ai mis une avec '$' et c'est pass�.
  
-La seconde �tait que la longueur de la colonne LOCATION_BROWSER_LANG (piwik_log_visit toujours) �tait trop courte, je l'ai rallong�e � 100 pour voir ce qu'il voulait y mettre et j'y ai trouv� apr�s : "fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3".
-
-todo: when adding a user, should test that email is unique
-   piwik.php link to /piwik
 editing site web with single quote bugs in siteAdmin
 something is wrong in JS calendar when year selected
 
-
-added index _visit server_date
-added index _log_link_action idvisit
-
 plugins easy to register a new hook
 
-PPT= TRY PIWIK instead of onlin demo + screenshot piiwk
-
 error RSS Feed only used on DataTable_Array http://piwik.org/demo/?module=API&method=Referers.getKeywords&idSite=1&period=week&date=yesterday&format=rss&filter_limit=30&filter_sort_column=3 
 NOT CLEAR MESSAGE
 
 documenter 	const VISIT_STANDARD_LENGTH = 1800; when writing plugin and need to test stats log
 
+Pour la home de Piwik, on aurait en + du contenu piwik proprement dit :
+- un extrait du  blog
+- le nombre d�install piwik ( le compteur )
+- la possibilit� de s�abonner a une newsletter
+- Les news Piwik...
+
+
 CHANGES DONE TO LIBRARIES
 =========================
+- edited Zend/Db/Adapter/Abstract.php added resetConfigArray()
 - edited zend_log and changed attr to protected
 - fixed bug fwrite in zend_log stream writer
 - fixed PEAR so that it works under PHP5 with STRICT MODE enabled
 - edited line 145 registry.php from require_once 'Zend/Exception.php'; to require_once 'Exception.php';
-
-

Modified: trunk/modules/API/Request.php
===================================================================
--- trunk/modules/API/Request.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/API/Request.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -508,6 +508,16 @@
 	 */
 	protected function applyDataTableGenericFilters($dataTable)
 	{
+		if($dataTable instanceof Piwik_DataTable_Array )
+		{
+			$tables = $dataTable->getArray();
+			foreach($tables as $table)
+			{
+				$this->applyDataTableGenericFilters($table);
+			}
+			return;
+		}
+		
 		// Generic filters
 		// PatternFileName => Parameter names to match to constructor parameters
 		/*
@@ -548,7 +558,6 @@
 				}
 				catch(Exception $e)
 				{
-//					print($e->getMessage());
 					$exceptionRaised = true;
 					break;
 				}

Modified: trunk/modules/Access.php
===================================================================
--- trunk/modules/Access.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Access.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -245,9 +245,13 @@
 	 */
 	public function checkUserHasAdminAccess( $idSites )
 	{
+		if($idSites === 'all')
+		{
+			$idSites = $this->getSitesIdWithAtLeastViewAccess();
+		}
 		if(!is_array($idSites))
 		{
-			$idSites = array($idSites);
+			$idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
 		}
 		$idSitesAccessible = $this->getSitesIdWithAdminAccess();
 		foreach($idSites as $idsite)
@@ -264,14 +268,19 @@
 	 * This method checks that the user has VIEW or ADMIN access for the given list of websites.
 	 * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception.
 	 * 
-	 * @param int|arrayOfIntegers List of ID sites to check
+	 * @param int|arrayOfIntegers|string List of ID sites to check (integer, array of integers, string comma separated list of integers)
 	 * @throws Exception If for any of the websites the user doesn't have an VIEW or ADMIN access
 	 */
 	public function checkUserHasViewAccess( $idSites )
 	{
+		if($idSites === 'all')
+		{
+			$idSites = $this->getSitesIdWithAtLeastViewAccess();
+		}
+		
 		if(!is_array($idSites))
 		{
-			$idSites = array($idSites);
+			$idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
 		}
 		$idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
 

Added: trunk/modules/Archive/Array/IndexedByDate.php
===================================================================
--- trunk/modules/Archive/Array/IndexedByDate.php	                        (rev 0)
+++ trunk/modules/Archive/Array/IndexedByDate.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -0,0 +1,126 @@
+<?php
+require_once "Archive/Array.php";
+
+class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array {
+	
+	/**
+	 * Builds an array of Piwik_Archive of a given date range
+	 *
+	 * @param Piwik_Site $oSite 
+	 * @param string $strPeriod eg. 'day' 'week' etc.
+	 * @param string $strDate A date range, eg. 'last10', 'previous5' or 'YYYY-MM-DD,YYYY-MM-DD'
+	 */
+	function __construct(Piwik_Site $oSite, $strPeriod, $strDate)
+	{
+		$rangePeriod = new Piwik_Period_Range($strPeriod, $strDate);
+		
+		// TODO fix this when aggregating data from multiple websites
+		// CAREFUL this class wouldnt work as is if handling archives from multiple websites
+		// works only when managing archives from multiples dates/periods
+		foreach($rangePeriod->getSubperiods() as $subPeriod)
+		{
+			$startDate = $subPeriod->getDateStart();
+			$archive = Piwik_Archive::build($oSite->getId(), $strPeriod, $startDate );
+			$archive->prepareArchive();
+			$timestamp = $archive->getTimestampStartDate();
+			$this->archives[$timestamp] = $archive;
+		}
+		ksort( $this->archives );
+	}
+	
+	protected function getIndexName()
+	{
+		return 'date';
+	}
+	
+	protected function loadMetaData(Piwik_DataTable_Array $table, $archive)
+	{
+		$table->metaData[$archive->getPrettyDate()] = array( 
+				'timestamp' => $archive->getTimestampStartDate(),
+				'site' => $archive->getSite(),
+			);
+	}
+	protected function getDataTableLabelValue( $archive )
+	{
+		return $archive->getPrettyDate();
+	}
+	
+	/**
+	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Array
+	 * which is an array of Piwik_DataTable_Simple, ordered by chronological order
+	 *
+	 * @param array|string $fields array( fieldName1, fieldName2, ...)  Names of the mysql table fields to load
+	 * @return Piwik_DataTable_Array
+	 */
+	public function getDataTableFromNumeric( $fields )
+	{
+		if(!is_array($fields))
+		{
+			$fields = array($fields);
+		}
+		
+		$inName = "'" . implode("', '",$fields) . "'";
+		
+		// we select in different shots
+		// one per distinct table (case we select last 300 days, maybe we will  select from 10 different tables)
+		$queries = array();
+		foreach($this->archives as $archive) 
+		{
+			if(!$archive->isThereSomeVisits)
+			{
+				continue;
+			}
+			
+			$table = $archive->archiveProcessing->getTableArchiveNumericName();
+
+			// for every query store IDs
+			$queries[$table][] = $archive->getIdArchive();
+		}
+		// we select the requested value
+		$db = Zend_Registry::get('db');
+		
+		// date => array( 'field1' =>X, 'field2'=>Y)
+		// date2 => array( 'field1' =>X2, 'field2'=>Y2)		
+		
+		$arrayValues = array();
+		foreach($queries as $table => $aIds)
+		{
+			$inIds = implode(', ', $aIds);
+			$sql = "SELECT value, name, idarchive, UNIX_TIMESTAMP(date1) as timestamp
+									FROM $table
+									WHERE idarchive IN ( $inIds )
+										AND name IN ( $inName )";
+
+			$values = $db->fetchAll($sql);
+			
+			foreach($values as $value)
+			{
+				$arrayValues[$value['timestamp']][$value['name']] = $value['value'];
+			}			
+		}
+		
+		$contentArray = array();
+		// we add empty tables so that every requested date has an entry, even if there is nothing
+		// example: <result date="2007-01-01" />
+		foreach($this->archives as $timestamp => $archive)
+		{
+			$strDate = $this->archives[$timestamp]->getPrettyDate();
+			$contentArray[$timestamp]['table'] = new Piwik_DataTable_Simple();
+			$contentArray[$timestamp]['prettyDate'] = $strDate;
+		}
+
+		foreach($arrayValues as $timestamp => $aNameValues)
+		{
+			$contentArray[$timestamp]['table']->loadFromArray($aNameValues);
+		}
+		ksort( $contentArray );
+				
+		$tableArray = $this->getNewDataTableArray();
+		foreach($contentArray as $timestamp => $aData)
+		{
+			$tableArray->addTable($aData['table'], $aData['prettyDate']);
+			$this->loadMetaData($tableArray, $this->archives[$timestamp]);
+		}
+		return $tableArray;
+	}
+}
\ No newline at end of file

Added: trunk/modules/Archive/Array/IndexedBySite.php
===================================================================
--- trunk/modules/Archive/Array/IndexedBySite.php	                        (rev 0)
+++ trunk/modules/Archive/Array/IndexedBySite.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -0,0 +1,98 @@
+<?php
+require_once "Archive/Array.php";
+
+class Piwik_Archive_Array_IndexedBySite extends Piwik_Archive_Array {
+	
+	/**
+	 *
+	 * @param Piwik_Site $oSite 
+	 * @param string $strPeriod eg. 'day' 'week' etc.
+	 * @param string $strDate A date range, eg. 'last10', 'previous5' or 'YYYY-MM-DD,YYYY-MM-DD'
+	 */
+	function __construct($sites, $strPeriod, $strDate)
+	{
+		foreach($sites as $idSite)
+		{
+			$archive = Piwik_Archive::build($idSite, $strPeriod, $strDate );
+			$archive->setSite(new Piwik_Site($idSite));
+			$archive->prepareArchive();
+			$this->archives[$idSite] = $archive;
+		}
+		ksort( $this->archives );
+	}
+	
+	protected function getIndexName()
+	{
+		return 'idSite';
+	}
+	
+	protected function getDataTableLabelValue( $archive )
+	{
+		return $archive->getIdSite();
+	}
+	
+	/**
+	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Array
+	 * which is an array of Piwik_DataTable_Simple, ordered by chronological order
+	 *
+	 * @param array|string $fields array( fieldName1, fieldName2, ...)  Names of the mysql table fields to load
+	 * @return Piwik_DataTable_Array
+	 */
+	public function getDataTableFromNumeric( $fields )
+	{
+		if(!is_array($fields))
+		{
+			$fields = array($fields);
+		}
+		$inName = "'" . implode("', '",$fields) . "'";
+		
+		
+		$numericTable = null;
+		foreach($this->archives as $archive)
+		{
+			if(is_null($numericTable))
+			{
+				$numericTable = $archive->archiveProcessing->getTableArchiveNumericName();
+			}
+			else if( $numericTable != $archive->archiveProcessing->getTableArchiveNumericName())
+			{
+				throw new Exception("Piwik_Archive_Array_IndexedBySite::getDataTableFromNumeric() algorithm won't work if data is stored in different tables");
+			}
+		}
+		
+		
+		$inIds = implode(', ', $aIds);
+		$sql = "SELECT value, name, idarchive, idsite
+								FROM $numericTable
+								WHERE idarchive IN ( $inIds )
+									AND name IN ( $inName )";
+		$values = Zend_Registry::get('db')->fetchAll($sql);
+			
+		$arrayValues = array();
+		foreach($values as $value)
+		{
+			$arrayValues[$value['idsite']][$value['name']] = $value['value'];
+		}			
+		
+		// we add empty tables so that every requested date has an entry, even if there is nothing
+		// example: <result idSite="159" />
+		$contentArray = array();
+		foreach($this->archives as $idSite => $archive)
+		{
+			$contentArray[$idSite]['table'] = new Piwik_DataTable_Simple();
+		}
+		
+		foreach($arrayValues as $idSite => $aNameValues)
+		{
+			$contentArray[$idSite]['table']->loadFromArray($aNameValues);
+		}
+		ksort( $contentArray );
+				
+		$tableArray = $this->getNewDataTableArray();
+		foreach($contentArray as $idSite => $aData)
+		{
+			$tableArray->addTable($aData['table'], $idSite);
+		}
+		return $tableArray;
+	}
+}
\ No newline at end of file

Modified: trunk/modules/Archive/Array.php
===================================================================
--- trunk/modules/Archive/Array.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Archive/Array.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -12,12 +12,11 @@
 
 require_once "DataTable/Simple.php";
 require_once "DataTable/Array.php";
-
 /**
  * This class is used to store multiple archives, when the user requests a period's archive.
  *
  */
-class Piwik_Archive_Array extends Piwik_Archive
+abstract class Piwik_Archive_Array extends Piwik_Archive
 {	
 	/**
 	 * This array contains one Piwik_Archive per entry in the period
@@ -26,58 +25,31 @@
 	 */
 	protected $archives = array();
 	
-	/**
-	 * Stores the timestamp of each archive, this is used for sorting the archives by date
-	 * 
-	 * @var array pairs(id,timestamp)
-	 */
-	protected $idArchiveToTimestamp = array();
+	abstract protected function getIndexName();
+	abstract protected function getDataTableLabelValue( $archive );
 	
-	/**
-	 * Array containing the id of the archives stored in this object
-	 * 
-	 * @var array
-	 */
-	protected $idArchives = array();
-	
-	/**
-	 * Builds an array of Piwik_Archive of a given date range
-	 *
-	 * @param Piwik_Site $oSite 
-	 * @param string $strPeriod eg. 'day' 'week' etc.
-	 * @param string $strDate A date range, eg. 'last10', 'previous5' or 'YYYY-MM-DD,YYYY-MM-DD'
-	 */
-	function __construct(Piwik_Site $oSite, $strPeriod, $strDate)
+	public function prepareArchive()
 	{
-		$rangePeriod = new Piwik_Period_Range($strPeriod, $strDate);
-		
-		// TODO fix this when aggregating data from multiple websites
-		// CAREFUL this class wouldnt work as is if handling archives from multiple websites
-		// works only when managing archives from multiples dates/periods
-		foreach($rangePeriod->getSubperiods() as $subPeriod)
+		foreach($this->archives as $archive)
 		{
-			$startDate = $subPeriod->getDateStart();
-			$archive = Piwik_Archive::build($oSite->getId(), $strPeriod, $startDate );
 			$archive->prepareArchive();
-			$timestamp = $archive->getTimestampStartDate();
-			$this->archives[$timestamp] = $archive;
 		}
-		ksort( $this->archives );
 	}
 	
 	/**
 	 * Returns a newly created Piwik_DataTable_Array.
-	 * The future elements of this array should be indexed by their dates (we set the index name to 'date').
 	 *
 	 * @return Piwik_DataTable_Array
 	 */
 	protected function getNewDataTableArray()
 	{
 		$table = new Piwik_DataTable_Array;
-		$table->setNameKey('date');
+		$table->setKeyName($this->getIndexName());
 		return $table;
 	}
-
+	
+	
+	
 	/**
 	 * Adds metaData information to the Piwik_DataTable_Array 
 	 * using the information given by the Archive
@@ -87,10 +59,6 @@
 	 */
 	protected function loadMetaData(Piwik_DataTable_Array $table, $archive)
 	{
-		$table->metaData[$archive->getPrettyDate()] = array( 
-				'timestamp' => $archive->getTimestampStartDate(),
-				'site' => $archive->getSite(),
-			);
 	}
 	
 	/**
@@ -110,7 +78,7 @@
 			$numeric = $archive->getNumeric( $name ) ;
 			$subTable = new Piwik_DataTable_Simple();
 			$subTable->loadFromArray( array( $numeric ) );
-			$table->addTable($subTable, $archive->getPrettyDate());
+			$table->addTable($subTable, $this->getDataTableLabelValue($archive));
 			
 			$this->loadMetaData($table, $archive);
 		}
@@ -118,6 +86,7 @@
 		return $table;
 	}
 	
+	
 	/**
 	 * Returns a DataTable_Array containing values 
 	 * of the element $name from the archives in this Archive_Array.
@@ -138,7 +107,7 @@
 			$blob = $archive->getBlob( $name ) ;
 			$subTable = new Piwik_DataTable_Simple();
 			$subTable->loadFromArray( array('blob' => $blob));
-			$table->addTable($subTable, $archive->getPrettyDate());
+			$table->addTable($subTable, $this->getDataTableLabelValue($archive));
 			
 			$this->loadMetaData($table, $archive);
 		}
@@ -146,87 +115,6 @@
 	}
 	
 	/**
-	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Array
-	 * which is an array of Piwik_DataTable_Simple, ordered by chronological order
-	 *
-	 * @param array|string $fields array( fieldName1, fieldName2, ...)  Names of the mysql table fields to load
-	 * @return Piwik_DataTable_Array
-	 */
-	public function getDataTableFromNumeric( $fields )
-	{
-		if(!is_array($fields))
-		{
-			$fields = array($fields);
-		}
-		
-		$inName = "'" . implode("', '",$fields) . "'";
-		
-		// we select in different shots
-		// one per distinct table (case we select last 300 days, maybe we will  select from 10 different tables)
-		$queries = array();
-		foreach($this->archives as $archive) 
-		{
-			if(!$archive->isThereSomeVisits)
-			{
-				continue;
-			}
-			
-			$table = $archive->archiveProcessing->getTableArchiveNumericName();
-
-			// for every query store IDs
-			$queries[$table][] = $archive->getIdArchive();
-		}
-		// we select the requested value
-		$db = Zend_Registry::get('db');
-		
-		// date => array( 'field1' =>X, 'field2'=>Y)
-		// date2 => array( 'field1' =>X2, 'field2'=>Y2)		
-		
-		$idarchiveToName = array();
-		foreach($queries as $table => $aIds)
-		{
-			$inIds = implode(', ', $aIds);
-			$sql = "SELECT value, name, idarchive, UNIX_TIMESTAMP(date1) as timestamp
-									FROM $table
-									WHERE idarchive IN ( $inIds )
-										AND name IN ( $inName )";
-
-			$values = $db->fetchAll($sql);
-			
-			foreach($values as $value)
-			{
-				$idarchiveToName[$value['timestamp']][$value['name']] = $value['value'];
-			}			
-		}
-		
-		// we add empty tables so that every requested date has an entry, even if there is nothing
-		// example: <result date="2007-01-01" />
-		$emptyTable = new Piwik_DataTable_Simple;
-		foreach($this->archives as $timestamp => $archive)
-		{
-			$strDate = $this->archives[$timestamp]->getPrettyDate();
-			$contentArray[$timestamp]['table'] = clone $emptyTable;
-			$contentArray[$timestamp]['prettyDate'] = $strDate;
-		}
-		
-		foreach($idarchiveToName as $timestamp => $aNameValues)
-		{
-			$contentArray[$timestamp]['table']->loadFromArray($aNameValues);
-		}
-		
-		ksort( $contentArray );
-				
-		$tableArray = $this->getNewDataTableArray();
-		foreach($contentArray as $timestamp => $aData)
-		{
-			$tableArray->addTable($aData['table'], $aData['prettyDate']);
-			
-			$this->loadMetaData($tableArray, $this->archives[$timestamp]);
-		}
-		return $tableArray;
-	}
-
-	/**
 	 * Given a BLOB field name (eg. 'Referers_searchEngineByKeyword'), it will return a Piwik_DataTable_Array
 	 * which is an array of Piwik_DataTable, ordered by chronological order
 	 * 
@@ -241,7 +129,7 @@
 		foreach($this->archives as $archive)
 		{
 			$subTable =  $archive->getDataTable( $name, $idSubTable ) ;
-			$table->addTable($subTable, $archive->getPrettyDate());
+			$table->addTable($subTable, $this->getDataTableLabelValue($archive));
 			
 			$this->loadMetaData($table, $archive);
 		}
@@ -264,7 +152,7 @@
 		foreach($this->archives as $archive)
 		{
 			$subTable =  $archive->getDataTableExpanded( $name, $idSubTable ) ;
-			$table->addTable($subTable, $archive->getPrettyDate());
+			$table->addTable($subTable, $this->getDataTableLabelValue($archive));
 			
 			$this->loadMetaData($table, $archive);
 		}

Modified: trunk/modules/Archive/Single.php
===================================================================
--- trunk/modules/Archive/Single.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Archive/Single.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -117,7 +117,6 @@
 	{
 		if(!is_null($this->archiveProcessing))
 		{
-//			var_dump($this->archiveProcessing->period->getPrettyString());
 			return $this->archiveProcessing->getTimestampStartDate();
 		}
 		
@@ -370,7 +369,16 @@
 	}
 	
 	/**
-	 * Returns a DataTable_Simple with one row per field from $fields array names.
+	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Simple 
+	 * containing one row per field name.
+	 * 
+	 * For example $fields = array( 	'max_actions',
+	 *						'nb_uniq_visitors', 
+	 *						'nb_visits',
+	 *						'nb_actions', 
+	 *						'sum_visit_length',
+	 *						'bounce_count',
+	 *					); 
 	 *
 	 * @param string|array $fields Name or array of names of Archive fields 
 	 * 

Modified: trunk/modules/Archive.php
===================================================================
--- trunk/modules/Archive.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Archive.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -71,7 +71,7 @@
 	/**
 	 * Builds an Archive object or returns the same archive if previously built.
 	 *
-	 * @param int $idSite
+	 * @param string|int idSite integer, or comma separated list of integer
 	 * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
 	 * @param string $period 'week' 'day' etc.
 	 * 
@@ -79,18 +79,33 @@
 	 */
 	static public function build($idSite, $period, $strDate )
 	{
-		$oSite = new Piwik_Site($idSite);
+		//TODO clean this method
 		
+		if($idSite === 'all')
+		{
+			$sites = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
+		}
+		else
+		{
+			$sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+		}
+		// if we have multiple idSite comma separated
+		if( count($sites) > 1 )
+		{
+			require_once 'Archive/Array/IndexedBySite.php';
+			$archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
+		}
 		// if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
-		if(is_string($strDate) 
+		elseif(is_string($strDate) 
 			&& (
 				ereg('^(last|previous){1}([0-9]*)$', $strDate, $regs)
 				|| ereg('^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})$', $strDate, $regs)
 				)
 			)
 		{
-			require_once 'Archive/Array.php';
-			$archive = new Piwik_Archive_Array($oSite, $period, $strDate);
+			$oSite = new Piwik_Site($idSite);
+			require_once 'Archive/Array/IndexedByDate.php';
+			$archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
 		}
 		// case we request a single archive
 		else
@@ -114,7 +129,7 @@
 			
 			$archive = new Piwik_Archive_Single;
 			$archive->setPeriod($oPeriod);
-			$archive->setSite($oSite);
+			$archive->setSite(new Piwik_Site($idSite));
 			
 			self::$alreadyBuilt[$idSite][$date][$period] = $archive;
 		}
@@ -122,6 +137,8 @@
 		return $archive;
 	}
 	
+	abstract public function prepareArchive();
+	
 	/**
 	 * Returns the value of the element $name from the current archive 
 	 * The value to be returned is a numeric value and is stored in the archive_numeric_* tables
@@ -143,21 +160,6 @@
 	 */
 	abstract public function getBlob( $name );
 	
-	/**
-	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Simple 
-	 * containing one row per value.
-	 * 
-	 * For example $fields = array( 	'max_actions',
-	 *						'nb_uniq_visitors', 
-	 *						'nb_visits',
-	 *						'nb_actions', 
-	 *						'sum_visit_length',
-	 *						'bounce_count',
-	 *					); 
-	 *
-	 * @param array|string $fields array( fieldName1, fieldName2, ...)
-	 * @return Piwik_DataTable_Simple
-	 */
 	abstract public function getDataTableFromNumeric( $fields );
 
 	/**
@@ -199,7 +201,7 @@
 	 *
 	 * @param Piwik_Site $site
 	 */
-	public function getSite( )
+	public function getSite()
 	{
 		return $this->site;
 	}

Modified: trunk/modules/DataTable/Array.php
===================================================================
--- trunk/modules/DataTable/Array.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Array.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -37,32 +37,32 @@
 	 * This is the label used to index the tables.
 	 * For example if the tables are indexed using the timestamp of each period
 	 * eg. $this->array[1045886960] = new Piwik_DataTable;
-	 * the nameKey would be 'timestamp'.
+	 * the keyName would be 'timestamp'.
 	 * 
 	 * This label is used in the Renderer (it becomes a column name or the XML description tag)
 	 *
 	 * @var string
 	 */
-	protected $nameKey = 'defaultKeyName';
+	protected $keyName = 'defaultKeyName';
 	
 	/**
-	 * Returns the nameKey string @see self::$nameKey
+	 * Returns the keyName string @see self::$keyName
 	 *
 	 * @return string
 	 */
-	public function getNameKey()
+	public function getKeyName()
 	{
-		return $this->nameKey;
+		return $this->keyName;
 	}
 	
 	/**
-	 * Set the nameKey @see self::$nameKey
+	 * Set the keyName @see self::$keyName
 	 *
 	 * @param string $name
 	 */
-	public function setNameKey($name)
+	public function setKeyName($name)
 	{
-		$this->nameKey = $name;
+		$this->keyName = $name;
 	}
 	
 	/**
@@ -120,7 +120,7 @@
 	 * @param Piwik_DataTable $table
 	 * @param string $label Label used to index this table in the array
 	 */
-	public function addTable( Piwik_DataTable $table, $label )
+	public function addTable( $table, $label )
 	{
 		$this->array[$label] = $table;
 	}

Modified: trunk/modules/DataTable/Renderer/Csv.php
===================================================================
--- trunk/modules/DataTable/Renderer/Csv.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Csv.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -75,7 +75,7 @@
 		if($table instanceof Piwik_DataTable_Array)
 		{
 			$str = $header = '';
-			$prefixColumns = $table->getNameKey() . $this->separator;
+			$prefixColumns = $table->getKeyName() . $this->separator;
 			foreach($table->getArray() as $currentLinePrefix => $dataTable)
 			{
 				$returned = explode("\n",$this->renderTable($dataTable));

Modified: trunk/modules/DataTable/Renderer/Html.php
===================================================================
--- trunk/modules/DataTable/Renderer/Html.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Html.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -33,7 +33,7 @@
 	{
 		if($table instanceof Piwik_DataTable_Array)
 		{
-			$columnPrefixToAdd = $table->getNameKey();
+			$columnPrefixToAdd = $table->getKeyName();
 			$out = "<table border=1>";
 			foreach($table->getArray() as $date => $subtable )
 			{

Modified: trunk/modules/DataTable/Renderer/Json.php
===================================================================
--- trunk/modules/DataTable/Renderer/Json.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Json.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -19,9 +19,9 @@
  */
 class Piwik_DataTable_Renderer_Json extends Piwik_DataTable_Renderer
 {
-	function __construct($table = null)
+	function __construct($table = null, $renderExpanded = null)
 	{
-		parent::__construct($table);
+		parent::__construct($table, $renderExpanded);
 	}
 	
 	function render()
@@ -31,8 +31,8 @@
 
 	protected function renderTable($table)
 	{
-		$renderer = new Piwik_DataTable_Renderer_Php($table, $serialize = false);
-		$array = $renderer->flatRender(null, (bool)Piwik_Common::getRequestVar('expanded', false));
+		$renderer = new Piwik_DataTable_Renderer_Php($table, $this->renderExpanded, $serialize = false);
+		$array = $renderer->flatRender();
 		
 		if(!is_array($array))
 		{

Modified: trunk/modules/DataTable/Renderer/Php.php
===================================================================
--- trunk/modules/DataTable/Renderer/Php.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Php.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -24,9 +24,9 @@
 {
 	protected $serialize;
 	
-	public function __construct($table = null, $serialize = true)
+	public function __construct($table = null, $renderExpanded = null, $serialize = true)
 	{
-		parent::__construct($table);
+		parent::__construct($table, $renderExpanded);
 		$this->setSerialize($serialize);
 	}
 	
@@ -44,6 +44,25 @@
 		}
 		return $data;
 	}
+
+	public function render( $dataTable = null )
+	{
+		if(is_null($dataTable))
+		{
+			$dataTable = $this->table;
+		}
+		$toReturn = $this->flatRender( $dataTable );
+		
+		if( false !== Piwik_Common::getRequestVar('prettyDisplay', false) )
+		{
+			if(!is_array($toReturn))
+			{
+				$toReturn = unserialize($toReturn);
+			}
+			$toReturn =  "<pre>" . var_export($toReturn, true ) . "</pre>";
+		}
+		return $toReturn;
+	}
 	
 	/**
 	 * Produces a flat php array from the DataTable, putting "columns" and "details" on the same level.
@@ -60,7 +79,7 @@
 	 * @return array Php array representing the 'flat' version of the datatable
 	 *
 	 */
-	public function flatRender( $dataTable = null, $doRenderSubTablesIfAvailable = true )
+	public function flatRender( $dataTable = null )
 	{
 		if(is_null($dataTable))
 		{
@@ -74,7 +93,7 @@
 			{
 				$serializeSave = $this->serialize;
 				$this->serialize = false;
-				$flatArray[$keyName] = $this->flatRender($table, $doRenderSubTablesIfAvailable);
+				$flatArray[$keyName] = $this->flatRender($table);
 				$this->serialize = $serializeSave;
 			}
 		}
@@ -95,7 +114,7 @@
 		// A normal DataTable needs to be handled specifically
 		else
 		{
-			$array = $this->renderTable($dataTable, $doRenderSubTablesIfAvailable);
+			$array = $this->renderTable($dataTable);
 			$flatArray = $this->flattenArray($array);
 		}
 		
@@ -126,25 +145,6 @@
 		return $flatArray;
 	}
 	
-	public function render( $dataTable = null)
-	{
-		if(is_null($dataTable))
-		{
-			$dataTable = $this->table;
-		}
-		$toReturn = $this->flatRender( $dataTable );
-		
-		if( false !== Piwik_Common::getRequestVar('prettyDisplay', false) )
-		{
-			if(!is_array($toReturn))
-			{
-				$toReturn = unserialize($toReturn);
-			}
-			$toReturn =  "<pre>" . var_export($toReturn, true ) . "</pre>";
-		}
-		return $toReturn;
-	}
-	
 	public function originalRender()
 	{
 		if($this->table instanceof Piwik_DataTable_Simple)
@@ -153,7 +153,7 @@
 		}
 		else
 		{
-			$array = $this->renderTable($this->table, $doRenderSubTablesIfAvailable = false);
+			$array = $this->renderTable($this->table);
 		}
 				
 		if($this->serialize)
@@ -164,8 +164,7 @@
 		return $array;
 	}
 	
-	
-	protected function renderTable($table, $doRenderSubTablesIfAvailable = true)
+	protected function renderTable($table)
 	{
 		$array = array();
 
@@ -177,7 +176,7 @@
 				'idsubdatatable' => $row->getIdSubDataTable(),
 				);
 			
-			if($doRenderSubTablesIfAvailable
+			if($this->renderExpanded
 				&& $row->getIdSubDataTable() !== null)
 			{
 				try{

Modified: trunk/modules/DataTable/Renderer/Rss.php
===================================================================
--- trunk/modules/DataTable/Renderer/Rss.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Rss.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -31,12 +31,12 @@
 	
 	protected function renderTable($table)
 	{
-		if(!($table instanceof Piwik_DataTable_Array))
+		if(!($table instanceof Piwik_DataTable_Array)
+			|| $table->getKeyName() != 'date')
 		{
-			throw new Exception("RSS Feed only used on DataTable_Array");
+			throw new Exception("RSS Feed only used on Piwik_DataTable_Array with keyName = 'date'");
 		}
 		
-		
 		$idSite = Piwik_Common::getRequestVar('idSite', 1);
 		$period = Piwik_Common::getRequestVar('period');
 		$currentUrl = Piwik_Url::getCurrentUrlWithoutFileName();

Modified: trunk/modules/DataTable/Renderer/Xml.php
===================================================================
--- trunk/modules/DataTable/Renderer/Xml.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer/Xml.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -22,9 +22,9 @@
  */
 class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
 {
-	function __construct($table = null)
+	function __construct($table = null, $renderExpanded = null)
 	{
-		parent::__construct($table);
+		parent::__construct($table, $renderExpanded);
 	}
 	
 	function render()
@@ -32,21 +32,36 @@
 		return $this->renderTable($this->table);
 	}
 	
-	protected function renderTable($table)
+	protected function getArrayFromDataTable($table)
 	{
-		$renderer = new Piwik_DataTable_Renderer_Php($table, $serialize = false);
+		$renderer = new Piwik_DataTable_Renderer_Php($table, $this->renderExpanded, $serialize = false);
+		return $renderer->flatRender();
+	}
+	
+	protected function renderTable($table, $returnOnlyDataTableXml = false, $prefixLines = '')
+	{
+		$array = $this->getArrayFromDataTable($table);
 		
-		$array = $renderer->flatRender(null, (bool)Piwik_Common::getRequestVar('expanded', false));
-		
 		// case DataTable_Array
 		if($table instanceof Piwik_DataTable_Array)
 		{
-			return $this->renderDataTableArray($table, $array);
+			$out = $this->renderDataTableArray($table, $array, $prefixLines);
+			
+			if($returnOnlyDataTableXml)
+			{
+				return $out;
+			}
+			$out = "<results>\n$out</results>";
+			return $this->output($out);
 		}
 	
 		// integer value of ZERO is a value we want to display
 		if($array != 0 && empty($array))
 		{
+			if($returnOnlyDataTableXml)
+			{
+				throw new Exception("Illegal state, what xml shall we return?");
+			}
 			$out = "<result />";
 			return $this->output($out);
 		}
@@ -55,11 +70,24 @@
 			if(is_array($array))
 			{
 				$out = $this->renderDataTableSimple($array);
+			}
+			else
+			{
+				$out = $array;
+			}
+		
+			if($returnOnlyDataTableXml)
+			{
+				return $out;
+			}
+			
+			if(is_array($array))
+			{
 				$out = "<result>\n".$out."</result>";
 			}
 			else
 			{
-				$out = "<result>".$array."</result>";
+				$out = "<result>".$out."</result>";
 			}
 			return $this->output($out);
 		}
@@ -67,6 +95,10 @@
 		if($table instanceof Piwik_DataTable)
 		{
 			$out = $this->renderDataTable($array);
+			if($returnOnlyDataTableXml)
+			{
+				return $out;
+			}
 			$out = "<result>\n$out</result>";
 			return $this->output($out);
 		}
@@ -74,7 +106,7 @@
 		
 	}
 	
-	protected function renderDataTableArray($table, $array)
+	protected function renderDataTableArray($table, $array, $prefixLines = "")
 	{
 		// CASE 1
 		//array
@@ -83,23 +115,28 @@
 		$firstTable = current($array);
 		if(!is_array( $firstTable ))
 		{
-	  		$xml = "<results>\n";
-	  		$nameDescriptionAttribute = $table->getNameKey();
+			$xml = '';
+	  		$nameDescriptionAttribute = $table->getKeyName();
 	  		foreach($array as $valueAttribute => $value)
 	  		{
-	  			if(!empty($value))
+	  			if(empty($value))
 	  			{
-		  			$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\">$value</result>\n";
+		  			$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";	  				
 	  			}
+	  			elseif($value instanceof Piwik_DataTable_Array )
+	  			{
+	  				$out = $this->renderTable($value, true);
+		  			//TODO somehow this code is not tested, cover this case
+	  				$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\">\n$out</result>\n";
+	  			}
 	  			else
 	  			{
-		  			$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";	  				
+		  			$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">$value</result>\n";	  				
 	  			}
 	  		}
-	  		$xml .= "</results>";
-	  		return $this->output($xml);
+	  		return $xml;
 		}
-		
+	
 		$subTables = $table->getArray();
 		$firstTable = current($subTables);
 		
@@ -115,26 +152,25 @@
   		//      'nb_visits' => string '11' 
 		if( $firstTable instanceof Piwik_DataTable_Simple)
 		{
-	  		$xml = "<results>\n";
-			$nameDescriptionAttribute = $table->getNameKey();
+			$xml = '';
+			$nameDescriptionAttribute = $table->getKeyName();
 	  		foreach($array as $valueAttribute => $dataTableSimple)
 	  		{
-	  			
+//	  			var_dump($dataTableSimple);exit;
 	  			if(count($dataTableSimple) == 0)
 				{
-					$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";
+					$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";
 				}
 	  			else
 	  			{
 		  			if(is_array($dataTableSimple))
 		  			{
-			  			$dataTableSimple = "\n" . $this->renderDataTableSimple($dataTableSimple, "\t") . "\t" ;
+			  			$dataTableSimple = "\n" . $this->renderDataTableSimple($dataTableSimple, $prefixLines . "\t") . "\t" ;
 		  			}
-		  			$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\">".$dataTableSimple."</result>\n";
+		  			$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">".$dataTableSimple. $prefixLines . "</result>\n";
 	  			}
 	  		}
-	  		$xml .= "</results>";
-	  		return $this->output($xml);
+	  		return $xml;
 		}
 		
 		// CASE 3
@@ -165,26 +201,39 @@
 		//          'nb_visits' => int 120
 		if($firstTable instanceof Piwik_DataTable)
 		{
-			$out = "<results>\n";
-			$nameDescriptionAttribute = $table->getNameKey();
+			$xml = '';
+			$nameDescriptionAttribute = $table->getKeyName();
 			foreach($array as $keyName => $arrayForSingleDate)
 			{
-				$dataTableOut = $this->renderDataTable( $arrayForSingleDate, "\t" );
-				
+//				var_dump($arrayForSingleDate);exit;
+				$dataTableOut = $this->renderDataTable( $arrayForSingleDate, $prefixLines . "\t" );
 				if(empty($dataTableOut))
 				{
-					$out .= "\t<result $nameDescriptionAttribute=\"$keyName\" />\n";
+					$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$keyName\" />\n";
 				}
 				else
 				{
-					$out .= "\t<result $nameDescriptionAttribute=\"$keyName\">\n";
-					$out .= $dataTableOut;
-					$out .= "\t</result>\n";
+					$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$keyName\">\n";
+					$xml .= $dataTableOut;
+					$xml .= $prefixLines . "\t</result>\n";
 				}
 			}
-			$out .= "</results>";
-			return $this->output($out);
+			return $xml;
 		}
+		
+		if($firstTable instanceof Piwik_DataTable_Array)
+		{
+			$xml = '';
+			$tables = $table->getArray();
+			$nameDescriptionAttribute = $table->getKeyName();
+			foreach( $tables as $valueAttribute => $tableInArray)
+			{
+				$out = $this->renderTable($tableInArray, true, $prefixLines . "\t");
+				$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">\n".$out.$prefixLines."\t</result>\n";
+	  			
+			}
+			return $xml;
+		}
 	}
 	
 	protected function renderDataTable( $array, $prefixLine = "" )

Modified: trunk/modules/DataTable/Renderer.php
===================================================================
--- trunk/modules/DataTable/Renderer.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/DataTable/Renderer.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -22,6 +22,7 @@
 abstract class Piwik_DataTable_Renderer
 {
 	protected $table;
+	protected $renderExpanded;
 	
 	/**
 	 * Builds the renderer.
@@ -29,12 +30,20 @@
 	 *
 	 * @param Piwik_DataTable|Piwik_DataTable_Simple|Piwik_DataTable_Array $table to be rendered
 	 */
-	function __construct($table = null)
+	function __construct($table = null, $renderExpanded = null)
 	{
 		if(!is_null($table))
 		{
 			$this->setTable($table);
 		}
+		if(is_null($renderExpanded))
+		{
+			$this->renderExpanded = (bool)Piwik_Common::getRequestVar('expanded', false);
+		}
+		else
+		{
+			$this->renderExpanded = $renderExpanded; 
+		}
 	}
 	
 	/**

Modified: trunk/modules/Date.php
===================================================================
--- trunk/modules/Date.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Date.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -39,7 +39,7 @@
 	 * 
 	 * @param Timestamp date OR string format 2007-01-31
 	 */
-	public function __construct(  $date  )
+	public function __construct( $date )
 	{
 		if(is_int( $date ))
 		{

Modified: trunk/modules/Site.php
===================================================================
--- trunk/modules/Site.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/Site.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -48,5 +48,20 @@
 		return new Piwik_Date($date);
 	}
 	
+	/**
+	 * @param string comma separated idSite list
+	 * @return array of valid integer
+	 */
+	static public function getIdSitesFromIdSitesString( $string )
+	{
+		$ids = explode(',', $string);
+		$validIds = array();
+		foreach($ids as $id)
+		{
+			$id = trim($id);
+			$validIds[] = $id;
+		}
+		return $validIds;
+	}
 }
 

Modified: trunk/modules/ViewDataTable.php
===================================================================
--- trunk/modules/ViewDataTable.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/modules/ViewDataTable.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -753,6 +753,10 @@
 		$data = array();
 		foreach($dataTableArray->getArray() as $keyName => $table)
 		{
+			if($table instanceof Piwik_DataTable_Array)
+			{
+				throw new Exception("Operation not supported (yet)");
+			}
 			$value = false;
 			
 			$onlyRow = $table->getFirstRow();

Modified: trunk/plugins/UsersManager/API.php
===================================================================
--- trunk/plugins/UsersManager/API.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/UsersManager/API.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -40,7 +40,8 @@
 		$db = Zend_Registry::get('db');
 		$users = $db->fetchAll("SELECT * FROM ".Piwik::prefixTable("user")." ORDER BY login ASC");
 		return $users;
-	}
+	}
+	
 	/**
 	 * Returns the list of all the users login
 	 * 
@@ -176,7 +177,6 @@
 		$user = $db->fetchRow("SELECT * 
 								FROM ".Piwik::prefixTable("user")
 								." WHERE login = ?", $userLogin);
-//		var_dump($user); exit;
 		return $user;
 	}
 	
@@ -437,7 +437,7 @@
 		// in case the idSites is an integer we build an array		
 		elseif(!is_array($idSites))
 		{
-			$idSites = array($idSites);
+			$idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
 		}
 		
 		// it is possible to set user access on websites only for the websites admin

Modified: trunk/plugins/VisitFrequency/API.php
===================================================================
--- trunk/plugins/VisitFrequency/API.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitFrequency/API.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -9,7 +9,6 @@
  * @package Piwik_VisitFrequency
  */
 
-
 /**
  * 
  * @package Piwik_VisitFrequency
@@ -39,7 +38,6 @@
 							'bounce_count_returning',
 				);
 		$dataTable = $archive->getDataTableFromNumeric($toFetch);
-
 		return $dataTable;
 	}
 
@@ -55,21 +53,24 @@
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'nb_visits_returning');
 	}
+	
 	public function getActionsReturning( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'nb_actions_returning');
 	}
+	
 	public function getMaxActionsReturning( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'max_actions_returning');
 	}
+	
 	public function getSumVisitsLengthReturning( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'sum_visit_length_returning');
 	}
+	
 	public function getBounceCountReturning( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'bounce_count_returning');
 	}
 }
-

Modified: trunk/plugins/VisitFrequency/Controller.php
===================================================================
--- trunk/plugins/VisitFrequency/Controller.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitFrequency/Controller.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -1,12 +1,11 @@
 <?php
-
 require_once "ViewDataTable.php";
+
 class Piwik_VisitFrequency_Controller extends Piwik_Controller 
 {
 	function index()
 	{
 		$view = new Piwik_View('VisitFrequency/index.tpl');
-		/* VisitFrequency */
 		$view->graphEvolutionVisitFrequency = $this->getLastVisitsReturningGraph( true );
 		$this->setSparklinesAndNumbers($view);
 		echo $view->render();
@@ -21,14 +20,12 @@
 		$view->urlSparklineMaxActionsReturning 		= $this->getUrlSparkline( 'getLastMaxActionsReturningGraph');
 		$view->urlSparklineBounceCountReturning 	= $this->getUrlSparkline( 'getLastBounceCountReturningGraph');
 		
-		$dataTableFrequency = $this->getSummary(true);
-		
+		$dataTableFrequency = $this->getSummary();
 		$view->nbVisitsReturning = $dataTableFrequency->getColumn('nb_visits_returning');
 		$view->nbActionsReturning = $dataTableFrequency->getColumn('nb_actions_returning');
 		$view->maxActionsReturning = $dataTableFrequency->getColumn('max_actions_returning');
 		$view->sumVisitLengthReturning = $dataTableFrequency->getColumn('sum_visit_length_returning');
 		$view->bounceCountReturning = $dataTableFrequency->getColumn('bounce_count_returning');
-		
 	}
 
 	function getSparklines()
@@ -37,9 +34,7 @@
 		$this->setSparklinesAndNumbers($view);		
 		echo $view->render();
 	}
-	/**
-	 * VisitFrequency
-	 */
+
 	protected function getSummary()
 	{		
 		$requestString = 'method='."VisitFrequency.getSummary".'&format=original';
@@ -76,5 +71,4 @@
 		$view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "VisitFrequency.getBounceCountReturning");
 		return $this->renderView($view, $fetch);
 	}
-	
 }

Modified: trunk/plugins/VisitFrequency/VisitFrequency.php
===================================================================
--- trunk/plugins/VisitFrequency/VisitFrequency.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitFrequency/VisitFrequency.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -33,7 +33,6 @@
 	{
 		Piwik_AddWidget( 'VisitFrequency', 'getSparklines', Piwik_Translate('VisitFrequency_WidgetOverview'));
 		Piwik_AddWidget( 'VisitFrequency', 'getLastVisitsReturningGraph', Piwik_Translate('VisitFrequency_WidgetGraphReturning'));
-
 		Piwik_AddMenu('Visitors', Piwik_Translate('VisitFrequency_SubmenuFrequency'), array('module' => 'VisitFrequency'));
 	}
 	
@@ -46,7 +45,6 @@
 		return $hooks;
 	}
 	
-	
 	function archiveMonth( $notification )
 	{
 		$archiveProcessing = $notification->getNotificationObject();
@@ -57,9 +55,7 @@
 				'sum_visit_length_returning',
 				'bounce_count_returning',
 		);
-		
 		$archiveProcessing->archiveNumericValuesSum($numericToSum);
-		
 		$archiveProcessing->archiveNumericValuesMax('max_actions_returning');
 	}
 	

Modified: trunk/plugins/VisitorInterest/API.php
===================================================================
--- trunk/plugins/VisitorInterest/API.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitorInterest/API.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -27,7 +27,6 @@
 		return self::$instance;
 	}
 
-
 	public function getNumberOfVisitsPerVisitDuration( $idSite, $period, $date )
 	{
 		Piwik::checkUserHasViewAccess( $idSite );
@@ -41,7 +40,6 @@
 		return $dataTable;
 	}
 
-
 	public function getNumberOfVisitsPerPage( $idSite, $period, $date )
 	{
 		Piwik::checkUserHasViewAccess( $idSite );
@@ -55,6 +53,7 @@
 	}
 }
 
+//TODO i18n
 function Piwik_getDurationLabel($label)
 { 
 	if(($pos = strpos($label,'-')) !== false)
@@ -80,6 +79,7 @@
 	}
 }
 
+//TODO i18n
 function Piwik_getPageGapLabel($label)
 {
 	$return = false;

Modified: trunk/plugins/VisitorInterest/Controller.php
===================================================================
--- trunk/plugins/VisitorInterest/Controller.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitorInterest/Controller.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -6,17 +6,11 @@
 	function index()
 	{
 		$view = new Piwik_View('VisitorInterest/index.tpl');
-		
-		/* Visitor Interest */
 		$view->dataTableNumberOfVisitsPerVisitDuration = $this->getNumberOfVisitsPerVisitDuration(true);
 		$view->dataTableNumberOfVisitsPerPage = $this->getNumberOfVisitsPerPage(true);
-				
 		echo $view->render();
 	}
 	
-	/**
-	 * VisitorInterest
-	 */
 	function getNumberOfVisitsPerVisitDuration( $fetch = false)
 	{
 		$view = Piwik_ViewDataTable::factory( 'cloud' );
@@ -48,6 +42,4 @@
 		
 		return $this->renderView($view, $fetch);
 	}
-	
-	
 }

Modified: trunk/plugins/VisitorInterest/VisitorInterest.php
===================================================================
--- trunk/plugins/VisitorInterest/VisitorInterest.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/plugins/VisitorInterest/VisitorInterest.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -76,7 +76,6 @@
 		return $hooks;
 	}
 	
-	
 	function archiveMonth( $notification )
 	{
 		$archiveProcessing = $notification->getNotificationObject();
@@ -85,12 +84,11 @@
 				'VisitorInterest_timeGap',
 				'VisitorInterest_pageGap',
 		);
-		
 		$archiveProcessing->archiveDataTable($dataTableToSum);
-	}
+	}
+	
 	public function archiveDay( $notification )
 	{
-		// used in protected methods
 		$this->archiveProcessing = $notification->getNotificationObject();
 
 		$recordName = 'VisitorInterest_timeGap';
@@ -100,10 +98,6 @@
 		$recordName = 'VisitorInterest_pageGap';
 		$tablePagegap = $this->getTablePageGap();
 		$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tablePagegap->getSerialized());
-		
-//		echo $tableTimegap;
-//		echo $tablePagegap;
-		
 	}
 	
 	protected function getTablePageGap()
@@ -155,16 +149,15 @@
 		$toSelect = implode(" , ", $select);
 		
 		$table = $this->archiveProcessing->getSimpleDataTableFromSelect($toSelect, Piwik_Archive::INDEX_NB_VISITS);
-//		echo $table;
 		return $table;
 	}
 	
-
 	public function headerVisitsFrequency($notification)
 	{
 		$out =& $notification->getNotificationObject();
 		$out = '<div id="leftcolumn">';
-	}
+	}
+	
 	public function footerVisitsFrequency($notification)
 	{
 		$out =& $notification->getNotificationObject();

Modified: trunk/tests/modules/DataTable/Renderer.test.php
===================================================================
--- trunk/tests/modules/DataTable/Renderer.test.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/tests/modules/DataTable/Renderer.test.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -102,7 +102,7 @@
 	function test_XML_test1()
 	{
 		$dataTable = $this->getDataTableTest();
-	  	$render = new Piwik_DataTable_Renderer_Xml($dataTable);
+	  	$render = new Piwik_DataTable_Renderer_Xml($dataTable, true);
 		$expected = '<?xml version="1.0" encoding="utf-8" ?>
 <result>
 	<row>
@@ -126,7 +126,7 @@
 		<bounce_count>90</bounce_count>
 		<url>http://www.yahoo.com</url>
 		<logo>./plugins/Referers/images/searchEngines/www.yahoo.com.png</logo>
-		<idsubdatatable>1</idsubdatatable>
+		<idsubdatatable>0</idsubdatatable>
 		<subtable>
 			<row>
 				<label>sub1</label>
@@ -140,7 +140,6 @@
 	</row>
 </result>';
 		$rendered = $render->render();
-		
 		$this->assertEqual( $expected,$rendered);
 	}
 
@@ -238,9 +237,8 @@
 	function test_JSON_test1()
 	{
 		$dataTable = $this->getDataTableTest();
-	  	$render = new Piwik_DataTable_Renderer_Json($dataTable);
-		$expected = '[{"label":"Google","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":1,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
-
+	  	$render = new Piwik_DataTable_Renderer_Json($dataTable, true);
+		$expected = '[{"label":"Google","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":0,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
 		$rendered = $render->render();
 		
 		$this->assertEqual( $expected,$rendered);
@@ -281,7 +279,7 @@
 	function test_PHP_test1()
 	{
 		$dataTable = $this->getDataTableTest();
-	  	$render = new Piwik_DataTable_Renderer_Php($dataTable);
+	  	$render = new Piwik_DataTable_Renderer_Php($dataTable, true);
 		$expected = serialize(array (
 					  0 => 
 					  array (
@@ -306,7 +304,7 @@
 					    'bounce_count' => 90,
 					    'url' => 'http://www.yahoo.com',
 					    'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png',
-					  	'idsubdatatable' => 1,
+					  	'idsubdatatable' => 0,
 					    'subtable' => 
 						    array (
 						      0 => 
@@ -322,8 +320,7 @@
 					    ),
 					  ),
 					));
-		$rendered = $render->render();
-//		var_export(unserialize($rendered));
+		$rendered = $render->render(null);
 		$this->assertEqual( $expected,$rendered);
 	}
 	function test_PHP_test2()
@@ -401,7 +398,7 @@
 		
 		
 		$table = new Piwik_DataTable_Array();
-		$table->setNameKey('testKey');
+		$table->setKeyName('testKey');
 		$table->addTable($table1, 'date1');
 		$table->addTable($table2, 'date2');
 		$table->addTable($table3, 'date3');
@@ -422,7 +419,7 @@
 		$table3 = new Piwik_DataTable_Simple;
 		
 		$table = new Piwik_DataTable_Array();
-		$table->setNameKey('testKey');
+		$table->setKeyName('testKey');
 		$table->addTable($table1, 'row1');
 		$table->addTable($table2, 'row2');
 		$table->addTable($table3, 'row3');
@@ -435,7 +432,6 @@
 		$array1 = array ( 'nb_visits' => 14.0 );
 		$table1 = new Piwik_DataTable_Simple;
 		$table1->loadFromArray($array1);
-				
 		$array2 = array ( 'nb_visits' => 15.0 );
 		$table2 = new Piwik_DataTable_Simple;
 		$table2->loadFromArray($array2);
@@ -443,7 +439,7 @@
 		$table3 = new Piwik_DataTable_Simple;
 		
 		$table = new Piwik_DataTable_Array();
-		$table->setNameKey('testKey');
+		$table->setKeyName('testKey');
 		$table->addTable($table1, 'row1');
 		$table->addTable($table2, 'row2');
 		$table->addTable($table3, 'row3');
@@ -451,6 +447,30 @@
 		return $table;
 	}
 	
+	protected function getDataTableArray_containsDataTableArray_normal()
+	{
+		$table = new Piwik_DataTable_Array();
+		$table->setKeyName('parentArrayKey');
+		$table->addTable($this->getDataTableArrayTest(), 'idSite');
+		return $table;
+	}
+	
+	protected function getDataTableArray_containsDataTableArray_simple()
+	{	
+		$table = new Piwik_DataTable_Array();
+		$table->setKeyName('parentArrayKey');
+		$table->addTable($this->getDataTableSimpleArrayTest(), 'idSite');
+		return $table;
+	}
+	
+	protected function getDataTableArray_containsDataTableArray_simpleOneRow()
+	{
+		$table = new Piwik_DataTable_Array();
+		$table->setKeyName('parentArrayKey');
+		$table->addTable($this->getDataTableSimpleOneRowArrayTest(), 'idSite');
+		return $table;
+	}
+	
 
 	/**
 	 * START TESTS DATATABLE_ARRAY
@@ -506,6 +526,53 @@
 	}
 	
 
+	function test_XML_Array_isMadeOfArray_test1()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_normal();
+	  	$render = new Piwik_DataTable_Renderer_Xml($dataTable);
+		$expected = '<?xml version="1.0" encoding="utf-8" ?>
+<results>
+	<result parentArrayKey="idSite">
+		<result testKey="date1">
+			<row>
+				<label>Google</label>
+				<nb_uniq_visitors>11</nb_uniq_visitors>
+				<nb_visits>11</nb_visits>
+				<url>http://www.google.com</url>
+				<logo>./plugins/Referers/images/searchEngines/www.google.com.png</logo>
+			</row>
+			<row>
+				<label>Yahoo!</label>
+				<nb_uniq_visitors>15</nb_uniq_visitors>
+				<nb_visits>151</nb_visits>
+				<url>http://www.yahoo.com</url>
+				<logo>./plugins/Referers/images/searchEngines/www.yahoo.com.png</logo>
+			</row>
+		</result>
+		<result testKey="date2">
+			<row>
+				<label>Google1</label>
+				<nb_uniq_visitors>110</nb_uniq_visitors>
+				<nb_visits>110</nb_visits>
+				<url>http://www.google.com1</url>
+				<logo>./plugins/Referers/images/searchEngines/www.google.com.png1</logo>
+			</row>
+			<row>
+				<label>Yahoo!1</label>
+				<nb_uniq_visitors>150</nb_uniq_visitors>
+				<nb_visits>1510</nb_visits>
+				<url>http://www.yahoo.com1</url>
+				<logo>./plugins/Referers/images/searchEngines/www.yahoo.com.png1</logo>
+			</row>
+		</result>
+		<result testKey="date3" />
+	</result>
+</results>';
+		$rendered = $render->render();
+		$this->assertEqual( $expected, $rendered);
+	}
+	
+
 	function test_XML_Array_test2()
 	{
 		$dataTable = $this->getDataTableSimpleArrayTest();
@@ -524,6 +591,30 @@
 </results>';
 		$this->assertEqual( $expected,$render->render());
 	}
+	
+	function test_XML_Array_isMadeOfArray_test2()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simple();
+	  	$render = new Piwik_DataTable_Renderer_Xml($dataTable);
+		$expected = '<?xml version="1.0" encoding="utf-8" ?>
+<results>
+	<result parentArrayKey="idSite">
+		<result testKey="row1">
+			<max_actions>14</max_actions>
+			<nb_uniq_visitors>57</nb_uniq_visitors>
+		</result>
+		<result testKey="row2">
+			<max_actions>140</max_actions>
+			<nb_uniq_visitors>570</nb_uniq_visitors>
+		</result>
+		<result testKey="row3" />
+	</result>
+</results>';
+		$rendered = $render->render();
+//		echo "$rendered\n$expected";exit;
+		$this->assertEqual( $expected,$rendered);
+	}
+
 	function test_XML_Array_test3()
 	{
 		$dataTable = $this->getDataTableSimpleOneRowArrayTest();
@@ -534,10 +625,28 @@
 	<result testKey="row2">15</result>
 	<result testKey="row3" />
 </results>';
-		$this->assertEqual( $expected,$render->render());
+		$rendered = $render->render();
+		$this->assertEqual( $expected,$rendered);
 	}
 	
+	function test_XML_Array_isMadeOfArray_test3()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simpleOneRow();
+	  	$render = new Piwik_DataTable_Renderer_Xml($dataTable);
+		$expected = '<?xml version="1.0" encoding="utf-8" ?>
+<results>
+	<result parentArrayKey="idSite">
+		<result testKey="row1">14</result>
+		<result testKey="row2">15</result>
+		<result testKey="row3" />
+	</result>
+</results>';
+		$rendered = $render->render();
+//		echo "$rendered\n$expected";exit;
+		$this->assertEqual( $expected,$rendered);
+	}
 	
+	
 
 	function test_PHP_Array_test1()
 	{
@@ -625,8 +734,98 @@
 		$this->assertEqual( $expected,$rendered);
 	}
 	
+	function test_PHP_Array_isMadeOfArray_test1()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_normal();
+	  	$render = new Piwik_DataTable_Renderer_Php($dataTable);
+	  	$rendered = $render->render();
+	  	
+		$expected = serialize(array('idSite'=> 
+			array (
+				  'date1' => 
+				  array (
+				    0 => 
+				    array (
+				      'label' => 'Google',
+				      'nb_uniq_visitors' => 11,
+				      'nb_visits' => 11,
+				      'url' => 'http://www.google.com',
+				      'logo' => './plugins/Referers/images/searchEngines/www.google.com.png',
+				    ),
+				    1 => 
+				    array (
+				      'label' => 'Yahoo!',
+				      'nb_uniq_visitors' => 15,
+				      'nb_visits' => 151,
+				      'url' => 'http://www.yahoo.com',
+				      'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png',
+				    ),
+				  ),
+				  'date2' => 
+				  array (
+				    0 => 
+				    array (
+				      'label' => 'Google1',
+				      'nb_uniq_visitors' => 110,
+				      'nb_visits' => 110,
+				      'url' => 'http://www.google.com1',
+				      'logo' => './plugins/Referers/images/searchEngines/www.google.com.png1',
+				    ),
+				    1 => 
+				    array (
+				      'label' => 'Yahoo!1',
+				      'nb_uniq_visitors' => 150,
+				      'nb_visits' => 1510,
+				      'url' => 'http://www.yahoo.com1',
+				      'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png1',
+				    ),
+				),
+				  'date3' => array (),
+				  )));
+				  
+		$this->assertEqual( $expected,$rendered);
+	}
+	function test_PHP_Array_isMadeOfArray_test2()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simple();
+	  	$render = new Piwik_DataTable_Renderer_Php($dataTable);
+	  	$rendered = $render->render();
+	  	
+		$expected = serialize(array ('idSite'=> 
+			array(
+			  'row1' => 
+			  array (
+			    'max_actions' => 14.0,
+			    'nb_uniq_visitors' => 57.0,
+			  ),
+			  'row2' => 
+			  array (
+			    'max_actions' => 140.0,
+			    'nb_uniq_visitors' => 570.0,
+			  ),
+			  'row3' => 
+			  array (
+			  ),
+			)));
+		$this->assertEqual( $expected,$rendered);
+	}
+	function test_PHP_Array_isMadeOfArray_test3()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simpleOneRow();
+	  	$render = new Piwik_DataTable_Renderer_Php($dataTable);	  	
+	  	$rendered = $render->render();
+	  
+		$expected = serialize(array ('idSite'=>  
+			array(
+				  'row1' => 14.0,
+				  'row2' => 15.0,
+				  'row3' => array(),
+				)));
+		$this->assertEqual( $expected,$rendered);
+	}
 	
 
+
 	function test_JSON_Array_test1()
 	{
 		$dataTable = $this->getDataTableArrayTest();
@@ -657,9 +856,34 @@
 		$this->assertEqual( $expected,$rendered);
 	}
 	
-	
-	
+	function test_JSON_Array_isMadeOfArray_test1()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_normal();
+	  	$render = new Piwik_DataTable_Renderer_Json($dataTable);
+	  	$rendered = $render->render();
+	  	$expected = '{"idSite":{"date1":[{"label":"Google","nb_uniq_visitors":11,"nb_visits":11,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png"}],"date2":[{"label":"Google1","nb_uniq_visitors":110,"nb_visits":110,"url":"http:\/\/www.google.com1","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png1"},{"label":"Yahoo!1","nb_uniq_visitors":150,"nb_visits":1510,"url":"http:\/\/www.yahoo.com1","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png1"}],"date3":[]}}';
+		$this->assertEqual( $expected,$rendered);
+	}
+	function test_JSON_Array_isMadeOfArray_test2()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simple();
+	  	$render = new Piwik_DataTable_Renderer_Json($dataTable);
+	  	$rendered = $render->render();
+	  	
+		$expected = '{"idSite":{"row1":{"max_actions":14,"nb_uniq_visitors":57},"row2":{"max_actions":140,"nb_uniq_visitors":570},"row3":[]}}';
 
+		$this->assertEqual( $expected,$rendered);
+	}
+
+	function test_JSON_Array_isMadeOfArray_test3()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simpleOneRow();
+	  	$render = new Piwik_DataTable_Renderer_Json($dataTable);
+	  	$rendered = $render->render();
+	  	
+		$expected = '{"idSite":{"row1":14,"row2":15,"row3":[]}}';
+		$this->assertEqual( $expected,$rendered);
+	}
 	
 	function test_CSV_Array_test1()
 	{
@@ -697,9 +921,45 @@
 	}
 	
 	
+	function test_CSV_Array_isMadeOfArray_test1()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_normal();
+	  	$render = new Piwik_DataTable_Renderer_Csv($dataTable);
+		$expected = 'parentArrayKey,testKey,label,nb_uniq_visitors,nb_visits,detail_url,detail_logo
+idSite,date1,Google,11,11,http://www.google.com,./plugins/Referers/images/searchEngines/www.google.com.png
+idSite,date1,Yahoo!,15,151,http://www.yahoo.com,./plugins/Referers/images/searchEngines/www.yahoo.com.png
+idSite,date2,Google1,110,110,http://www.google.com1,./plugins/Referers/images/searchEngines/www.google.com.png1
+idSite,date2,Yahoo!1,150,1510,http://www.yahoo.com1,./plugins/Referers/images/searchEngines/www.yahoo.com.png1';
+
+		$this->assertEqual( $expected,$render->render());
+	}
+	function test_CSV_Array_isMadeOfArray_test2()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simple();
+	  	$render = new Piwik_DataTable_Renderer_Csv($dataTable);
+		$expected = 'parentArrayKey,testKey,label,value
+idSite,row1,max_actions,14
+idSite,row1,nb_uniq_visitors,57
+idSite,row2,max_actions,140
+idSite,row2,nb_uniq_visitors,570';
+
+		$this->assertEqual( $expected,$render->render());
+	}
+
+	function test_CSV_Array_isMadeOfArray_test3()
+	{
+		$dataTable = $this->getDataTableArray_containsDataTableArray_simpleOneRow();
+	  	$render = new Piwik_DataTable_Renderer_Csv($dataTable);
+		$expected = "parentArrayKey,testKey,value
+idSite,row1,14
+idSite,row2,15";
+		$this->assertEqual( $expected,$render->render());
+	}
 	
 	
 	
+	
+	
 	/**
 	 *  test with a row without child
 	 * 			  a row with a child that has a child

Modified: trunk/tests/modules/Database.test.php
===================================================================
--- trunk/tests/modules/Database.test.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/tests/modules/Database.test.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -50,7 +50,7 @@
 		
 		if(!is_array($idSites))
 		{
-			$idSites=array($idSites);
+			$idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
 		}
 		foreach($idSites as $idsite)
 		{

Modified: trunk/tests/modules/UsersManager.test.php
===================================================================
--- trunk/tests/modules/UsersManager.test.php	2008-06-01 21:05:48 UTC (rev 505)
+++ trunk/tests/modules/UsersManager.test.php	2008-06-06 01:18:47 UTC (rev 506)
@@ -10,6 +10,7 @@
 
 
 require 'UsersManager/API.php';
+require_once 'modules/Site.php';
 
 class Test_Piwik_UsersManager extends Test_Database
 {
@@ -614,7 +615,7 @@
     	$access = Piwik_UsersManager_API::getSitesAccessFromUser("gegg4564eqgeqag");
     	$this->assertEqual( array(1), array_keys($access));
     }
-    
+
     /**
      * normal case, access set for multiple sites
      */
@@ -631,6 +632,22 @@
     	$access = Piwik_UsersManager_API::getSitesAccessFromUser("gegg4564eqgeqag");
     	$this->assertEqual( array($id1,$id3), array_keys($access));
     }
+    /**
+     * normal case, string idSites comma separated access set for multiple sites
+     */
+    function test_setUserAccess_withIdSitesIsStringCommaSeparated()
+    {
+    	
+    	Piwik_UsersManager_API::addUser("gegg4564eqgeqag", "geqgegagae", "tegst at tesgt.com", "alias");
+    	$id1=Piwik_SitesManager_API::addSite("test",array("http://piwik.net","http://piwik.com/test/"));
+		$id2=Piwik_SitesManager_API::addSite("test",array("http://piwik.net","http://piwik.com/test/"));
+		$id3=Piwik_SitesManager_API::addSite("test",array("http://piwik.net","http://piwik.com/test/"));
+		
+    	Piwik_UsersManager_API::setUserAccess("gegg4564eqgeqag", "view", "1,3");
+    	
+    	$access = Piwik_UsersManager_API::getSitesAccessFromUser("gegg4564eqgeqag");
+    	$this->assertEqual( array($id1,$id3), array_keys($access));
+    }
     
     
     /**



More information about the Piwik-svn mailing list