[Piwik-svn] r179 - in trunk: . config misc modules modules/API modules/Archive modules/DataTable modules/DataTable/Renderer plugins/Installation tests/modules

svnmaster at piwik.org svnmaster at piwik.org
Thu Jan 17 05:58:59 CET 2008


Author: matt
Date: 2008-01-17 05:58:59 +0100 (Thu, 17 Jan 2008)
New Revision: 179

Added:
   trunk/modules/Archive/
   trunk/modules/Archive/Array.php
   trunk/modules/Archive/Single.php
   trunk/modules/DataTable/Array.php
Modified:
   trunk/config/global.ini.php
   trunk/index.php
   trunk/misc/generateVisits.php
   trunk/modules/API/Request.php
   trunk/modules/Archive.php
   trunk/modules/ArchiveProcessing.php
   trunk/modules/DataTable.php
   trunk/modules/DataTable/Renderer.php
   trunk/modules/DataTable/Renderer/Console.php
   trunk/modules/Date.php
   trunk/modules/FrontController.php
   trunk/modules/Period.php
   trunk/modules/Piwik.php
   trunk/modules/Site.php
   trunk/modules/TablePartitioning.php
   trunk/plugins/Installation/Controller.php
   trunk/tests/modules/Period.test.php
   trunk/tests/modules/TablePartitioning.test.php
Log:
Approximately 40% work done on #38
needs to implement stuff in Archive_Array
Redo the renderers to handle the DataTable_Array structure
Add correct date output 


Modified: trunk/config/global.ini.php
===================================================================
--- trunk/config/global.ini.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/config/global.ini.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -10,14 +10,12 @@
 dbname			= 
 tables_prefix	= 
 adapter			= PDO_MYSQL ; PDO_MYSQL or MYSQLI
-;is it used? if yes add it in the session array in the installation
-;profiler 		= false
 
 [database_tests]
 host 			= localhost
 username 		= root
 password 		= 
-dbname			= piwik_tests5
+dbname			= piwik_tests6
 tables_prefix	= piwiktests_
 adapter 		= PDO_MYSQL
 
@@ -51,12 +49,12 @@
 [Debug]
 ; if set to true, the archiving process will always be triggered, even if the archive has already been computed
 ; this is useful when making changes to the archiving code so we can 
-always_archive_data = true
+always_archive_data = false
 
 [General]
 ; Time in seconds after which an archive will be computed again. 
 ; This setting is used only for today's statistics.
-time_before_archive_considered_outdated = 300
+time_before_archive_considered_outdated = 600
 
 ; character used to automatically create categories in the "Action" "Downloads" reports
 ; for example a URL like "example.com/blog/development/first-post" will create 

Modified: trunk/index.php
===================================================================
--- trunk/index.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/index.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -22,7 +22,7 @@
 require_once PIWIK_INCLUDE_PATH . "/modules/testMinimumPhpVersion.php";
 
 
-date_default_timezone_set('Europe/London');
+//date_default_timezone_set('Europe/London');
 if(!defined('ENABLE_DISPATCH'))
 {
 	define('ENABLE_DISPATCH', true);	

Modified: trunk/misc/generateVisits.php
===================================================================
--- trunk/misc/generateVisits.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/misc/generateVisits.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -52,7 +52,7 @@
  * Generate visits / actions for the last 31 days
  */
 
-$daysToCompute = 1;
+$daysToCompute = 50;
 
 // do NOT edit this line
 $startTime = time() - ($daysToCompute-1)*86400;

Modified: trunk/modules/API/Request.php
===================================================================
--- trunk/modules/API/Request.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/API/Request.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -63,7 +63,14 @@
 		}
 		
 		// remove all spaces from parameters values (when calling internally the API for example)
-		$requestArray = array_map('trim',$requestArray);
+		foreach($requestArray as &$element)
+		{
+			// sometimes GET parameters can be arrays but we assume module accepting arrays are correctly handling spaces
+			if(!is_array($element))
+			{
+				$element = trim($element);
+			}			
+		}
 		
 		$this->requestToUse = $requestArray;
 	}
@@ -220,15 +227,26 @@
 		// If the returned value is an object DataTable we
 		// apply the set of generic filters if asked in the URL
 		// and we render the DataTable according to the format specified in the URL
-		if($returnedValue instanceof Piwik_DataTable)
-		{			
-			$this->applyDataTableGenericFilters($returnedValue);
+		if($returnedValue instanceof Piwik_DataTable
+			|| $returnedValue instanceof Piwik_DataTable_Array)
+		{
+			if($returnedValue instanceof Piwik_DataTable)
+			{
+				$this->applyDataTableGenericFilters($returnedValue);
+			}
+			elseif($returnedValue instanceof Piwik_DataTable_Array)
+			{
+				$tables = $returnedValue->getArray();
+				foreach($tables as $table)
+				{
+					$this->applyDataTableGenericFilters($table);
+				}
+			}
 			
 			$returnedValue->applyQueuedFilters();
 			
-			$toReturn = $this->getRenderedDataTable($returnedValue);
+			$toReturn = $this->getRenderedDataTable($returnedValue);
 			
-			
 		}
 		
 		// Case nothing returned (really nothing was 'return'ed), 

Added: trunk/modules/Archive/Array.php
===================================================================
--- trunk/modules/Archive/Array.php	                        (rev 0)
+++ trunk/modules/Archive/Array.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -0,0 +1,180 @@
+<?php
+
+require_once "DataTable/Array.php";
+
+class Piwik_Archive_Array extends Piwik_Archive
+{	
+	protected $archives = array();
+	
+	
+	function __construct(Piwik_Site $oSite, $strPeriod, $strDate)
+	{
+		$rangePeriod = new Piwik_Period_Range($strPeriod, $strDate);
+		
+		foreach($rangePeriod->getSubperiods() as $subPeriod)
+		{
+			$archive = Piwik_Archive::build($oSite->getId(), $strPeriod, $subPeriod->getDateStart() );
+			$archive->prepareArchive();
+		
+			$this->archives[$archive->getIdArchive()] = $archive;
+			$this->idArchives[] = $archive->getIdArchive();
+		}
+		
+		$this->inIdArchives = implode("",$this->idArchives);
+	}
+	
+	
+	/**
+	 * 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
+	 *
+	 * @param string $name For example Referers_distinctKeywords 
+	 * @return float|int|false False if no value with the given name
+	 */
+	public function getNumeric( $name )
+	{
+		$table = new Piwik_DataTable_Array;
+		return $table;
+	}
+	
+	/**
+	 * Returns the value of the element $name from the current archive
+	 * 
+	 * The value to be returned is a blob value and is stored in the archive_numeric_* tables
+	 * 
+	 * It can return anything from strings, to serialized PHP arrays or PHP objects, etc.
+	 *
+	 * @param string $name For example Referers_distinctKeywords 
+	 * @return mixed False if no value with the given name
+	 */
+	public function getBlob( $name )
+	{
+		$table = new Piwik_DataTable_Array;
+		return $table;
+	}
+	
+	/**
+	 * 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 $fields array( fieldName1, fieldName2, ...)
+	 * @return Piwik_DataTable_Simple
+	 */
+	public function getDataTableFromNumeric( $fields )
+	{
+		// Simple algorithm not efficient
+//		$table = new Piwik_DataTable_Array;
+//		foreach($this->archives as $archive)
+//		{
+//			$subTable =  $archive->getDataTableFromNumeric( $fields ) ;
+//			$table->addTable($subTable, $archive->getPrettyDate());
+//		}
+//		return $table;
+
+//		$fields = $fields[1];
+		require_once "DataTable/Simple.php";
+		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)
+		
+		$tableArray = new Piwik_DataTable_Array;
+		
+		foreach($queries as $table => $aIds)
+		{
+			$inIds = implode(', ', $aIds);
+			$sql = "SELECT value, name, idarchive
+									FROM $table
+									WHERE idarchive IN ( $inIds )
+										AND name IN ( $inName )";
+
+			$values = $db->fetchAll($sql);
+			
+			$idarchiveToName = array();
+			foreach($values as $value)
+			{
+				$idarchiveToName[$value['idarchive']][$value['name']] = $value['value'];
+			}
+//			var_dump($idarchiveToName);exit;
+			
+			foreach($idarchiveToName as $id => $aNameValues)
+			{
+				$strDate = $this->archives[$id]->getPrettyDate();
+				
+				$table = new Piwik_DataTable_Simple;
+				$table->loadFromArray($aNameValues);
+				
+//				echo $table; echo $strDate;exit;
+				$tableArray->addTable($table, $strDate);
+			}
+		}
+				
+		return $tableArray;
+	}
+
+	/**
+	 * This method will build a dataTable from the blob value $name in the current archive.
+	 * 
+	 * For example $name = 'Referers_searchEngineByKeyword' will return a  Piwik_DataTable containing all the keywords
+	 * If a idSubTable is given, the method will return the subTable of $name 
+	 * 
+	 * @param string $name
+	 * @param int $idSubTable
+	 * @return Piwik_DataTable
+	 * @throws exception If the value cannot be found
+	 */
+	public function getDataTable( $name, $idSubTable = null )
+	{		
+		$table = new Piwik_DataTable_Array;
+		return $table;
+	}
+	
+	
+	/**
+	 * Same as getDataTable() except that it will also load in memory
+	 * all the subtables for the DataTable $name. 
+	 * You can then access the subtables by using the Piwik_DataTable_Manager getTable() 
+	 *
+	 * @param string $name
+	 * @param int $idSubTable
+	 * @return Piwik_DataTable
+	 */
+	public function getDataTableExpanded($name, $idSubTable = null)
+	{
+		$table = new Piwik_DataTable_Array;
+		return $table;
+	}
+}
\ No newline at end of file

Added: trunk/modules/Archive/Single.php
===================================================================
--- trunk/modules/Archive/Single.php	                        (rev 0)
+++ trunk/modules/Archive/Single.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -0,0 +1,311 @@
+<?php
+class Piwik_Archive_Single extends Piwik_Archive
+{
+	public $archiveProcessing = null;
+	public $isThereSomeVisits = false;
+
+	protected $period = null;
+	
+	protected $blobCached = array();
+	protected $cacheEnabledForNumeric = true;
+	protected $numericCached = array();
+	protected $idArchive = null;
+	
+	public function getPrettyDate()
+	{
+		$str = $this->period->getLabel() . " from " . $this->period->getDateStart()->toString() . " to " . $this->period->getDateEnd()->toString();
+		return $str;
+	}
+	
+	public function getIdArchive()
+	{
+		return $this->idArchive;
+	}
+	
+	/**
+	 * Set the period 
+	 *
+	 * @param Piwik_Period $period
+	 */
+	public function setPeriod( Piwik_Period $period )
+	{
+		$this->period = $period;
+	}
+	
+		
+	/**
+	 * Prepares the archive. Gets the idarchive from the ArchiveProcessing.
+	 * 
+	 * This will possibly launch the archiving process if the archive was not available.
+	 * 
+	 * @return void
+	 */
+	public function prepareArchive()
+	{
+		if(!$this->alreadyChecked)
+		{
+			// we make sure the archive is available for the given date
+			$periodLabel = $this->period->getLabel();
+			$archiveProcessing = Piwik_ArchiveProcessing::factory($periodLabel);
+			$archiveProcessing->setSite($this->site);
+			$archiveProcessing->setPeriod($this->period);
+			$IdArchive = $archiveProcessing->loadArchive();
+			
+			$this->archiveProcessing = $archiveProcessing;
+			$isThereSomeVisits = Zend_Registry::get('db')->fetchOne(
+					'SELECT value 
+					FROM '.$archiveProcessing->getTableArchiveNumericName().
+					' WHERE name = ? AND idarchive = ?', array('nb_visits',$IdArchive));
+					
+			if($isThereSomeVisits!==false)
+			{
+				$this->isThereSomeVisits = true;
+			}
+			$this->idArchive = $IdArchive;
+			$this->alreadyChecked = true;
+		}
+	}
+	
+	/**
+	 * Returns a value from the current archive with the name = $name 
+	 * Method used by getNumeric or getBlob
+	 *
+	 * @param string $name
+	 * @param string $typeValue numeric|blob
+	 * @return mixed|false if no result
+	 */
+	protected function get( $name, $typeValue = 'numeric' )
+	{
+		// values previously "get" and now cached
+		if($typeValue == 'numeric'
+			&& $this->cacheEnabledForNumeric
+			&& isset($this->numericCached[$name])
+			)
+		{
+			return $this->numericCached[$name];
+		}
+		
+		// During archiving we prefetch the blobs recursively
+		// and we get them faster from memory after
+		if($typeValue == 'blob'
+			&& isset($this->blobCached[$name]))
+		{
+			return $this->blobCached[$name];
+		}
+		
+		$this->prepareArchive();
+				
+		if($name == 'idarchive')
+		{
+			return $this->idArchive;
+		}
+		
+//		Piwik::log("-- get '$name'");
+		
+		if(!$this->isThereSomeVisits)
+		{
+			return false;
+		}
+
+		// select the table to use depending on the type of the data requested		
+		switch($typeValue)
+		{
+			case 'blob':
+				$table = $this->archiveProcessing->getTableArchiveBlobName();
+			break;
+
+			case 'numeric':
+			default:
+				$table = $this->archiveProcessing->getTableArchiveNumericName();
+			break;
+		}
+
+		// we select the requested value
+		$db = Zend_Registry::get('db');
+		$value = $db->fetchOne("SELECT value 
+								FROM $table
+								WHERE idarchive = ?
+									AND name = ?",	
+								array( $this->idArchive , $name) 
+							);
+
+		// no result, returns false
+		if($value === false)
+		{
+			if($typeValue == 'numeric' 
+				&& $this->cacheEnabledForNumeric)
+			{
+				// we cache the results
+				$this->numericCached[$name] = false;
+			}	
+			return $value;
+		}
+		
+		// uncompress when selecting from the BLOB table
+		if($typeValue == 'blob')
+		{
+			$value = gzuncompress($value);
+		}
+		
+		if($typeValue == 'numeric' 
+			&& $this->cacheEnabledForNumeric)
+		{
+			// we cache the results
+			$this->numericCached[$name] = $value;
+		}
+		return $value;
+	}
+	
+	
+	/**
+	 * This method loads in memory all the subtables for the main table called $name.
+	 * You have to give it the parent table $dataTableToLoad so we can lookup the sub tables ids to load.
+	 * 
+	 * If $addDetailSubtableId set to true, it will add for each row a 'detail' called 'databaseSubtableId' 
+	 *  containing the child ID of the subtable  associated to this row.
+	 *
+	 * @param string $name
+	 * @param Piwik_DataTable $dataTableToLoad
+	 * @param bool $addDetailSubtableId
+	 * 
+	 * @return void
+	 */
+	public function loadSubDataTables($name, Piwik_DataTable $dataTableToLoad, $addDetailSubtableId = false)
+	{
+		// we have to recursively load all the subtables associated to this table's rows
+		// and update the subtableID so that it matches the newly instanciated table 
+		foreach($dataTableToLoad->getRows() as $row)
+		{
+			$subTableID = $row->getIdSubDataTable();
+			
+			if($subTableID !== null)
+			{
+				$subDataTableLoaded = $this->getDataTable($name, $subTableID);
+				
+				$this->loadSubDataTables($name, $subDataTableLoaded);
+				
+				// we edit the subtable ID so that it matches the newly table created in memory
+				// NB:
+				// we dont do that in the case we are displaying the table expanded.
+				// in this case we wan't the user to see the REAL dataId in the database
+				if($addDetailSubtableId)
+				{
+					$row->addDetail('databaseSubtableId', $row->getIdSubDataTable());
+				}
+				$row->setSubtable( $subDataTableLoaded );
+			}
+		}
+	}
+
+	
+	/**
+	 * Free the blob cache memory array
+	 *
+	 * @return void
+	 */
+	public function freeBlob( $name )
+	{
+		// we delete the blob
+		$this->blobCached = null; 
+		$this->blobCached = array(); 
+	}
+	
+	/**
+	 * Fetches all blob fields name_* at once for the current archive for performance reasons.
+	 * 
+	 * @return void
+	 */
+	public function preFetchBlob( $name )
+	{
+//		Piwik::log("-- prefetch blob ".$name."_*");
+		
+		if(!$this->isThereSomeVisits)
+		{
+			return false;
+		}
+
+		$tableBlob = $this->archiveProcessing->getTableArchiveBlobName();
+
+		// we select the requested value
+		$db = Zend_Registry::get('db');
+		$query = $db->query("SELECT value, name
+								FROM $tableBlob
+								WHERE idarchive = ?
+									AND name LIKE '$name%'",	
+								array( $this->idArchive ) 
+							);
+
+		while($row = $query->fetch())
+		{
+			$value = $row['value'];
+			$name = $row['name'];
+						
+			$this->blobCached[$name] = gzuncompress($value);
+		}
+	}
+	
+	
+	public function getNumeric( $name )
+	{
+		// we cast the result as float because returns false when no visitors
+		return (float)$this->get($name, 'numeric');
+	}
+
+	public function getBlob( $name )
+	{
+		return $this->get($name, 'blob');		
+	}
+	
+	public function getDataTableFromNumeric( $fields )
+	{
+		require_once "DataTable/Simple.php";
+		if(!is_array($fields))
+		{
+			$fields = array($fields);
+		}
+		
+		$values = array();
+		foreach($fields as $field)
+		{
+			$values[$field] = $this->getNumeric($field);
+		}
+		
+		$table = new Piwik_DataTable_Simple;
+		$table->loadFromArray($values);
+		return $table;
+	}
+	
+	public function getDataTable( $name, $idSubTable = null )
+	{
+		if(!is_null($idSubTable))
+		{
+			$name .= "_$idSubTable";
+		}
+		
+		$data = $this->get($name, 'blob');
+		
+		$table = new Piwik_DataTable;
+		
+		if($data !== false)
+		{
+			$table->loadFromSerialized($data);
+		}
+		
+		if($data === false 
+			&& $idSubTable !== null)
+		{
+			throw new Exception("You are requesting a precise subTable but there is not such data in the Archive.");
+		}
+	
+		return $table;
+	}
+	
+	public function getDataTableExpanded($name, $idSubTable = null)
+	{
+		$this->preFetchBlob($name);
+		$dataTableToLoad = $this->getDataTable($name, $idSubTable);
+		$this->loadSubDataTables($name, $dataTableToLoad, $addDetailSubtableId = true);
+		return $dataTableToLoad;		
+	}
+}
+?>
\ No newline at end of file

Modified: trunk/modules/Archive.php
===================================================================
--- trunk/modules/Archive.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/Archive.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -11,8 +11,9 @@
 
  
 require_once 'Period.php';
-require_once 'Date.php';
-require_once 'ArchiveProcessing.php';
+require_once 'Date.php';
+require_once 'ArchiveProcessing.php';
+require_once 'Archive/Single.php';
 
 /**
  * Architecture
@@ -32,7 +33,7 @@
  * @package Piwik
  */
 
-class Piwik_Archive
+abstract class Piwik_Archive
 {
 	const INDEX_NB_UNIQ_VISITORS = 1;
 	const INDEX_NB_VISITS = 2;
@@ -40,50 +41,54 @@
 	const INDEX_MAX_ACTIONS = 4;
 	const INDEX_SUM_VISIT_LENGTH = 5;
 	const INDEX_BOUNCE_COUNT = 6;
-	
-	protected $period = null;
-	protected $id = null;
-	protected $isThereSomeVisits = false;
+
 	protected $alreadyChecked = false;
-	protected $archiveProcessing = null;
-	protected $blobCached = array();
-	
-	protected $cacheEnabledForNumeric = true;
-	
-	public function __construct()
-	{
-	}
-	
+		
 	static protected $alreadyBuilt = array();
 	
 	/**
 	 * Builds an Archive object or returns the same archive if previously built.
 	 *
 	 * @param int $idSite
-	 * @param string $date 'YYYY-MM-DD' or magic keywords 'today' See Piwik_Date::factory
+	 * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' See Piwik_Date::factory
 	 * @param string $period 'week' 'day' etc.
 	 * @return Piwik_Archive
 	 */
-	static public function build($idSite, $period, $date )
+	static public function build($idSite, $period, $oDate )
 	{
-//		$archive = new Piwik_Archive_Single($date,);
-		
-		$oDate = Piwik_Date::factory($date);
-		$date = $oDate->toString();
-		if(isset(self::$alreadyBuilt[$idSite][$date][$period]))
+		$oSite = new Piwik_Site($idSite);
+			
+		if(is_string($oDate) 
+			&& ereg('last([0-9]*)', $oDate, $regs))
 		{
-			return self::$alreadyBuilt[$idSite][$date][$period];
+			require_once 'Archive/Array.php';
+			
+			$archive = new Piwik_Archive_Array($oSite, $period, $oDate);
+			
 		}
+		else
+		{			
 		
-		$oPeriod = Piwik_Period::factory($period, $oDate);
-		$oSite = new Piwik_Site($idSite);
+			if(is_string($oDate))
+			{
+				$oDate = Piwik_Date::factory($oDate);
+			}
+			$date = $oDate->toString();
+			
+			if(isset(self::$alreadyBuilt[$idSite][$date][$period]))
+			{
+				return self::$alreadyBuilt[$idSite][$date][$period];
+			}
+			
+			$oPeriod = Piwik_Period::factory($period, $oDate);
+			
+			$archive = new Piwik_Archive_Single;
+			$archive->setPeriod($oPeriod);
+			$archive->setSite($oSite);
+			
+			self::$alreadyBuilt[$idSite][$date][$period] = $archive;
+		}
 		
-		
-		$archive = new Piwik_Archive;
-		$archive->setPeriod($oPeriod);
-		$archive->setSite($oSite);
-		
-		self::$alreadyBuilt[$idSite][$date][$period] = $archive;
 		return $archive;
 	}
 	
@@ -94,11 +99,7 @@
 	 * @param string $name For example Referers_distinctKeywords 
 	 * @return float|int|false False if no value with the given name
 	 */
-	public function getNumeric( $name )
-	{
-		// we cast the result as float because returns false when no visitors
-		return (float)$this->get($name, 'numeric');
-	}
+	abstract public function getNumeric( $name );
 	
 	/**
 	 * Returns the value of the element $name from the current archive
@@ -110,10 +111,7 @@
 	 * @param string $name For example Referers_distinctKeywords 
 	 * @return mixed False if no value with the given name
 	 */
-	public function getBlob( $name )
-	{
-		return $this->get($name, 'blob');		
-	}
+	abstract public function getBlob( $name );
 	
 	/**
 	 * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Simple 
@@ -130,24 +128,7 @@
 	 * @param array $fields array( fieldName1, fieldName2, ...)
 	 * @return Piwik_DataTable_Simple
 	 */
-	public function getDataTableFromNumeric( $fields )
-	{
-		require_once "DataTable/Simple.php";
-		if(!is_array($fields))
-		{
-			$fields = array($fields);
-		}
-		
-		$values = array();
-		foreach($fields as $field)
-		{
-			$values[$field] = $this->getNumeric($field);
-		}
-		
-		$table = new Piwik_DataTable_Simple;
-		$table->loadFromArray($values);
-		return $table;
-	}
+	abstract public function getDataTableFromNumeric( $fields );
 
 	/**
 	 * This method will build a dataTable from the blob value $name in the current archive.
@@ -160,30 +141,7 @@
 	 * @return Piwik_DataTable
 	 * @throws exception If the value cannot be found
 	 */
-	public function getDataTable( $name, $idSubTable = null )
-	{
-		if(!is_null($idSubTable))
-		{
-			$name .= "_$idSubTable";
-		}
-		
-		$data = $this->get($name, 'blob');
-		
-		$table = new Piwik_DataTable;
-		
-		if($data !== false)
-		{
-			$table->loadFromSerialized($data);
-		}
-		
-		if($data === false 
-			&& $idSubTable !== null)
-		{
-			throw new Exception("You are requesting a precise subTable but there is not such data in the Archive.");
-		}
-	
-		return $table;
-	}
+	abstract public function getDataTable( $name, $idSubTable = null );
 
 	/**
 	 * Same as getDataTable() except that it will also load in memory
@@ -194,115 +152,9 @@
 	 * @param int $idSubTable
 	 * @return Piwik_DataTable
 	 */
-	public function getDataTableExpanded($name, $idSubTable = null)
-	{
-		$this->preFetchBlob($name);
-		$dataTableToLoad = $this->getDataTable($name, $idSubTable);
-		$this->loadSubDataTables($name, $dataTableToLoad, $addDetailSubtableId = true);
-		return $dataTableToLoad;		
-	}
-	
-	/**
-	 * Returns a value from the current archive with the name = $name 
-	 * Method used by getNumeric or getBlob
-	 *
-	 * @param string $name
-	 * @param string $typeValue numeric|blob
-	 * @return mixed|false if no result
-	 */
-	protected function get( $name, $typeValue = 'numeric' )
-	{
-		// values previously "get" and now cached
-		if($typeValue == 'numeric'
-			&& $this->cacheEnabledForNumeric
-			&& isset($this->numericCached[$name])
-			)
-		{
-			return $this->numericCached[$name];
-		}
-		
-		// During archiving we prefetch the blobs recursively
-		// and we get them faster from memory after
-		if($typeValue == 'blob'
-			&& isset($this->blobCached[$name]))
-		{
-			return $this->blobCached[$name];
-		}
-		
-		$this->prepareArchive();
-				
-		if($name == 'idarchive')
-		{
-			return $this->idArchive;
-		}
-		
-//		Piwik::log("-- get '$name'");
-		
-		if(!$this->isThereSomeVisits)
-		{
-			return false;
-		}
+	abstract public function getDataTableExpanded($name, $idSubTable = null);
 
-		// select the table to use depending on the type of the data requested		
-		switch($typeValue)
-		{
-			case 'blob':
-				$table = $this->archiveProcessing->getTableArchiveBlobName();
-			break;
-
-			case 'numeric':
-			default:
-				$table = $this->archiveProcessing->getTableArchiveNumericName();
-			break;
-		}
-
-		// we select the requested value
-		$db = Zend_Registry::get('db');
-		$value = $db->fetchOne("SELECT value 
-								FROM $table
-								WHERE idarchive = ?
-									AND name = ?",	
-								array( $this->idArchive , $name) 
-							);
-
-		// no result, returns false
-		if($value === false)
-		{
-			if($typeValue == 'numeric' 
-				&& $this->cacheEnabledForNumeric)
-			{
-				// we cache the results
-				$this->numericCached[$name] = false;
-			}	
-			return $value;
-		}
-		
-		// uncompress when selecting from the BLOB table
-		if($typeValue == 'blob')
-		{
-			$value = gzuncompress($value);
-		}
-		
-		if($typeValue == 'numeric' 
-			&& $this->cacheEnabledForNumeric)
-		{
-			// we cache the results
-			$this->numericCached[$name] = $value;
-		}
-		return $value;
-	}
-	
 	/**
-	 * Set the period 
-	 *
-	 * @param Piwik_Period $period
-	 */
-	public function setPeriod( Piwik_Period $period )
-	{
-		$this->period = $period;
-	}
-	
-	/**
 	 * Set the site
 	 *
 	 * @param Piwik_Site $site
@@ -321,127 +173,7 @@
 	{
 		return $this->site->getId();
 	}
-	
-	/**
-	 * Prepares the archive. Gets the idarchive from the ArchiveProcessing.
-	 * 
-	 * This will possibly launch the archiving process if the archive was not available.
-	 * 
-	 * @return void
-	 */
-	public function prepareArchive()
-	{
-		if(!$this->alreadyChecked)
-		{
-			// we make sure the archive is available for the given date
-			$periodLabel = $this->period->getLabel();
-			$archiveProcessing = Piwik_ArchiveProcessing::factory($periodLabel);
-			$archiveProcessing->setSite($this->site);
-			$archiveProcessing->setPeriod($this->period);
-			$IdArchive = $archiveProcessing->loadArchive();
-			
-			$this->archiveProcessing = $archiveProcessing;
-			$isThereSomeVisits = Zend_Registry::get('db')->fetchOne(
-					'SELECT value 
-					FROM '.$archiveProcessing->getTableArchiveNumericName().
-					' WHERE name = ? AND idarchive = ?', array('nb_visits',$IdArchive));
-					
-			if($isThereSomeVisits!==false)
-			{
-				$this->isThereSomeVisits = true;
-			}
-			$this->idArchive = $IdArchive;
-			$this->alreadyChecked = true;
-		}
-	}
 	
-	/**
-	 * This method loads in memory all the subtables for the main table called $name.
-	 * You have to give it the parent table $dataTableToLoad so we can lookup the sub tables ids to load.
-	 * 
-	 * If $addDetailSubtableId set to true, it will add for each row a 'detail' called 'databaseSubtableId' 
-	 *  containing the child ID of the subtable  associated to this row.
-	 *
-	 * @param string $name
-	 * @param Piwik_DataTable $dataTableToLoad
-	 * @param bool $addDetailSubtableId
-	 * 
-	 * @return void
-	 */
-	public function loadSubDataTables($name, Piwik_DataTable $dataTableToLoad, $addDetailSubtableId = false)
-	{
-		// we have to recursively load all the subtables associated to this table's rows
-		// and update the subtableID so that it matches the newly instanciated table 
-		foreach($dataTableToLoad->getRows() as $row)
-		{
-			$subTableID = $row->getIdSubDataTable();
-			
-			if($subTableID !== null)
-			{
-				$subDataTableLoaded = $this->getDataTable($name, $subTableID);
-				
-				$this->loadSubDataTables($name, $subDataTableLoaded);
-				
-				// we edit the subtable ID so that it matches the newly table created in memory
-				// NB:
-				// we dont do that in the case we are displaying the table expanded.
-				// in this case we wan't the user to see the REAL dataId in the database
-				if($addDetailSubtableId)
-				{
-					$row->addDetail('databaseSubtableId', $row->getIdSubDataTable());
-				}
-				$row->setSubtable( $subDataTableLoaded );
-			}
-		}
-	}
-	
-	
-	
-	/**
-	 * Free the blob cache memory array
-	 *
-	 * @return void
-	 */
-	public function freeBlob( $name )
-	{
-		// we delete the blob
-		$this->blobCached = null; 
-		$this->blobCached = array(); 
-	}
-	
-	/**
-	 * Fetches all blob fields name_* at once for the current archive for performance reasons.
-	 * 
-	 * @return void
-	 */
-	public function preFetchBlob( $name )
-	{
-//		Piwik::log("-- prefetch blob ".$name."_*");
-		
-		if(!$this->isThereSomeVisits)
-		{
-			return false;
-		}
-
-		$tableBlob = $this->archiveProcessing->getTableArchiveBlobName();
-
-		// we select the requested value
-		$db = Zend_Registry::get('db');
-		$query = $db->query("SELECT value, name
-								FROM $tableBlob
-								WHERE idarchive = ?
-									AND name LIKE '$name%'",	
-								array( $this->idArchive ) 
-							);
-
-		while($row = $query->fetch())
-		{
-			$value = $row['value'];
-			$name = $row['name'];
-						
-			$this->blobCached[$name] = gzuncompress($value);
-		}
-	}
 }
 
 

Modified: trunk/modules/ArchiveProcessing.php
===================================================================
--- trunk/modules/ArchiveProcessing.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/ArchiveProcessing.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -154,21 +154,21 @@
 	/**
 	 * Returns the name of the numeric table where the archive numeric values are stored
 	 *
-	 * @return Piwik_TablePartitioning 
+	 * @return string 
 	 */
 	public function getTableArchiveNumericName()
 	{
-		return $this->tableArchiveNumeric;
+		return (string)$this->tableArchiveNumeric;
 	}
 	
 	/**
 	 * Returns the name of the blob table where the archive blob values are stored
 	 *
-	 * @return Piwik_TablePartitioning 
+	 * @return string 
 	 */
 	public function getTableArchiveBlobName()
 	{
-		return $this->tableArchiveBlob;
+		return (string)$this->tableArchiveBlob;
 	}
 	
 	
@@ -354,7 +354,7 @@
 		// we first compute every subperiod of the archive
 		foreach($this->period->getSubperiods() as $period)
 		{
-			$archivePeriod = new Piwik_Archive;
+			$archivePeriod = new Piwik_Archive_Single;
 			$archivePeriod->setSite( $this->site );
 			$archivePeriod->setPeriod( $period );
 			$archivePeriod->prepareArchive();

Added: trunk/modules/DataTable/Array.php
===================================================================
--- trunk/modules/DataTable/Array.php	                        (rev 0)
+++ trunk/modules/DataTable/Array.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ * 
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Simple.php 168 2008-01-14 05:26:43Z matt $
+ * 
+ * @package Piwik_DataTable
+ */
+
+/**
+ * The DataTable_Array is a way to store an array of dataTable
+ * 
+ * @package Piwik_DataTable
+ */
+class Piwik_DataTable_Array
+{
+	protected $array = array();
+	protected $nameKey = 'defaultKeyName';
+	
+	public function getNameKey()
+	{
+		return $this->nameKey;
+	}
+	public function setNameKey($name)
+	{
+		$this->nameKey = $name;
+	}
+	
+	public function queueFilter( $className, $parameters = array() )
+	{
+		foreach($this->array as $table)
+		{
+			$table->queueFilter($className, $parameters);
+		}
+	}
+	
+	public function applyQueuedFilters()
+	{
+		foreach($this->array as $table)
+		{
+			$table->applyQueuedFilters();
+		}
+	}
+	
+	public function getArray()
+	{
+		return $this->array;
+	}
+	
+	public function addTable( Piwik_DataTable $table, $label )
+	{
+		$this->array[$label] = $table;
+	}
+	
+	public function __toString()
+	{
+		$renderer = new Piwik_DataTable_Renderer_Console($this);
+		return (string)$renderer;
+	}
+	
+}
+
+

Modified: trunk/modules/DataTable/Renderer/Console.php
===================================================================
--- trunk/modules/DataTable/Renderer/Console.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/DataTable/Renderer/Console.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -36,6 +36,19 @@
 	
 	protected function renderTable($table)
 	{
+		if($table instanceof Piwik_DataTable_Array)
+		{
+			$output = '';
+			$output .= "Piwik_DataTable_Array<hr>";
+			foreach($table->getArray() as $descTable => $table)
+			{
+				$output .="<b>". $descTable. "</b><br>";
+				$output .= $table;
+				$output .= "<hr>";
+			}
+			return $output;
+		}
+		
 		if($table->getRowsCount() == 0)
 		{
 			return "Empty table <br>\n";

Modified: trunk/modules/DataTable/Renderer.php
===================================================================
--- trunk/modules/DataTable/Renderer.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/DataTable/Renderer.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -46,9 +46,10 @@
 	 */
 	public function setTable($table)
 	{
-		if(!($table instanceof Piwik_DataTable))
+		if(!($table instanceof Piwik_DataTable)
+			&& !($table instanceof Piwik_DataTable_Array))
 		{
-			throw new Exception("The renderer accepts only a Piwik_DataTable object.");
+			throw new Exception("The renderer accepts only a Piwik_DataTable or an array of DataTable (Piwik_DataTable_Array) object.");
 		}
 		$this->table = $table;
 	}

Modified: trunk/modules/DataTable.php
===================================================================
--- trunk/modules/DataTable.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/DataTable.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -171,7 +171,6 @@
 		$this->queuedFilters[] = array('className' => $className, 'parameters' => $parameters);
 	}
 	
-	
 	public function applyQueuedFilters()
 	{
 		foreach($this->queuedFilters as $filter)

Modified: trunk/modules/Date.php
===================================================================
--- trunk/modules/Date.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/Date.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -46,11 +46,16 @@
 		return date($part, $this->getTimestamp());
 	}
 	
+	public function __toString()
+	{
+		return $this->toString();
+	}
+
     /**
      * Sets a new day
      * Returned is the new date object
      * 
-     * @return   new date
+     * @return Piwik_Date  new date
      */
 	public function setDay( $day )
 	{
@@ -65,6 +70,26 @@
 					);
 		return new Piwik_Date( $result );
 	}
+    /**
+     * Sets a new year
+     * Returned is the new date object
+     * 
+     * @param int 2010
+     * @return Piwik_Date  new date
+     */
+	public function setYear( $year )
+	{
+		$ts = $this->getTimestamp();
+		$result = mktime( 
+						date('H', $ts),
+						date('i', $ts),
+						date('s', $ts),
+						date('n', $ts),
+						date('j', $ts),
+						$year
+					);
+		return new Piwik_Date( $result );
+	}
 	
     /**
      * Compares only the week part, returning the difference
@@ -89,12 +114,12 @@
 		return 1;
     }
 
-	
+
     /**
      * Subtracts days from the existing date object.
 
      * Returned is the new date object
-     * @return Zend_Date  new date
+     * @return Piwik_Date  new date
      */
     public function subDay( $n )
     {
@@ -103,9 +128,21 @@
     }
     
     /**
+     * Subtracts month from the existing date object.
+     * Returned is the new date object
+     * 
+     * @return Piwik_Date  new date
+     */
+    public function subMonth( $n )
+    {
+    	$ts = strtotime("-$n months", $this->getTimestamp());
+		return new Piwik_Date( $ts );
+    }
+    
+    /**
      * Returns a representation of a date or datepart
      *
-     * @param  string              $part    OPTIONAL Part of the date to return, if null the timestamp is returned
+     * @param  string  $part    OPTIONAL Part of the date to return, if null the timestamp is returned
      * @return integer|string  date or datepart
      */
 	public function get($part = null)
@@ -120,7 +157,7 @@
     /**
      * Adds days to the existing date object.
      * Returned is the new date object
-     * @return   new date
+     * @return  Piwik_Date new date
      */
 	public function addDay( $n )
 	{

Modified: trunk/modules/FrontController.php
===================================================================
--- trunk/modules/FrontController.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/FrontController.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -97,9 +97,13 @@
 	
 	function end()
 	{
-//		Piwik::printZendProfiler();
-//		Piwik::printMemoryUsage();
-//		Piwik::printQueryCount();
+		try {
+			Piwik::printZendProfiler();
+			Piwik::printQueryCount();
+		}catch(Exception $e) {}
+		
+		Piwik::printMemoryUsage();
+		Piwik::printTimer();
 //		Piwik::uninstall();
 //
 	}

Modified: trunk/modules/Period.php
===================================================================
--- trunk/modules/Period.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/Period.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -188,6 +188,13 @@
 		return true;
 	}
 	
+	public function getPrettyString()
+	{
+		$temp = $this->toString();
+		$out = $this->getLabel() . " from " . $temp[0] . " to " . end($temp);
+		return $out;
+	}
+	
 	public function toString()
 	{
 		if(!$this->subperiodsProcessed)
@@ -207,7 +214,91 @@
 		return $this->date->get($part);
 	}
 }
-
+
+/**
+ * from a starting date to an ending date
+ *
+ */
+class Piwik_Period_Range extends Piwik_Period
+{
+	public function __construct( $strPeriod, $strDate )
+	{
+		$this->strPeriod = $strPeriod;
+		$this->strDate = $strDate;
+		
+	}
+	protected function removePeriod( $date, $n )
+	{
+		switch($this->strPeriod)
+		{
+			case 'day':	
+				$startDate = $date->subDay( $n );
+			break;
+			
+			case 'week':
+				$startDate = $date->subDay( $n * 7 );					
+			break;
+			
+			case 'month':
+				$startDate = $date->subMonth( $n );					
+			break;
+			
+			case 'year':
+				$startDate = $date->subMonth( 12 * $n );					
+			break;
+		}
+		return $startDate;
+	}
+	protected function generate()
+	{
+		if($this->subperiodsProcessed)
+		{
+			return;
+		}
+		$this->subperiodsProcessed = true;
+		
+		if(ereg('last([0-9]*)', $this->strDate, $regs))
+		{
+			$lastN = $regs[1];
+			
+			// last1 means only one result ; last2 means 2 results so we remove only 1 to the days/weeks/etc
+			$lastN--;
+			
+			$endDate = Piwik_Date::today();
+			$startDate = $this->removePeriod($endDate, $lastN);
+		}
+		else
+		{
+			throw new Exception("The date $strDate seems incorrect");
+		}
+		//TODO handle previous
+		
+		$endSubperiod = Piwik_Period::factory($this->strPeriod, $endDate);
+		$this->addSubperiod($endSubperiod);
+		
+		for($i = $lastN; $i > 0 ; $i--)
+		{
+			$endDate = $this->removePeriod($endDate, 1);
+			$subPeriod = Piwik_Period::factory($this->strPeriod, $endDate);
+			$this->addSubperiod( $subPeriod );
+		}
+	}
+	
+	function toString()
+	{
+		if(!$this->subperiodsProcessed)
+		{
+			$this->generate();
+		}
+		$range = array();
+		foreach($this->subperiods as $element)
+		{
+			$range[] = $element->toString();
+		}
+		return $range;
+	}
+}
+	
 /**
  * 
  * @package Piwik_Period

Modified: trunk/modules/Piwik.php
===================================================================
--- trunk/modules/Piwik.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/Piwik.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -23,7 +23,7 @@
 {
 	const CLASSES_PREFIX = "Piwik_";
 	
-	static $idPeriods =  array(
+	public static $idPeriods =  array(
 			'day'	=> 1,
 			'week'	=> 2,
 			'month'	=> 3,
@@ -241,7 +241,11 @@
 	static function printZendProfiler()
 	{
 		$profiler = Zend_Registry::get('db')->getProfiler();
-	
+		
+		if(!$profiler->getEnabled())
+		{
+			throw new Exception("To display the profiler you should turn on profiling on your config/config.ini.php file");
+		}
 		$totalTime    = $profiler->getTotalElapsedSecs();
 		$queryCount   = $profiler->getTotalNumQueries();
 		$longestTime  = 0;
@@ -261,8 +265,36 @@
 		$str .= '<br>Longest query: <br>' . $longestQuery . "\n";
 		
 		Piwik::log($str);
+		
+		foreach($profiler->getQueryProfiles() as $query)
+		{
+			if(isset($indexByQuery[$query->getQuery()]))
+			{
+				$existing =  $indexByQuery[$query->getQuery()];
+			}
+			else
+			{
+				$existing = array( 'count' => 0, 'sumTimeSeconds' => 0);
+			}
+			$new = array( 'count' => $existing['count'] + 1,
+							'sumTimeSeconds' =>  $existing['count'] + $query->getElapsedSecs()
+				);
+			$indexByQuery[$query->getQuery()] = $new;
+		}
+		function sortTimeDesc($a,$b)
+		{
+			return $a['sumTimeSeconds'] < $b['sumTimeSeconds'];
+		}
+		uasort( $indexByQuery, 'sortTimeDesc');
+		var_dump($indexByQuery);
+		
 	}
 	
+	static public function printTimer()
+	{
+		echo Zend_Registry::get('timer');
+	}
+	
 	static public function printMemoryUsage( $prefixString = null )
 	{
 		$memory = false;
@@ -598,29 +630,37 @@
 		return $return;
 	}
 	
-	static public function getTablesInstalled()
+	static $tablesInstalled = null;
+	
+	static public function getTablesInstalled( $forceReload = true )
 	{
-
-		$db = Zend_Registry::get('db');
-		$config = Zend_Registry::get('config');
-		$prefixTables = $config->database->tables_prefix;
-		
-		$allTables = $db->fetchCol("SHOW TABLES");
-		
-		// all the tables to be installed
-		$allMyTables = self::getTablesNames();
-		
-		// we get the intersection between all the tables in the DB and the tables to be installed
-		$tablesInstalled = array_intersect($allMyTables, $allTables);
-		
-		// at this point we have only the piwik tables which is good
-		// but we still miss the piwik generated tables (using the class Piwik_TablePartitioning)
-		$allArchiveNumeric = $db->fetchCol("SHOW TABLES LIKE '".$prefixTables."archive_numeric%'");
-		$allArchiveBlob = $db->fetchCol("SHOW TABLES LIKE '".$prefixTables."archive_blob%'");
-				
-		$allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob);
-		
-		return 	$allTablesReallyInstalled;
+		if(is_null(self::$tablesInstalled) 
+			|| $forceReload === true)
+		{
+			
+			$db = Zend_Registry::get('db');
+			$config = Zend_Registry::get('config');
+			$prefixTables = $config->database->tables_prefix;
+			
+			$allTables = $db->fetchCol("SHOW TABLES");
+			
+			// all the tables to be installed
+			$allMyTables = self::getTablesNames();
+			
+			// we get the intersection between all the tables in the DB and the tables to be installed
+			$tablesInstalled = array_intersect($allMyTables, $allTables);
+			
+			// at this point we have only the piwik tables which is good
+			// but we still miss the piwik generated tables (using the class Piwik_TablePartitioning)
+			
+			$allArchiveNumeric = $db->fetchCol("SHOW TABLES LIKE '".$prefixTables."archive_numeric%'");
+			$allArchiveBlob = $db->fetchCol("SHOW TABLES LIKE '".$prefixTables."archive_blob%'");
+					
+			$allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob);
+			
+			self::$tablesInstalled = $allTablesReallyInstalled;
+		}
+		return 	self::$tablesInstalled;
 	}
 	
 	static public function createDatabase()
@@ -650,6 +690,7 @@
 		$db->getConnection();
 		Zend_Db_Table::setDefaultAdapter($db);
 		Zend_Registry::set('db', $db);
+		
 	}
 
 	static public function createLogObject()

Modified: trunk/modules/Site.php
===================================================================
--- trunk/modules/Site.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/Site.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -16,12 +16,17 @@
 class Piwik_Site
 {
 	protected $id = null;
+	
+	protected static $infoSites = array();
 
 	function __construct($idsite)
 	{
 		$this->id = $idsite;
 		
-		$this->info = Piwik_SitesManager_API::getSiteFromId($idsite);
+		if(!isset(self::$infoSites[$this->id]))
+		{
+			self::$infoSites[$this->id] = Piwik_SitesManager_API::getSiteFromId($idsite);
+		}
 	}
 	
 	function getId()
@@ -31,7 +36,7 @@
 	
 	function getCreationDate()
 	{
-		$date = $this->info['ts_created'];
+		$date = self::$infoSites[$this->id]['ts_created'];
 		return new Piwik_Date($date);
 	}
 	

Modified: trunk/modules/TablePartitioning.php
===================================================================
--- trunk/modules/TablePartitioning.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/modules/TablePartitioning.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -22,6 +22,8 @@
 	protected $generatedTableName = null;
 	protected $timestamp = null;
 	
+	static public $tablesAlreadyInstalled = null;
+	
 	public function __construct( $tableName )
 	{
 		$this->tableName = $tableName;
@@ -59,9 +61,12 @@
 	
 	protected function checkTableExists()
 	{
-		$tablesAlreadyInstalled = Piwik::getTablesInstalled();
+		if(is_null(self::$tablesAlreadyInstalled))
+		{
+			self::$tablesAlreadyInstalled = Piwik::getTablesInstalled( $forceReload = false );
+		}
 		
-		if(!in_array($this->generatedTableName, $tablesAlreadyInstalled))
+		if(!in_array($this->generatedTableName, self::$tablesAlreadyInstalled))
 		{
 			$db = Zend_Registry::get('db');
 			$sql = Piwik::getTableCreateSql($this->tableName);
@@ -71,6 +76,8 @@
 			$sql = str_replace( $prefixTables . $this->tableName, $this->generatedTableName, $sql);
 			
 			$db->query( $sql );
+			
+			self::$tablesAlreadyInstalled[] = $this->generatedTableName;
 		}
 	}
 	

Modified: trunk/plugins/Installation/Controller.php
===================================================================
--- trunk/plugins/Installation/Controller.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/plugins/Installation/Controller.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -119,6 +119,7 @@
 				'dbname' 		=> $form->getSubmitValue('dbname'),
 				'tables_prefix' => $form->getSubmitValue('tables_prefix'),
 				'adapter' 		=> Zend_Registry::get('config')->database->adapter,
+				'profiler' 		=> 'false',
 			);
 			
 			// we test the DB connection with these settings

Modified: trunk/tests/modules/Period.test.php
===================================================================
--- trunk/tests/modules/Period.test.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/tests/modules/Period.test.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -436,7 +436,7 @@
 	/* //http://framework.zend.com/issues/browse/ZF-1832
 	 function test_week_zendsetweekday()
 	 {
-	 	$date = new Zend_Date('2006-01-01','YYYY-MM-dd', 'en');
+	 	$date = new Piwik_Date('2006-01-01','YYYY-MM-dd', 'en');
 	 	$date->setWeekday(1);	 	
 	 	$this->assertEqual('2005-12-26', $date->toString("Y-m-d"));
 	 }*/
@@ -554,11 +554,11 @@
 			'2024-11-01',
 			'2024-12-01',);
 		
-	 	$week = new Piwik_Period_Year( new Piwik_Date('2024-10-09'));
-	 	$this->assertEqual( $week->getNumberOfSubperiods(), 12);
-	 	$this->assertEqual( $week->isFinished(), false);
-	 	$this->assertEqual( $week->toString(), $correct);
-
+	 	$year = new Piwik_Period_Year( new Piwik_Date('2024-10-09'));
+	 	$this->assertEqual( $year->getNumberOfSubperiods(), 12);
+	 	$this->assertEqual( $year->isFinished(), false);
+	 	$this->assertEqual( $year->toString(), $correct);
+	 	
 	 }
 	 
 	// test past
@@ -584,5 +584,116 @@
 //	 	$this->assertEqual( $week->isFinished(), true);
 //	 	$this->assertEqual( $week->toString(), $correct);
 	 }
+	 
+
+	// test range 1
+	function test_range_today()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'day', 'last1' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct=array(
+			$today->toString(),
+		);
+			
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 1);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	}
+	// test range 2
+	function test_range_2days()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'day', 'last2' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct=array(
+			$today->toString(),
+			$today->subDay(1)->toString()
+		);
+			
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 2);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	 }
+	// test range 3
+	function test_range_5days()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'day', 'last50' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct = array();
+	 	for($i=0;$i<50;$i++)
+	 	{
+	 		$correct[]=$today->subDay($i)->toString();
+	 	}
+			
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 50);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	 }
+	// test range WEEK
+	function test_range_week()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'week', 'last50' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct = array();
+	 	for($i=0;$i<50;$i++)
+	 	{
+	 		$date = $today->subDay($i*7);
+	 		$week = new Piwik_Period_Week($date);
+	 		
+	 		$correct[]= $week->toString();
+	 	}
+			
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 50);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	 }
+	// test range MONTH
+	function test_range_month()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'month', 'last20' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct = array();
+	 	for($i=0;$i<20;$i++)
+	 	{
+	 		$date = $today->subMonth($i);
+	 		$week = new Piwik_Period_Month($date);
+	 		
+	 		$correct[]= $week->toString();
+	 	}
+			
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 20);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	 }
+	 
+	// test range YEAR
+	function test_range_year()
+	{
+		
+	 	$range = new Piwik_Period_Range( 'year', 'last20' );
+	 	$today = Piwik_Date::today();
+	 	
+	 	$correct = array();
+	 	for($i=0;$i<20;$i++)
+	 	{
+	 		$date = $today->subMonth(12*$i);
+	 		$week = new Piwik_Period_Year($date);
+	 		
+	 		$correct[]= $week->toString();
+	 	}
+	 	
+	 	$this->assertEqual( $range->getNumberOfSubperiods(), 20);
+	 	$this->assertEqual( $range->isFinished(), false);
+	 	$this->assertEqual( $range->toString(), $correct);
+	 }
 }
 

Modified: trunk/tests/modules/TablePartitioning.test.php
===================================================================
--- trunk/tests/modules/TablePartitioning.test.php	2008-01-17 00:39:12 UTC (rev 178)
+++ trunk/tests/modules/TablePartitioning.test.php	2008-01-17 04:58:59 UTC (rev 179)
@@ -18,6 +18,7 @@
     public function setUp()
 	{
 		parent::setUp();
+		Piwik_TablePartitioning::$tablesAlreadyInstalled = null;
 	}
 	
     // test no timestamp  => exception
@@ -47,34 +48,13 @@
 		
     	$p->setTimestamp( $timestamp );
     	
-    	$allTablesInstalled = Piwik::getTablesInstalled();
+    	$allTablesInstalled = Piwik::getTablesInstalled($forceReload = true);
     	
     	$this->assertTrue( in_array($tablename, $allTablesInstalled), "$tablename !==".var_export($allTablesInstalled,true));
     	$this->assertTrue( $tablename, $p->getTableName());
     	$this->assertEqual( $tablename, (string)$p);
     }
 	
-	// test table present => nothing
-    function test_tablePresent()
-    {
-    	$tableName ='archive_numeric';
-    	$p = new Piwik_TablePartitioning_Monthly($tableName);
-    	$timestamp = strtotime("10 September 2000");
-    	$suffixShouldBe = "_2000_09";
-		$config = Zend_Registry::get('config');
-		$prefixTables = $config->database->tables_prefix;
-		$tablename = $prefixTables.$tableName.$suffixShouldBe;
-		
-		Zend_Registry::get('db')->query("CREATE TABLE $tablename (`test` VARCHAR( 255 ) NOT NULL)");
-
-		$p->setTimestamp( $timestamp );
-    	
-    	$allTablesInstalled = Piwik::getTablesInstalled();
-    	$this->assertTrue( in_array($tablename, $allTablesInstalled));
-    	$this->assertTrue( $tablename, $p->getTableName());
-    	$this->assertEqual( $tablename, (string)$p);
-    }
-    
 	// test monthly
     function test_monthlyPartition()
     {
@@ -89,7 +69,7 @@
 		
     	$p->setTimestamp( $timestamp );
     	
-    	$allTablesInstalled = Piwik::getTablesInstalled();
+    	$allTablesInstalled = Piwik::getTablesInstalled( $forceReload = true );
     	$this->assertTrue( in_array($tablename, $allTablesInstalled));
     	$this->assertTrue( $tablename, $p->getTableName());
     	$this->assertEqual( $tablename, (string)$p);



More information about the Piwik-svn mailing list