diff options
author | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-12-26 17:37:46 +0300 |
---|---|---|
committer | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-12-26 17:37:46 +0300 |
commit | d389561c0ccb76536d18239c9b7f81cce3d02fc1 (patch) | |
tree | 2bac760977afe8e7f3ae7890d7cd286e37109d88 /plugins | |
parent | 47f4495a2adba4cbce5d1c3d3510ce26f8650f69 (diff) | |
parent | b86d75c79c557a7c89899939055ee7306f40d28a (diff) |
Diffstat (limited to 'plugins')
79 files changed, 3013 insertions, 1236 deletions
diff --git a/plugins/API/Controller.php b/plugins/API/Controller.php index 60602f585e..8eb442cca1 100644 --- a/plugins/API/Controller.php +++ b/plugins/API/Controller.php @@ -10,7 +10,7 @@ */ require_once "API/Request.php"; - +require_once "API/DocumentationGenerator.php"; /** * @@ -26,36 +26,19 @@ class Piwik_API_Controller extends Piwik_Controller public function listAllMethods() { - $this->init(); - echo Piwik_API_Proxy::getInstance()->getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = Piwik_Common::getRequestVar('prefixUrl', '') ); + $ApiDocumentation = new Piwik_API_DocumentationGenerator(); + echo $ApiDocumentation->getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = Piwik_Common::getRequestVar('prefixUrl', '') ); } public function listAllAPI() { $view = new Piwik_View("API/templates/listAllAPI.tpl"); $this->setGeneralVariablesView($view); - $view->countLoadedAPI = $this->init(); - $view->list_api_methods_with_links = Piwik_API_Proxy::getInstance()->getAllInterfaceString(); - echo $view->render(); - } - - protected function init() - { - $plugins = Piwik_PluginsManager::getInstance()->getLoadedPluginsName(); - $loaded = 0; - foreach( $plugins as $plugin ) - { - $plugin = Piwik::unprefixClass($plugin); - - try { - Piwik_API_Proxy::getInstance()->registerClass($plugin); - $loaded++; - } - catch(Exception $e){ - } - } - return $loaded; + $ApiDocumentation = new Piwik_API_DocumentationGenerator(); + $view->countLoadedAPI = Piwik_API_Proxy::getInstance()->getCountRegisteredClasses(); + $view->list_api_methods_with_links = $ApiDocumentation->getAllInterfaceString(); + echo $view->render(); } } diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php index 42996b7a53..57c3afa6fe 100644 --- a/plugins/Actions/API.php +++ b/plugins/Actions/API.php @@ -18,7 +18,7 @@ require_once "Actions.php"; * * @package Piwik_Actions */ -class Piwik_Actions_API extends Piwik_Apiable +class Piwik_Actions_API { static private $instance = null; diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php index 40e167bd38..50e1d04345 100644 --- a/plugins/Actions/Actions.php +++ b/plugins/Actions/Actions.php @@ -1,21 +1,21 @@ -<?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$
- *
- * @package Piwik_Actions
- */
-
-/**
- *
- * @package Piwik_Actions
- */
-class Piwik_Actions extends Piwik_Plugin
-{
- static protected $actionCategoryDelimiter = null;
+<?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$ + * + * @package Piwik_Actions + */ + +/** + * + * @package Piwik_Actions + */ +class Piwik_Actions extends Piwik_Plugin +{ + static protected $actionCategoryDelimiter = null; static protected $limitLevelSubCategory = 10; public function getInformation() @@ -41,309 +41,310 @@ class Piwik_Actions extends Piwik_Plugin ); return $hooks; } -
- public function __construct()
+ + public function __construct() + { + $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter); + } + + public function setCategoryDelimiter($delimiter) { - $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter);
- }
-
- public function setCategoryDelimiter($delimiter)
- {
- self::$actionCategoryDelimiter = $delimiter;
- }
-
+ self::$actionCategoryDelimiter = $delimiter; + } + function addWidgets() { Piwik_AddWidget( 'Actions', 'getActions', Piwik_Translate('Actions_SubmenuPages')); Piwik_AddWidget( 'Actions', 'getDownloads', Piwik_Translate('Actions_SubmenuDownloads')); Piwik_AddWidget( 'Actions', 'getOutlinks', Piwik_Translate('Actions_SubmenuOutlinks')); } -
- function addMenus()
- {
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
- }
-
- function archivePeriod( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- $dataTableToSum = array(
- 'Actions_actions',
- 'Actions_downloads',
- 'Actions_outlink',
- );
+ + function addMenus() + { + Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions')); + Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks')); + Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads')); + } + + function archivePeriod( $notification ) + { + $archiveProcessing = $notification->getNotificationObject(); + + $dataTableToSum = array( + 'Actions_actions', + 'Actions_downloads', + 'Actions_outlink', + ); $maximumRowsInDataTableLevelZero = 200; - $maximumRowsInSubDataTable = 50;
- $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- }
-
- /**
- * Compute all the actions along with their hierarchies.
- *
- * For each action we process the "interest statistics" :
- * visits, unique visitors, bouce count, sum visit length.
- *
- *
- */
- public function archiveDay( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- require_once "Tracker/Action.php";
-
- $this->actionsTablesByType = array(
- Piwik_Tracker_Action::TYPE_ACTION => array(),
- Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
- Piwik_Tracker_Action::TYPE_OUTLINK => array(),
- );
-
- // This row is used in the case where an action is know as an exit_action
- // but this action was not properly recorded when it was hit in the first place
- // so we add this fake row information to make sure there is a nb_hits, etc. column for every action
- $this->defaultRow = new Piwik_DataTable_Row(array(
- Piwik_DataTable_Row::COLUMNS => array(
- 'nb_visits' => 1,
- 'nb_uniq_visitors' => 1,
- 'nb_hits' => 1,
- )));
-
- /*
- * Actions global information
- */
- $query = "SELECT name,
- type,
- count(distinct t1.idvisit) as nb_visits,
- count(distinct visitor_idcookie) as nb_uniq_visitors,
- count(*) as nb_hits
- FROM (".$archiveProcessing->logTable." as t1
- LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
- LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ $maximumRowsInSubDataTable = 50; + $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); + } + + /** + * Compute all the actions along with their hierarchies. + * + * For each action we process the "interest statistics" : + * visits, unique visitors, bouce count, sum visit length. + * + * + */ + public function archiveDay( $notification ) + { + $archiveProcessing = $notification->getNotificationObject(); + + require_once "Tracker/Action.php"; + + $this->actionsTablesByType = array( + Piwik_Tracker_Action::TYPE_ACTION => array(), + Piwik_Tracker_Action::TYPE_DOWNLOAD => array(), + Piwik_Tracker_Action::TYPE_OUTLINK => array(), + ); + + // This row is used in the case where an action is know as an exit_action + // but this action was not properly recorded when it was hit in the first place + // so we add this fake row information to make sure there is a nb_hits, etc. column for every action + $this->defaultRow = new Piwik_DataTable_Row(array( + Piwik_DataTable_Row::COLUMNS => array( + 'nb_visits' => 1, + 'nb_uniq_visitors' => 1, + 'nb_hits' => 1, + ))); + + /* + * Actions global information + */ + $query = "SELECT name, + type, + count(distinct t1.idvisit) as nb_visits, + count(distinct visitor_idcookie) as nb_uniq_visitors, + count(*) as nb_hits + FROM (".$archiveProcessing->logTable." as t1 + LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit)) + LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction) + WHERE visit_server_date = ? + AND idsite = ? GROUP BY t3.idaction - ORDER BY nb_hits DESC";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Entry actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as entry_nb_unique_visitor,
- count(*) as entry_nb_visits,
- sum(visit_total_actions) as entry_nb_actions,
- sum(visit_total_time) as entry_sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ ORDER BY nb_hits DESC"; + $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); + $modified = $this->updateActionsTableWithRowQuery($query); + + + /* + * Entry actions + */ + $query = "SELECT name, + type, + count(distinct visitor_idcookie) as entry_nb_unique_visitor, + count(*) as entry_nb_visits, + sum(visit_total_actions) as entry_nb_actions, + sum(visit_total_time) as entry_sum_visit_length, + sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count + FROM ".$archiveProcessing->logTable." + JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction) + WHERE visit_server_date = ? + AND idsite = ? GROUP BY visit_entry_idaction - ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Exit actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as exit_nb_unique_visitor,
- count(*) as exit_nb_visits,
- sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count
-
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ "; + $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); + $modified = $this->updateActionsTableWithRowQuery($query); + + + /* + * Exit actions + */ + $query = "SELECT name, + type, + count(distinct visitor_idcookie) as exit_nb_unique_visitor, + count(*) as exit_nb_visits, + sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count + + FROM ".$archiveProcessing->logTable." + JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction) + WHERE visit_server_date = ? + AND idsite = ? GROUP BY visit_exit_idaction - ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
- /*
- * Time per action
- */
- $query = "SELECT name,
- type,
- sum(time_spent_ref_action) as sum_time_spent
- FROM (".$archiveProcessing->logTable." log_visit
- JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
- JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)
- WHERE visit_server_date = ?
- AND idsite = ?
- GROUP BY idaction_ref
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
+ "; + $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); + $modified = $this->updateActionsTableWithRowQuery($query); - $maximumRowsInDataTableLevelZero = 200; - $maximumRowsInSubDataTable = 50; -
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s);
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s);
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s);
+ /* + * Time per action + */ + $query = "SELECT name, + type, + sum(time_spent_ref_action) as sum_time_spent + FROM (".$archiveProcessing->logTable." log_visit + JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit)) + JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref) + WHERE visit_server_date = ? + AND idsite = ? + GROUP BY idaction_ref + "; + $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); + $modified = $this->updateActionsTableWithRowQuery($query); + + $this->archiveDayRecordInDatabase(); + } + + protected function archiveDayRecordInDatabase() + { + $maximumRowsInDataTableLevelZero = 1000; + $maximumRowsInSubDataTable = 200; + + $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION]); + $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable ); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s); + + $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]); + $s = $dataTable->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable ); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s); - unset($this->actionsTablesByType);
- }
-
- static public function splitUrl($url)
- {
- $matches = $split_arr = array();
- $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE);
- if( $n )
- {
- $host = substr($url, 0, $matches[1][1]);
- $split_arr = array($host, $url);
- }
- else
- {
- $split_arr = array($url);
- }
- return $split_arr;
- }
-
- static public function getActionCategoryFromName($name)
- {
- $isUrl = false;
- // case the name is an URL we dont clean the name the same way
- if(Piwik_Common::isLookLikeUrl($name)
- || preg_match('#^mailto:#',$name))
- {
- $split = self::splitUrl($name);
- $isUrl = true;
- }
- else
+ $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]); + $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable ); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s); + + unset($this->actionsTablesByType); + } + + static public function splitUrl($url) + { + $matches = $split_arr = array(); + $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE); + if( $n ) + { + $host = substr($url, 0, $matches[1][1]); + $split_arr = array($host, $url); + } + else + { + $split_arr = array($url); + } + return $split_arr; + } + + static public function getActionCategoryFromName($name) + { + $isUrl = false; + // case the name is an URL we dont clean the name the same way + if(Piwik_Common::isLookLikeUrl($name) + || preg_match('#^mailto:#',$name)) + { + $split = self::splitUrl($name); + $isUrl = true; + } + else { if(empty(self::$actionCategoryDelimiter)) { $split = array($name); } else - {
+ { $split = explode(self::$actionCategoryDelimiter, $name, self::$limitLevelSubCategory); - }
- }
- return array( $isUrl, $split);
- }
-
-
- protected function updateActionsTableWithRowQuery($query)
- {
- $rowsProcessed = 0;
-
- while( $row = $query->fetch() )
- {
- // split the actions by category
- $returned = $this->getActionCategoryFromName($row['name']);
- $aActions = $returned[1];
- $isUrl = $returned[0];
-
- // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.)
- $currentTable =& $this->actionsTablesByType[$row['type']];
-
- // go to the level of the subcategory
- $end = count($aActions)-1;
- for($level = 0 ; $level < $end; $level++)
- {
- $actionCategory = $aActions[$level];
- $currentTable =& $currentTable[$actionCategory];
- }
- $actionName = $aActions[$end];
-
- // create a new element in the array for the page
- // we are careful to prefix the pageName with some value so that if a page has the same name
- // as a category we don't overwrite or do other silly things
-
- // if the page name is not a URL we add a / before
- if( !$isUrl )
- {
- // we know that the concatenation of a space and the name of the action
- // will always be unique as all the action names have been trimmed before reaching this point
- $actionName = '/' . $actionName;
- }
- else
- {
- $actionName = ' ' . $actionName;
- }
-
- // currentTable is now the array element corresponding the the action
- // at this point we may be for example at the 4th level of depth in the hierarchy
- $currentTable =& $currentTable[$actionName];
-
- // add the row to the matching sub category subtable
- if(!($currentTable instanceof Piwik_DataTable_Row))
- {
- $currentTable = new Piwik_DataTable_Row(
- array( Piwik_DataTable_Row::COLUMNS =>
- array( 'label' => (string)$actionName,
- 'full_url' => (string)$row['name'],
- )
- )
- );
- }
-
- foreach($row as $name => $value)
- {
- // we don't add this information as itnot pertinent
- // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
- // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
- if($name != 'name' && $name != 'type')
- {
- // in some very rare case, we actually have twice the same action name with 2 different idaction
- // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
- // and in between the two the other visitor comes.
- // here we handle the case where there is already a row for this action name, if this is the case we add the value
- if(($alreadyValue = $currentTable->getColumn($name)) !== false)
- {
- $currentTable->setColumn($name, $alreadyValue+$value);
- }
- else
- {
- $currentTable->addColumn($name, $value);
- }
- }
- }
-
- // if the exit_action was not recorded properly in the log_link_visit_action
- // there would be an error message when getting the nb_hits column
- // we must fake the record and add the columns
- if($currentTable->getColumn('nb_hits') === false)
- {
- // to test this code: delete the entries in log_link_action_visit for
- // a given exit_idaction
- foreach($this->defaultRow->getColumns() as $name => $value)
- {
- $currentTable->addColumn($name, $value);
- }
- }
- // simple count
- $rowsProcessed++;
- }
-
- // just to make sure php copies the last $currentTable in the $parentTable array
- $currentTable =& $this->actionsTablesByType;
-
- return $rowsProcessed;
- }
-}
-
+ } + } + return array( $isUrl, $split); + } + + + protected function updateActionsTableWithRowQuery($query) + { + $rowsProcessed = 0; + + while( $row = $query->fetch() ) + { + // split the actions by category + $returned = $this->getActionCategoryFromName($row['name']); + $aActions = $returned[1]; + $isUrl = $returned[0]; + + // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.) + $currentTable =& $this->actionsTablesByType[$row['type']]; + + // go to the level of the subcategory + $end = count($aActions)-1; + for($level = 0 ; $level < $end; $level++) + { + $actionCategory = $aActions[$level]; + $currentTable =& $currentTable[$actionCategory]; + } + $actionName = $aActions[$end]; + + // create a new element in the array for the page + // we are careful to prefix the pageName with some value so that if a page has the same name + // as a category we don't overwrite or do other silly things + + // if the page name is not a URL we add a / before + if( !$isUrl ) + { + // we know that the concatenation of a space and the name of the action + // will always be unique as all the action names have been trimmed before reaching this point + $actionName = '/' . $actionName; + } + else + { + $actionName = ' ' . $actionName; + } + + // currentTable is now the array element corresponding the the action + // at this point we may be for example at the 4th level of depth in the hierarchy + $currentTable =& $currentTable[$actionName]; + + // add the row to the matching sub category subtable + if(!($currentTable instanceof Piwik_DataTable_Row)) + { + $currentTable = new Piwik_DataTable_Row( + array( Piwik_DataTable_Row::COLUMNS => + array( 'label' => (string)$actionName, + 'full_url' => (string)$row['name'], + ) + ) + ); + } + + foreach($row as $name => $value) + { + // we don't add this information as itnot pertinent + // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string + // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate. + if($name != 'name' && $name != 'type') + { + // in some very rare case, we actually have twice the same action name with 2 different idaction + // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page, + // and in between the two the other visitor comes. + // here we handle the case where there is already a row for this action name, if this is the case we add the value + if(($alreadyValue = $currentTable->getColumn($name)) !== false) + { + $currentTable->setColumn($name, $alreadyValue+$value); + } + else + { + $currentTable->addColumn($name, $value); + } + } + } + + // if the exit_action was not recorded properly in the log_link_visit_action + // there would be an error message when getting the nb_hits column + // we must fake the record and add the columns + if($currentTable->getColumn('nb_hits') === false) + { + // to test this code: delete the entries in log_link_action_visit for + // a given exit_idaction + foreach($this->defaultRow->getColumns() as $name => $value) + { + $currentTable->addColumn($name, $value); + } + } + // simple count + $rowsProcessed++; + } + + // just to make sure php copies the last $currentTable in the $parentTable array + $currentTable =& $this->actionsTablesByType; + + return $rowsProcessed; + } +} + diff --git a/plugins/Actions/Controller.php b/plugins/Actions/Controller.php index 4957756f3c..20e160f927 100644 --- a/plugins/Actions/Controller.php +++ b/plugins/Actions/Controller.php @@ -45,7 +45,6 @@ class Piwik_Actions_Controller extends Piwik_Controller __FUNCTION__, 'Actions.getActions', 'getActionsSubDataTable' ); - return $this->renderView($view, $fetch); } @@ -117,8 +116,6 @@ class Piwik_Actions_Controller extends Piwik_Controller $currentMethod, $methodToCall, $subMethod ); - $view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews')); - $view->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnUniquePageviews')); $view->setTemplate('CoreHome/templates/datatable_actions.tpl'); if(Piwik_Common::getRequestVar('idSubtable', -1) != -1) @@ -132,25 +129,24 @@ class Piwik_Actions_Controller extends Piwik_Controller $view->setTemplate('CoreHome/templates/datatable_actions_recursive.tpl'); } $view->disableSort(); - - $view->setSortedColumn( 'nb_hits', 'desc' ); - $view->disableOffsetInformation(); + $view->setLimit( 100 ); $view->setColumnsToDisplay( array('label','nb_uniq_visitors','nb_hits') ); - $view->setLimit( 100 ); + $view->setSortedColumn( 'nb_uniq_visitors', 'desc' ); + $view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews')); + $view->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnUniquePageviews')); + // computing minimum value to exclude require_once "VisitsSummary/Controller.php"; $visitsInfo = Piwik_VisitsSummary_Controller::getVisitsSummary(); $nbActions = $visitsInfo->getColumn('nb_actions'); $nbActionsLowPopulationThreshold = floor(0.02 * $nbActions); // 2 percent of the total number of actions - // we remove 1 to make sure some actions/downloads are displayed in the case we have a very few of them // and each of them has 1 or 2 hits... $nbActionsLowPopulationThreshold = min($visitsInfo->getColumn('max_actions')-1, $nbActionsLowPopulationThreshold-1); - $view->setExcludeLowPopulation( $nbActionsLowPopulationThreshold, 'nb_hits' ); - + $view->setExcludeLowPopulation( 'nb_hits', $nbActionsLowPopulationThreshold ); $view->main(); // we need to rewrite the phpArray so it contains all the recursive arrays diff --git a/plugins/CoreAdminHome/templates/header.tpl b/plugins/CoreAdminHome/templates/header.tpl index 8ed9472766..55762dccb3 100644 --- a/plugins/CoreAdminHome/templates/header.tpl +++ b/plugins/CoreAdminHome/templates/header.tpl @@ -18,6 +18,7 @@ <link rel="stylesheet" type="text/css" href="themes/default/common.css" /> <link rel="stylesheet" type="text/css" href="plugins/CoreAdminHome/templates/styles.css" /> +<link rel="stylesheet" type="text/css" href="libs/jquery/jquery-calendar.css" /> <link rel="shortcut icon" href="plugins/CoreHome/templates/images/favicon.ico"> diff --git a/plugins/CoreAdminHome/templates/styles.css b/plugins/CoreAdminHome/templates/styles.css index 6bf24d65b4..758e61f7b8 100644 --- a/plugins/CoreAdminHome/templates/styles.css +++ b/plugins/CoreAdminHome/templates/styles.css @@ -14,16 +14,6 @@ a { color: black; } -#ajaxError { - color: red; - text-align: center; - font-weight: bold; - width: 550px; - border: 3px solid red; - margin: 10px; - padding: 10px; -} - table.admin { font-size: 0.9em; font-family: Arial, Helvetica, verdana sans-serif; diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php index 713bba8e19..185cdfb2c2 100644 --- a/plugins/CoreHome/Controller.php +++ b/plugins/CoreHome/Controller.php @@ -1,56 +1,67 @@ -<?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: Controller.php 561 2008-07-21 00:00:35Z matt $
- *
- * @package Piwik_CoreHome
- *
- */
-
-require_once "API/Request.php";
-require_once "ViewDataTable.php";
-
-/**
- * @package Piwik_CoreHome
- */
-class Piwik_CoreHome_Controller extends Piwik_Controller
-{
- function getDefaultAction()
- {
- return 'redirectToIndex';
- }
+<?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: Controller.php 561 2008-07-21 00:00:35Z matt $ + * + * @package Piwik_CoreHome + * + */ + +require_once "API/Request.php"; +require_once "ViewDataTable.php"; + +/** + * @package Piwik_CoreHome + */ +class Piwik_CoreHome_Controller extends Piwik_Controller +{ + function getDefaultAction() + { + return 'redirectToIndex'; + } + + function redirectToIndex() + { + // redirect to Login only for anonymous user + if((bool)Zend_Registry::get('config')->General->default_module_login == true + && Piwik::getCurrentUserLogin() == 'anonymous') + { + return Piwik_FrontController::dispatch('Login', false); + } + parent::redirectToIndex('CoreHome', 'index'); + } - protected function setGeneralVariablesView($view)
- {
- parent::setGeneralVariablesView($view);
- $view->menu = Piwik_GetMenu();
- }
+ protected function setGeneralVariablesView($view) + { + parent::setGeneralVariablesView($view); + $view->menu = Piwik_GetMenu(); + } - public function showInContext()
- {
- $controllerName = Piwik_Common::getRequestVar('moduleToLoad');
- $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index');
-
- $view = $this->getDefaultIndexView();
- $view->basicHtmlView = true;
- $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName );
- echo $view->render();
- }
-
- protected function getDefaultIndexView()
- {
- $view = new Piwik_View('CoreHome/templates/index.tpl');
- $this->setGeneralVariablesView($view);
+ public function showInContext() + { + $controllerName = Piwik_Common::getRequestVar('moduleToLoad'); + $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index'); + + $view = $this->getDefaultIndexView(); + $view->basicHtmlView = true; + $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName ); + echo $view->render(); + } + + protected function getDefaultIndexView() + { + $view = new Piwik_View('CoreHome/templates/index.tpl'); + $this->setGeneralVariablesView($view); $view->content = ''; - return $view;
+ return $view; + } + + public function index() + { + $view = $this->getDefaultIndexView(); + echo $view->render(); } -
- public function index()
- {
- $view = $this->getDefaultIndexView();
- echo $view->render();
- }
-}
+} diff --git a/plugins/CoreHome/templates/calendar.js b/plugins/CoreHome/templates/calendar.js index 8a5b20ef1b..db71c42fe8 100644 --- a/plugins/CoreHome/templates/calendar.js +++ b/plugins/CoreHome/templates/calendar.js @@ -166,7 +166,7 @@ $(document).ready(function(){ _pk_translate('CoreHome_MonthSeptember'), _pk_translate('CoreHome_MonthOctober'), _pk_translate('CoreHome_MonthNovember'), - _pk_translate('CoreHome_MonthDecemeber')] + _pk_translate('CoreHome_MonthDecember')] }, currentDate); diff --git a/plugins/CoreHome/templates/cloud.tpl b/plugins/CoreHome/templates/cloud.tpl index 8989e48a85..b3c208ccc0 100644 --- a/plugins/CoreHome/templates/cloud.tpl +++ b/plugins/CoreHome/templates/cloud.tpl @@ -1,4 +1,4 @@ -<div id="{$id}"> +<div id="{$properties.uniqueId}"> {literal} <style> diff --git a/plugins/CoreHome/templates/datatable.css b/plugins/CoreHome/templates/datatable.css index 364e24cd69..5a3c3577a7 100644 --- a/plugins/CoreHome/templates/datatable.css +++ b/plugins/CoreHome/templates/datatable.css @@ -303,20 +303,6 @@ table thead div { padding: 0.5em; } -#tooltip h3 { - margin:0; - padding:0; -} -#tooltip { - position: absolute; - z-index: 3000; - border: 1px solid #111; - background-color: #eee; - opacity: 0.85; - font-size: 0.7em; - padding:7px; -} - /* Actions table */ table.dataTableActions tr td.labelodd { background-image: none; diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js index c8b7c26079..b24a8f1254 100644 --- a/plugins/CoreHome/templates/datatable.js +++ b/plugins/CoreHome/templates/datatable.js @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Data Table +// DataTable //----------------------------------------------------------------------------- //A list of all our DataTables //Test if the object have already been initialized (multiple includes) @@ -63,8 +63,7 @@ dataTable.prototype = 'filter_pattern', 'filter_column_recursive', 'filter_pattern_recursive', - 'filter_excludelowpop', - 'filter_excludelowpop_value', + 'enable_filter_excludelowpop', 'filter_offset', 'filter_limit', 'filter_sort_column', @@ -216,7 +215,6 @@ dataTable.prototype = handleSort: function(domElem) { var self = this; - if( self.param.enable_sort ) { $('.sortable', domElem).click( @@ -255,19 +253,19 @@ dataTable.prototype = .each( function() { - if(typeof self.param.filter_excludelowpop == 'undefined') + if(typeof self.param.enable_filter_excludelowpop == 'undefined') { - self.param.filter_excludelowpop = 0; + self.param.enable_filter_excludelowpop = 0; } - if(Number(self.param.filter_excludelowpop) != 0) + if(Number(self.param.enable_filter_excludelowpop) != 0) { string = _pk_translate('CoreHome_IncludeAllPopulation'); - self.param.filter_excludelowpop = 1; + self.param.enable_filter_excludelowpop = 1; } else { string = _pk_translate('CoreHome_ExcludeLowPopulation'); - self.param.filter_excludelowpop = 0; + self.param.enable_filter_excludelowpop = 0; } $(this).html(string); } @@ -276,7 +274,7 @@ dataTable.prototype = .click( function() { - self.param.filter_excludelowpop = 1 - self.param.filter_excludelowpop; + self.param.enable_filter_excludelowpop = 1 - self.param.enable_filter_excludelowpop; self.param.filter_offset = 0; self.reloadAjaxDataTable(true, callbackSuccess); } @@ -484,6 +482,19 @@ dataTable.prototype = } ); + $('#tableGoals', domElem) + .show() + .click( + function(){ + // we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30 + // this value is stored in config file General->dataTable_default_limit but this is more an edge case so ok to set it to 10 + delete self.param.filter_limit; + delete self.param.enable_filter_excludelowpop; + self.param.viewDataTable = 'tableGoals'; + self.reloadAjaxDataTable(); + } + ); + $('#tableAllColumnsSwitch', domElem) .show() .click( @@ -492,6 +503,11 @@ dataTable.prototype = // this value is stored in config file General->dataTable_default_limit but this is more an edge case so ok to set it to 10 delete self.param.filter_limit; self.param.viewDataTable = self.param.viewDataTable == 'table' ? 'tableAllColumns' : 'table'; + // when switching to display simple table, do not exclude low pop by default + if(self.param.viewDataTable == 'table') + { + self.param.enable_filter_excludelowpop = 0; + } self.reloadAjaxDataTable(); } ); @@ -505,12 +521,17 @@ dataTable.prototype = var method = $(this).attr('methodToCall'); var filter_limit = $(this).attr('filter_limit'); + var param_date = self.param.date; + var date = $(this).attr('date'); + if(typeof date != 'undefined') { + param_date = date; + } var str = '?module=API' +'&method='+method +'&format='+format +'&idSite='+self.param.idSite +'&period='+self.param.period - +'&date='+self.param.date + +'&date='+param_date +'&token_auth='+piwik.token_auth; if( filter_limit ) { @@ -580,7 +601,7 @@ dataTable.prototype = var urlToLink = $(urlLinkDom).html(); $(urlLinkDom).remove(); - var truncationOffsetBecauseImageIsPrepend = -2; + var truncationOffsetBecauseImageIsPrepend = -2; //website subtable needs -9. self.truncate( $(this), truncationOffsetBecauseImageIsPrepend ); if( urlToLink.match("javascript:") ) @@ -649,7 +670,7 @@ dataTable.prototype = var filtersToRestore = self.resetAllFilters(); self.param.idSubtable = idSubTable; - self.param.action = self.param.actionToLoadTheSubTable; + self.param.action = self.param.controllerActionCalledWhenRequestSubTable; self.reloadAjaxDataTable(false); self.param.action = savedActionVariable; @@ -862,7 +883,7 @@ actionDataTable.prototype = delete self.param.filter_pattern; self.param.idSubtable = idSubTable; - self.param.action = self.param.actionToLoadTheSubTable; + self.param.action = self.param.controllerActionCalledWhenRequestSubTable; self.reloadAjaxDataTable(false, function(resp){self.actionsSubDataTableLoaded(resp)}); self.param.action = savedActionVariable; diff --git a/plugins/CoreHome/templates/datatable.tpl b/plugins/CoreHome/templates/datatable.tpl index 49e233f82e..55291ee9ea 100644 --- a/plugins/CoreHome/templates/datatable.tpl +++ b/plugins/CoreHome/templates/datatable.tpl @@ -1,12 +1,12 @@ -<div id="{$id}">
- <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
+<div id="{$properties.uniqueId}">
+ <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{elseif $javascriptVariablesToSet.viewDataTable=='tableGoals'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
{if count($arrayDataTable) == 0}
<div id="emptyDatatable">{'CoreHome_TableNoData'|translate}</div>
{else}
- <a name="{$id}"></a>
+ <a name="{$properties.uniqueId}"></a>
<table cellspacing="0" class="dataTable">
<thead>
<tr>
@@ -18,11 +18,11 @@ <tbody>
{foreach from=$arrayDataTable item=row}
- <tr {if $row.idsubdatatable}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
+ <tr {if $row.idsubdatatable && $javascriptVariablesToSet.controllerActionCalledWhenRequestSubTable != null}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
{foreach from=$dataTableColumns item=column}
<td>
{if !$row.idsubdatatable && $column.name=='label' && isset($row.metadata.url)}<span id="urlLink">{$row.metadata.url}</span>{/if}
-{if $column.name=='label' && isset($row.metadata.logo)}<img {if isset($row.metadata.logoWidth)}width="{$row.metadata.logoWidth}"{/if} {if isset($row.metadata.logoHeight)}height="{$row.metadata.logoHeight}"{/if} src="{$row.metadata.logo}" />{/if}
+{if $column.name=='label'}{logoHtml metadata=$row.metadata alt=$row.columns.label}{/if}
{* sometimes all columns are not set in the datatable, we assume the value 0 *}
{if isset($row.columns[$column.name])}{$row.columns[$column.name]}{else}0{/if}
</td>
diff --git a/plugins/CoreHome/templates/datatable_actions.tpl b/plugins/CoreHome/templates/datatable_actions.tpl index 94341cddff..c2dbe1868f 100644 --- a/plugins/CoreHome/templates/datatable_actions.tpl +++ b/plugins/CoreHome/templates/datatable_actions.tpl @@ -1,4 +1,4 @@ -<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_js.tpl b/plugins/CoreHome/templates/datatable_actions_js.tpl index 5bf5ed2bca..568fe83d7b 100644 --- a/plugins/CoreHome/templates/datatable_actions_js.tpl +++ b/plugins/CoreHome/templates/datatable_actions_js.tpl @@ -1,12 +1,12 @@ <script type="text/javascript" defer="defer"> $(document).ready(function(){literal}{{/literal} - actionDataTables['{$id}'] = new actionDataTable(); - actionDataTables['{$id}'].param = {literal}{{/literal} + actionDataTables['{$properties.uniqueId}'] = new actionDataTable(); + actionDataTables['{$properties.uniqueId}'].param = {literal}{{/literal} {foreach from=$javascriptVariablesToSet key=name item=value name=loop} {$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if} {/foreach} {literal}};{/literal} - actionDataTables['{$id}'].init('{$id}'); + actionDataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}'); {literal}}{/literal}); </script> diff --git a/plugins/CoreHome/templates/datatable_actions_recursive.tpl b/plugins/CoreHome/templates/datatable_actions_recursive.tpl index bcec62eb2c..01a22255ed 100644 --- a/plugins/CoreHome/templates/datatable_actions_recursive.tpl +++ b/plugins/CoreHome/templates/datatable_actions_recursive.tpl @@ -1,4 +1,4 @@ -<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl index 39e103f691..1cfe58edc9 100644 --- a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl +++ b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl @@ -1,4 +1,4 @@ -<tr id="{$id}"></tr>
+<tr id="{$properties.uniqueId}"></tr>
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
diff --git a/plugins/CoreHome/templates/datatable_footer.tpl b/plugins/CoreHome/templates/datatable_footer.tpl index 355fbe2a3e..1d92fbcad5 100644 --- a/plugins/CoreHome/templates/datatable_footer.tpl +++ b/plugins/CoreHome/templates/datatable_footer.tpl @@ -23,10 +23,11 @@ <span id="exportToFormat" style="display:none;padding-left:4px;">
<img width="16" height="16" src="{$piwikUrl}themes/default/images/export.png" title="{'General_Export'|translate}" />
<span id="linksExportToFormat" style="display:none;">
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="CSV" filter_limit="100">CSV</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="XML" filter_limit="100">XML</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="JSON" filter_limit="100">Json</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="PHP" filter_limit="100">Php</a>
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="CSV" filter_limit="100">CSV</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="XML" filter_limit="100">XML</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="JSON" filter_limit="100">Json</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="PHP" filter_limit="100">Php</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="RSS" filter_limit="100" date="last10"><img border="0" src="{$piwikUrl}themes/default/images/feed.png"></a>
</span>
<a class="viewDataTable" format="cloud"><img width="16" height="16" src="{$piwikUrl}themes/default/images/tagcloud.png" title="{'General_TagCloud'|translate}" /></a>
<a class="viewDataTable" format="graphVerticalBar"><img width="16" height="16" src="{$piwikUrl}themes/default/images/chart_bar.png" title="{'General_VBarGraph'|translate}" /></a>
@@ -44,6 +45,13 @@ {/if}
</span>
{/if}
+ {if $properties.show_goals}
+ <span id="tableGoals" style="display:none;float:right;padding-right:4px;">
+ {if $javascriptVariablesToSet.viewDataTable != 'tableGoals'}
+ <img title="View Goals" src="{$piwikUrl}themes/default/images/goal.png" />
+ {/if}
+ </span>
+ {/if}
</span>
</div>
{/if}
diff --git a/plugins/CoreHome/templates/datatable_js.tpl b/plugins/CoreHome/templates/datatable_js.tpl index c3e5c9e5c3..acae875cf4 100644 --- a/plugins/CoreHome/templates/datatable_js.tpl +++ b/plugins/CoreHome/templates/datatable_js.tpl @@ -1,13 +1,13 @@ <script type="text/javascript" defer="defer"> $(document).ready(function(){literal}{{/literal} - dataTables['{$id}'] = new dataTable(); - dataTables['{$id}'].param = {literal}{{/literal} + dataTables['{$properties.uniqueId}'] = new dataTable(); + dataTables['{$properties.uniqueId}'].param = {literal}{{/literal} {foreach from=$javascriptVariablesToSet key=name item=value name=loop} {$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if} {/foreach} {literal}};{/literal} - dataTables['{$id}'].init('{$id}'); + dataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}'); {literal}}{/literal}); </script> diff --git a/plugins/CoreHome/templates/graph.tpl b/plugins/CoreHome/templates/graph.tpl index 74e6df6e1f..4e2bd9cda4 100644 --- a/plugins/CoreHome/templates/graph.tpl +++ b/plugins/CoreHome/templates/graph.tpl @@ -1,4 +1,4 @@ -<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="{if $graphType=='evolution'}dataTableGraphEvolutionWrapper{else}dataTableGraphWrapper{/if}">
{$jsInvocationTag}
diff --git a/plugins/DBStats/API.php b/plugins/DBStats/API.php index b041b9a227..5c26a6700e 100644 --- a/plugins/DBStats/API.php +++ b/plugins/DBStats/API.php @@ -13,7 +13,7 @@ * * @package Piwik_DBStats_API */ -class Piwik_DBStats_API extends Piwik_Apiable +class Piwik_DBStats_API { static private $instance = null; static public function getInstance() @@ -44,23 +44,6 @@ class Piwik_DBStats_API extends Piwik_Apiable return $status; } - static private function get_size($size) - { - $bytes = array('','K','M','G','T'); - foreach($bytes as $val) - { - if($size > 1024) - { - $size = $size / 1024; - } - else - { - break; - } - } - return round($size, 1)." ".$val; - } - static public function getTableStatus($table, $field = '') { Piwik::checkUserIsSuperUser(); @@ -80,30 +63,31 @@ class Piwik_DBStats_API extends Piwik_Apiable static public function getAllTablesStatus() { - Piwik::isUserIsSuperUser(); + Piwik::checkUserIsSuperUser(); $db = Zend_Registry::get('db'); // http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html $tablesPiwik = Piwik::getTablesInstalled(); $total = array('Name' => 'Total', 'Data_length' => 0, 'Index_length' => 0, 'Rows' => 0); - foreach($tablesPiwik as $table) + $table = array(); + foreach($tablesPiwik as $tableName) { - $t = self::getTableStatus($table); + $t = self::getTableStatus($tableName); $total['Data_length'] += $t['Data_length']; $total['Index_length'] += $t['Index_length']; $total['Rows'] += $t['Rows']; - $t['Total_length'] = self::get_size($t['Index_length']+$t['Data_length']); - $t['Data_length'] = self::get_size($t['Data_length']); - $t['Index_length'] = self::get_size($t['Index_length']); - $t['Rows'] = self::get_size($t['Rows']); - $tables[] = $t; + $t['Total_length'] = Piwik::getPrettySizeFromBytes($t['Index_length']+$t['Data_length']); + $t['Data_length'] = Piwik::getPrettySizeFromBytes($t['Data_length']); + $t['Index_length'] = Piwik::getPrettySizeFromBytes($t['Index_length']); + $t['Rows'] = Piwik::getPrettySizeFromBytes($t['Rows']); + $table[] = $t; } - $total['Total_length'] = self::get_size($total['Data_length']+$total['Index_length']); - $total['Data_length'] = self::get_size($total['Data_length']); - $total['Index_length'] = self::get_size($total['Index_length']); - $total['TotalRows'] = self::get_size($total['Rows']); - $tables['Total'] = $total; + $total['Total_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']+$total['Index_length']); + $total['Data_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']); + $total['Index_length'] = Piwik::getPrettySizeFromBytes($total['Index_length']); + $total['TotalRows'] = Piwik::getPrettySizeFromBytes($total['Rows']); + $table['Total'] = $total; - return $tables; + return $table; } } diff --git a/plugins/DBStats/templates/DBStats.tpl b/plugins/DBStats/templates/DBStats.tpl index 27f0769dcd..e82e095683 100644 --- a/plugins/DBStats/templates/DBStats.tpl +++ b/plugins/DBStats/templates/DBStats.tpl @@ -13,10 +13,11 @@ <th>{'DBStats_RowNumber'|translate}</th>
<th>{'DBStats_DataSize'|translate}</th>
<th>{'DBStats_IndexSize'|translate}</th>
+ <th>{'DBStats_TotalSize'|translate}</th>
</thead>
<tbody id="tables">
{foreach from=$tablesStatus key=index item=table}
- <tr {if $table.Name == 'Total'}class="active"{/if}>
+ <tr {if $table.Name == 'Total'}class="active" style="font-weight:bold;"{/if}>
<td>
{$table.Name}
</td>
@@ -29,6 +30,9 @@ <td>
{$table.Index_length}b
</td>
+ <td>
+ {$table.Total_length}b
+ </td>
</tr>
{/foreach}
</tbody>
diff --git a/plugins/ExampleAPI/API.php b/plugins/ExampleAPI/API.php index 8a6d19af96..ca052d42aa 100644 --- a/plugins/ExampleAPI/API.php +++ b/plugins/ExampleAPI/API.php @@ -20,7 +20,7 @@ * * @package Piwik_ExamplePlugin */ -class Piwik_ExampleAPI_API extends Piwik_Apiable +class Piwik_ExampleAPI_API { static private $instance = null; static public function getInstance() @@ -35,6 +35,7 @@ class Piwik_ExampleAPI_API extends Piwik_Apiable public function getPiwikVersion() { + Piwik::checkUserHasSomeViewAccess(); return Piwik_Version::VERSION; } diff --git a/plugins/ExamplePlugin/ExamplePlugin.php b/plugins/ExamplePlugin/ExamplePlugin.php index 106a6cdbb8..a2cc37bf15 100644 --- a/plugins/ExamplePlugin/ExamplePlugin.php +++ b/plugins/ExamplePlugin/ExamplePlugin.php @@ -21,6 +21,24 @@ class Piwik_ExamplePlugin extends Piwik_Plugin 'version' => '0.1', ); } + + public function getListHooksRegistered() + { + return array( +// 'Controller.renderView' => 'addUniqueVisitorsColumnToGivenReport', + ); + } + + function addUniqueVisitorsColumnToGivenReport($notification) + { + $view = $notification->getNotificationInfo(); + $view = $view['view']; + if($view->getCurrentControllerName() == 'Referers' + && $view->getCurrentControllerAction() == 'getWebsites') + { + $view->addColumnToDisplay('nb_uniq_visitors'); + } + } } // we register the widgets so they appear in the "Add a new widget" window in the dashboard diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php new file mode 100644 index 0000000000..5b1b849f01 --- /dev/null +++ b/plugins/Goals/API.php @@ -0,0 +1,227 @@ +<?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$ + * + * @package Piwik_VisitsSummary + */ + +/** + * @package Piwik_Goals + */ +class Piwik_Goals_API +{ + static private $instance = null; + static public function getInstance() + { + if (self::$instance == null) + { + $c = __CLASS__; + self::$instance = new $c(); + } + return self::$instance; + } + + static public function getGoals( $idSite ) + { + $goals = Zend_Registry::get('db')->fetchAll("SELECT * + FROM ".Piwik_Common::prefixTable('goal')." + WHERE idsite = ? + AND deleted = 0", $idSite); + $cleanedGoals = array(); + foreach($goals as &$goal) + { + unset($goal['idsite']); + $cleanedGoals[$goal['idgoal']] = $goal; + } + return $cleanedGoals; + } + + public function addGoal( $idSite, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue ) + { + Piwik::checkUserHasAdminAccess($idSite); + // save in db + $db = Zend_Registry::get('db'); + $idGoal = $db->fetchOne("SELECT max(idgoal) + 1 + FROM ".Piwik::prefixTable('goal')." + WHERE idsite = ?", $idSite); + if($idGoal == false) + { + $idGoal = 1; + } + self::checkPatternIsValid($patternType, $pattern); + $name = self::checkName($name); + $pattern = self::checkPattern($pattern); + $db->insert(Piwik::prefixTable('goal'), + array( + 'idsite' => $idSite, + 'idgoal' => $idGoal, + 'name' => $name, + 'match_attribute' => $matchAttribute, + 'pattern' => $pattern, + 'pattern_type' => $patternType, + 'case_sensitive' => $caseSensitive, + 'revenue' => $revenue, + 'deleted' => 0, + )); + Piwik_Common::regenerateCacheWebsiteAttributes($idSite); + return $idGoal; + } + + public function updateGoal( $idSite, $idGoal, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue ) + { + Piwik::checkUserHasAdminAccess($idSite); + $name = self::checkName($name); + $pattern = self::checkPattern($pattern); + self::checkPatternIsValid($patternType, $pattern); + Zend_Registry::get('db')->update( Piwik::prefixTable('goal'), + array( + 'name' => $name, + 'match_attribute' => $matchAttribute, + 'pattern' => $pattern, + 'pattern_type' => $patternType, + 'case_sensitive' => $caseSensitive, + 'revenue' => $revenue, + ), + "idsite = '$idSite' AND idgoal = '$idGoal'" + ); + Piwik_Common::regenerateCacheWebsiteAttributes($idSite); + } + + private function checkPatternIsValid($patternType, $pattern) + { + if($patternType == 'exact' + && substr($pattern, 0, 4) != 'http') + { + throw new Exception("If you choose 'exact match', the matching string must be a + URL starting with http:// or https://. For example, 'http://www.yourwebsite.com/newsletter/subscribed.html'."); + } + } + + private function checkName($name) + { + return urldecode($name); + } + + private function checkPattern($pattern) + { + return urldecode($pattern); + } + + public function deleteGoal( $idSite, $idGoal ) + { + Piwik::checkUserHasAdminAccess($idSite); + Zend_Registry::get('db')->query("UPDATE ".Piwik::prefixTable('goal')." + SET deleted = 1 + WHERE idsite = ? + AND idgoal = ?", + array($idSite, $idGoal)); + $db->query("DELETE FROM ".Piwik::prefixTable("log_conversion")." WHERE idgoal = ?", $idGoal); + Piwik_Common::regenerateCacheWebsiteAttributes($idSite); + } + +// public function getConversionsReturningVisitors( $idSite, $period, $date, $idGoal = false ) +// { +// +// } +// +// public function getConversionsNewVisitors( $idSite, $period, $date, $idGoal = false ) +// { +// +// } + + // TODO + public function getConversionRateReturningVisitors( $idSite, $period, $date, $idGoal = false ) + { + // visits converted for returning for all goals = call Frequency API + if($idGoal === false) + { + $request = new Piwik_API_Request("method=VisitFrequency.getConvertedVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original"); + $nbVisitsConvertedReturningVisitors = $request->process(); + } + // visits converted for returning = nb conversion for this goal + else + { + $nbVisitsConvertedReturningVisitors = $this->getNumeric($idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal, 1)); + } + // all returning visits + $request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original"); + $nbVisitsReturning = $request->process(); +// echo $nbVisitsConvertedReturningVisitors; +// echo "<br>". $nbVisitsReturning;exit; + return $this->getPercentage($nbVisitsConvertedReturningVisitors, $nbVisitsReturning); + } + + public function getConversionRateNewVisitors( $idSite, $period, $date, $idGoal = false ) + { + // new visits converted for all goals = nb visits converted - nb visits converted for returning + if($idGoal == false) + { + $request = new Piwik_API_Request("method=VisitsSummary.getVisitsConverted&idSite=$idSite&period=$period&date=$date&format=original"); + $convertedVisits = $request->process(); + $request = new Piwik_API_Request("method=VisitFrequency.getConvertedVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original"); + $convertedReturningVisits = $request->process(); + $convertedNewVisits = $convertedVisits - $convertedReturningVisits; + } + // new visits converted for a given goal = nb conversion for this goal for new visits + else + { + $convertedNewVisits = $this->getNumeric($idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal, 0)); + } + // all new visits = all visits - all returning visits + $request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original"); + $nbVisitsReturning = $request->process(); + $request = new Piwik_API_Request("method=VisitsSummary.getVisits&idSite=$idSite&period=$period&date=$date&format=original"); + $nbVisits = $request->process(); + $newVisits = $nbVisits - $nbVisitsReturning; + return $this->getPercentage($convertedNewVisits, $newVisits); + } + + protected function getPercentage($a, $b) + { + if($b == 0) + { + return 0; + } + return round(100 * $a / $b, Piwik_Goals::ROUNDING_PRECISION); + } + + public function get( $idSite, $period, $date, $idGoal = false ) + { + Piwik::checkUserHasViewAccess( $idSite ); + $archive = Piwik_Archive::build($idSite, $period, $date ); + $toFetch = array( Piwik_Goals::getRecordName('nb_conversions', $idGoal), + Piwik_Goals::getRecordName('conversion_rate', $idGoal), + Piwik_Goals::getRecordName('revenue', $idGoal), + ); + $dataTable = $archive->getDataTableFromNumeric($toFetch); + return $dataTable; + } + + protected static function getNumeric( $idSite, $period, $date, $toFetch ) + { + Piwik::checkUserHasViewAccess( $idSite ); + $archive = Piwik_Archive::build($idSite, $period, $date ); + $dataTable = $archive->getNumeric($toFetch); + return $dataTable; + } + + public function getConversions( $idSite, $period, $date, $idGoal = false ) + { + return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal)); + } + + public function getConversionRate( $idSite, $period, $date, $idGoal = false ) + { + return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('conversion_rate', $idGoal)); + } + + public function getRevenue( $idSite, $period, $date, $idGoal = false ) + { + return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('revenue', $idGoal)); + } + +} diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php new file mode 100644 index 0000000000..935d616258 --- /dev/null +++ b/plugins/Goals/Controller.php @@ -0,0 +1,150 @@ +<?php +require_once "Goals/API.php"; + +class Piwik_Goals_Controller extends Piwik_Controller +{ + const CONVERSION_RATE_PRECISION = 1; + function goalReport() + { + $idGoal = Piwik_Common::getRequestVar('idGoal', null, 'int'); + $idSite = Piwik_Common::getRequestVar('idSite'); + $goals = Piwik_Goals_API::getGoals($idSite); + if(!isset($goals[$idGoal])) + { + throw new Exception("idgoal $idGoal not valid."); + } + $goalDefinition = $goals[$idGoal]; + + $view = new Piwik_View('Goals/templates/single_goal.tpl'); + $view->currency = Piwik::getCurrency(); + $goal = $this->getMetricsForGoal($idGoal); + foreach($goal as $name => $value) + { + $view->$name = $value; + } + $view->name = $goalDefinition['name']; + $view->title = $goalDefinition['name'] . ' - Conversions'; + $view->graphEvolution = $this->getLastNbConversionsGraph(true); + $view->nameGraphEvolution = 'GoalsgetLastNbConversionsGraph'; // must be the function name used above + + $columnNbConversions = 'goal_'.$idGoal.'_nb_conversions'; + $columnConversionRate = 'goal_'.$idGoal.'_conversion_rate'; + + $topSegmentsToLoad = array( + 'country' => 'UserCountry.getCountry', + 'keyword' => 'Referers.getKeywords', + 'website' => 'Referers.getWebsites', + ); + + $topSegments = array(); + foreach($topSegmentsToLoad as $segmentName => $apiMethod) + { + $request = new Piwik_API_Request("method=$apiMethod + &format=original + &filter_update_columns_when_show_all_goals=1 + &filter_sort_order=desc + &filter_sort_column=$columnNbConversions + &filter_limit=3"); + $datatable = $request->process(); + $topSegment = array(); + foreach($datatable->getRows() as $row) + { + $topSegment[] = array ( + 'name' => $row->getColumn('label'), + 'nb_conversions' => $row->getColumn($columnNbConversions), + 'conversion_rate' => $row->getColumn($columnConversionRate), + 'metadata' => $row->getMetadata(), + ); + } + $topSegments[$segmentName] = $topSegment; +// echo $datatable; + } + + $request = new Piwik_API_Request("method=Goals.getConversionRateReturningVisitors&format=original"); + $view->conversion_rate_returning = round( $request->process(), self::CONVERSION_RATE_PRECISION ); + $request = new Piwik_API_Request("method=Goals.getConversionRateNewVisitors&format=original"); + $view->conversion_rate_new = round( $request->process(), self::CONVERSION_RATE_PRECISION ); + + $view->topSegments = $topSegments; + echo $view->render(); + //todo next: nice legends for graphs + } + + protected function getMetricsForGoal($goalId) + { + $request = new Piwik_API_Request("method=Goals.get&format=original&idGoal=$goalId"); + $datatable = $request->process(); + return array ( + 'id' => $goalId, + 'nb_conversions' => $datatable->getRowFromLabel(Piwik_Goals::getRecordName('nb_conversions', $goalId))->getColumn('value'), + 'conversion_rate' => round($datatable->getRowFromLabel(Piwik_Goals::getRecordName('conversion_rate', $goalId))->getColumn('value'), 1), + 'revenue' => $datatable->getRowFromLabel(Piwik_Goals::getRecordName('revenue', $goalId))->getColumn('value'), + 'urlSparklineConversions' => $this->getUrlSparkline('getLastNbConversionsGraph', $goalId) . "&idGoal=".$goalId, + 'urlSparklineConversionRate' => $this->getUrlSparkline('getLastConversionRateGraph', $goalId) . "&idGoal=".$goalId, + 'urlSparklineRevenue' => $this->getUrlSparkline('getLastRevenueGraph', $goalId) . "&idGoal=".$goalId, + ); + } + + function index() + { + $view = new Piwik_View('Goals/templates/overview.tpl'); + $view->currency = Piwik::getCurrency(); + + $view->title = 'All goals - evolution'; + $view->graphEvolution = $this->getLastNbConversionsGraph(true); + $view->nameGraphEvolution = 'GoalsgetLastNbConversionsGraph'; // must be the function name used above + + // sparkline for the historical data of the above values + $view->urlSparklineConversions = $this->getUrlSparkline('getLastNbConversionsGraph'); + $view->urlSparklineConversionRate = $this->getUrlSparkline('getLastConversionRateGraph'); + $view->urlSparklineRevenue = $this->getUrlSparkline('getLastRevenueGraph'); + + $request = new Piwik_API_Request("method=Goals.get&format=original"); + $datatable = $request->process(); + $view->nb_conversions = $datatable->getRowFromLabel('Goal_nb_conversions')->getColumn('value'); + $view->conversion_rate = $datatable->getRowFromLabel('Goal_conversion_rate')->getColumn('value'); + $view->revenue = $datatable->getRowFromLabel('Goal_revenue')->getColumn('value'); + + $goalMetrics = array(); + + $idSite = Piwik_Common::getRequestVar('idSite'); + $goals = Piwik_Goals_API::getGoals($idSite); + foreach($goals as $idGoal => $goal) + { + $goalMetrics[$idGoal] = $this->getMetricsForGoal($idGoal); + $goalMetrics[$idGoal]['name'] = $goal['name']; + } + + $view->goalMetrics = $goalMetrics; + $view->goals = $goals; + $view->goalsJSON = json_encode($goals); + $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite); + echo $view->render(); + } + + function addNewGoal() + { + $view = new Piwik_View('Goals/templates/add_new_goal.tpl'); + $idSite = Piwik_Common::getRequestVar('idSite'); + $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite); + $view->currency = Piwik::getCurrency(); + $view->onlyShowAddNewGoal = true; + echo $view->render(); + } + + function getLastNbConversionsGraph( $fetch = false ) + { + $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversions'); + return $this->renderView($view, $fetch); + } + function getLastConversionRateGraph( $fetch = false ) + { + $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversionRate'); + return $this->renderView($view, $fetch); + } + function getLastRevenueGraph( $fetch = false ) + { + $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getRevenue'); + return $this->renderView($view, $fetch); + } +} diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php new file mode 100644 index 0000000000..550f0e7288 --- /dev/null +++ b/plugins/Goals/Goals.php @@ -0,0 +1,206 @@ +<?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$ + * + * @package Piwik_Referers + */ + +require_once "core/Tracker/GoalManager.php"; + +/** + * @package Piwik_Referers + */ +class Piwik_Goals extends Piwik_Plugin +{ + const ROUNDING_PRECISION = 2; + + public function getInformation() + { + $info = array( + 'name' => '(ALPHA) Goal Tracking', + 'description' => 'Create Goals and see reports about your goal conversions: evolution over time, revenue per visit, conversions per referer, per keyword, etc.', + 'author' => 'Piwik', + 'homepage' => 'http://piwik.org/', + 'version' => '0.1', + 'TrackerPlugin' => true + ); + + return $info; + } + + function getListHooksRegistered() + { + $hooks = array( + 'Common.fetchWebsiteAttributes' => 'fetchGoalsFromDb', + 'ArchiveProcessing_Day.compute' => 'archiveDay', + 'ArchiveProcessing_Period.compute' => 'archivePeriod', + 'WidgetsList.add' => 'addWidgets', + 'Menu.add' => 'addMenus', + ); + return $hooks; + } + + function fetchGoalsFromDb($notification) + { + require_once "Goals/API.php"; + $info = $notification->getNotificationInfo(); + $idsite = $info['idsite']; + + // add the 'goal' entry in the website array + $array =& $notification->getNotificationObject(); + $array['goals'] = Piwik_Goals_API::getGoals($idsite); + } + + function addWidgets() + { +// Piwik_AddWidget( 'Referers', 'getKeywords', Piwik_Translate('Referers_WidgetKeywords')); + } + + function addMenus() + { + $goals = Piwik_Tracker_GoalManager::getGoalDefinitions(Piwik_Common::getRequestVar('idSite')); + if(count($goals)==0) + { + Piwik_AddMenu('Goals', 'Add a new Goal', array('module' => 'Goals', 'action' => 'addNewGoal')); + } + else + { + Piwik_AddMenu('Goals', 'Overview', array('module' => 'Goals')); + foreach($goals as $goal) + { + Piwik_AddMenu('Goals', str_replace('%', '%%', $goal['name']), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal'])); + } + } + } + + /** + * @param string $recordName 'nb_conversions' + * @param int $idGoal idGoal to return the metrics for, or false to return overall + * @param int $visitorReturning 0 for new visitors, 1 for returning visitors, false for all + * @return unknown + */ + static public function getRecordName($recordName, $idGoal = false, $visitorReturning = false) + { + $idGoalStr = $returningStr = ''; + if($idGoal !== false) + { + $idGoalStr = $idGoal . "_"; + } + if($visitorReturning !== false) + { + $returningStr = 'visitor_returning_' . $visitorReturning . '_'; + } + return 'Goal_' . $returningStr . $idGoalStr . $recordName; + } + + function archivePeriod($notification ) + { + /** + * @var Piwik_ArchiveProcessing_Period + */ + $archiveProcessing = $notification->getNotificationObject(); + + $metricsToSum = array( 'nb_conversions', 'revenue'); + $goalIdsToSum = Piwik_Tracker_GoalManager::getGoalIds($archiveProcessing->idsite); + + $fieldsToSum = array(); + foreach($metricsToSum as $metricName) + { + foreach($goalIdsToSum as $goalId) + { + $fieldsToSum[] = self::getRecordName($metricName, $goalId); + $fieldsToSum[] = self::getRecordName($metricName, $goalId, 0); + $fieldsToSum[] = self::getRecordName($metricName, $goalId, 1); + } + $fieldsToSum[] = self::getRecordName($metricName); + } + $records = $archiveProcessing->archiveNumericValuesSum($fieldsToSum); + + // also recording conversion_rate for each goal + foreach($goalIdsToSum as $goalId) + { + $nb_conversions = $records[self::getRecordName('nb_conversions', $goalId)]->value; + $conversion_rate = $this->getConversionRate($nb_conversions, $archiveProcessing); + $record = new Piwik_ArchiveProcessing_Record_Numeric(self::getRecordName('conversion_rate', $goalId), $conversion_rate); + } + + // global conversion rate + $nb_conversions = $records[self::getRecordName('nb_conversions')]->value; + $conversion_rate = $this->getConversionRate($nb_conversions, $archiveProcessing); + $record = new Piwik_ArchiveProcessing_Record_Numeric(self::getRecordName('conversion_rate'), $conversion_rate); + + } + + function archiveDay( $notification ) + { + /** + * @var Piwik_ArchiveProcessing_Day + */ + $archiveProcessing = $notification->getNotificationObject(); + + // by processing visitor_returning segment, we can also simply sum and get stats for all goals. + $query = $archiveProcessing->queryConversionsBySegment('visitor_returning'); + + $nb_conversions = $revenue = 0; + $goals = $goalsByVisitorReturning = array(); + while($row = $query->fetch() ) + { + $goalsByVisitorReturning[$row['idgoal']][$row['visitor_returning']] = $archiveProcessing->getGoalRowFromQueryRow($row); + + if(!isset($goals[$row['idgoal']])) $goals[$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats($row, $goals[$row['idgoal']]); + + $revenue += $row['revenue']; + $nb_conversions += $row['nb_conversions']; + } + + // Stats by goal, for all visitors + foreach($goals as $idgoal => $values) + { + foreach($values as $metricId => $value) + { + $metricName = Piwik_Archive::$mappingFromIdToNameGoal[$metricId]; + $recordName = self::getRecordName($metricName, $idgoal); + $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value); + } + $conversion_rate = $this->getConversionRate($values[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS], $archiveProcessing); + $recordName = self::getRecordName('conversion_rate', $idgoal); + $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $conversion_rate); + } + + // Stats by goal, for visitor returning / non returning + foreach($goalsByVisitorReturning as $idgoal => $values) + { + foreach($values as $visitor_returning => $goalValues) + { + foreach($goalValues as $metricId => $value) + { + $metricName = Piwik_Archive::$mappingFromIdToNameGoal[$metricId]; + $recordName = self::getRecordName($metricName, $idgoal, $visitor_returning); + $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value); +// echo $record . "<br>"; + } + } + } + + // Stats for all goals + $totalAllGoals = array( + self::getRecordName('conversion_rate') => round(100 * $archiveProcessing->getNumberOfVisitsConverted() / $archiveProcessing->getNumberOfVisits(), self::ROUNDING_PRECISION), + self::getRecordName('nb_conversions') => $nb_conversions, + self::getRecordName('revenue') => $revenue, + ); + foreach($totalAllGoals as $recordName => $value) + { + $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value); + } + } + + function getConversionRate($count, $archiveProcessing) + { + return round(100 * $count / $archiveProcessing->getNumberOfVisits(), self::ROUNDING_PRECISION); + } +} diff --git a/plugins/Goals/templates/GoalForm.js b/plugins/Goals/templates/GoalForm.js new file mode 100644 index 0000000000..4345bc8958 --- /dev/null +++ b/plugins/Goals/templates/GoalForm.js @@ -0,0 +1,124 @@ + +function showAddNewGoal() +{ + $("#GoalForm").show(); + $("#EditGoals").hide(); + $.scrollTo("#AddEditGoals", 400); + return false; +} + +function showEditGoals() +{ + $("#EditGoals").show(); + $("#GoalForm").hide(); + $.scrollTo("#AddEditGoals", 400); + return false; +} + +// init the goal form with existing goal value, if any +function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, pattern, patternType, caseSensitive, revenue, goalId) +{ + $('#goal_name').val(goalName); + $('input[@name=match_attribute][value='+matchAttribute+']').attr('checked', true); + $('#match_attribute_name').html(mappingMatchTypeName[matchAttribute]); + $('#examples_pattern').html(mappingMatchTypeExamples[matchAttribute]); + $('option[value='+patternType+']').attr('selected', true); + $('input[name=pattern]').val(pattern); + $('#case_sensitive').attr('checked', caseSensitive); + $('input[name=revenue]').val(revenue); + $('input[name=methodGoalAPI]').val(goalMethodAPI); + $('#goal_submit').val(submitText); + if(goalId != undefined) { + $('input[name=goalIdUpdate]').val(goalId); + } +} + +function initAndShowAddGoalForm() +{ + initGoalForm('Goals.addGoal', 'Add Goal', '', 'url', '', 'contains', false, '0'); + return showAddNewGoal(); +} +function bindGoalForm() +{ + $('input[@name=match_attribute]').click( function() { + var matchTypeId = $(this).attr('value'); + $('#match_attribute_name').html(mappingMatchTypeName[matchTypeId]); + $('#examples_pattern').html(mappingMatchTypeExamples[matchTypeId]); + }); + + $('#goal_submit').click( function() { + // prepare ajax query to API to add goal + ajaxRequestAddGoal = getAjaxAddGoal(); + $.ajax( ajaxRequestAddGoal ); + return false; + }); + + $('a[name=linkAddNewGoal]').click( function(){ + initAndShowAddGoalForm(); + } ); +} + +function bindListGoalEdit() +{ + $('a[name=linkEditGoal]').click( function() { + var goalId = $(this).attr('id'); + var goal = piwik.goals[goalId]; + initGoalForm("Goals.updateGoal", "Update Goal", goal.name, goal.match_attribute, goal.pattern, goal.pattern_type, (goal.case_sensitive=='0' ? false : true), goal.revenue, goalId); + showAddNewGoal(); + return false; + }); + + $('a[name=linkDeleteGoal]').click( function() { + var goalId = $(this).attr('id'); + var goalName = 'test goal';//piwik.goals[goalId][name] + if(confirm(sprintf('Are you sure you want to delete the Goal %s?','"'+goalName+'"'))) + { + $.ajax( getAjaxDeleteGoal( goalId ) ); + return false; + } + }); + + $('a[name=linkEditGoals]').click( function(){ + return showEditGoals(); + } ); +} +function getAjaxDeleteGoal(idGoal) +{ + var ajaxRequest = getStandardAjaxConf(); + toggleAjaxLoading(); + + var parameters = new Object; + parameters.idSite = piwik.idSite; + parameters.idGoal = idGoal; + parameters.method = 'Goals.deleteGoal'; + parameters.module = 'API'; + parameters.format = 'json'; + parameters.token_auth = piwik.token_auth; + ajaxRequest.data = parameters; + return ajaxRequest; +} + +function getAjaxAddGoal() +{ + var ajaxRequest = getStandardAjaxConf(); + toggleAjaxLoading(); + + var parameters = new Object; + + parameters.idSite = piwik.idSite; + parameters.name = encodeURIComponent( $('#goal_name').val() ); + parameters.matchAttribute = $('input[name=match_attribute][checked]').val(); + parameters.patternType = $('[name=pattern_type]').val(); + parameters.pattern = encodeURIComponent( $('input[name=pattern]').val() ); + parameters.caseSensitive = $('#case_sensitive').attr('checked') == true ? 1: 0; + parameters.revenue = $('input[name=revenue]').val(); + + parameters.idGoal = $('input[name=goalIdUpdate]').val(); + parameters.method = $('input[name=methodGoalAPI]').val(); + parameters.module = 'API'; + parameters.format = 'json'; + parameters.token_auth = piwik.token_auth; + + ajaxRequest.data = parameters; + return ajaxRequest; +}
\ No newline at end of file diff --git a/plugins/Goals/templates/add_edit_goal.tpl b/plugins/Goals/templates/add_edit_goal.tpl new file mode 100644 index 0000000000..2ca55ca102 --- /dev/null +++ b/plugins/Goals/templates/add_edit_goal.tpl @@ -0,0 +1,49 @@ + +<div id="AddEditGoals"> +{if isset($onlyShowAddNewGoal)} + <h2>Add a new Goal</h2> +{else} + <h2><a onclick='' name="linkAddNewGoal">+ Add a new Goal</a> + or <a onclick='' name="linkEditGoals">Edit</a> existing Goals</h2> +{/if} + + <div> + <div id="ajaxError" style="display:none"></div> + <div id="ajaxLoading" style="display:none"><div id="loadingPiwik"><img src="themes/default/images/loading-blue.gif" alt="" /> {'General_LoadingData'|translate}</div></div> + </div> + +{if !isset($onlyShowAddNewGoal)} + {include file="Goals/templates/list_goal_edit.tpl"} +{/if} + {include file="Goals/templates/form_add_goal.tpl"} + + <a id='bottom'></a> +</div> + +{literal} +<script type="text/javascript" src="plugins/Goals/templates/GoalForm.js"></script> +<script language="javascript"> + +var mappingMatchTypeName = { + "url": "URL", + "file": "filename", + "external_website": "external website URL" +}; +var mappingMatchTypeExamples = { + "url": "eg. contains 'checkout/confirmation'<br>eg. is exactly 'http://example.com/thank-you.html'<br>eg. matches the expression '[.*]\\\/demo\\\/[.*]'", + "file": "eg. contains 'files/brochure.pdf'<br>eg. is exactly 'http://example.com/files/brochure.pdf'<br>eg. matches the expression '[.*]\\\.zip'", + "external_website": "eg. contains 'amazon.com'<br>eg. is exactly 'http://mypartner.com/landing.html'<br>eg. matches the expression 'http://www.amazon.com\\\/[.*]\\\/yourAffiliateId'" +}; + +bindGoalForm(); + +{/literal} + +{if !isset($onlyShowAddNewGoal)} +piwik.goals = {$goalsJSON}; +bindListGoalEdit(); +{else} +initAndShowAddGoalForm(); +{/if} + +</script> diff --git a/plugins/Goals/templates/add_new_goal.tpl b/plugins/Goals/templates/add_new_goal.tpl new file mode 100644 index 0000000000..05a7f66e8d --- /dev/null +++ b/plugins/Goals/templates/add_new_goal.tpl @@ -0,0 +1,8 @@ + +{if $userCanEditGoals} + {include file=Goals/templates/add_edit_goal.tpl} +{else} +Only an Administrator or the Super User can add Goals for a given website. +Please ask your Piwik administrator to set up a Goal for your website. +<br>Tracking Goals are a great tool to help you maximize your website performance! +{/if} diff --git a/plugins/Goals/templates/form_add_goal.tpl b/plugins/Goals/templates/form_add_goal.tpl new file mode 100644 index 0000000000..95c4f6d3d9 --- /dev/null +++ b/plugins/Goals/templates/form_add_goal.tpl @@ -0,0 +1,67 @@ +{literal} +<style> +.goalInlineHelp{ +color:#9B9B9B; +} +</style> +{/literal} +<span id='GoalForm' style="display:none;"> +<form> + <table class="tableForm"> + <tr> + <td>Goal Name </td> + <td><input type="text" name="name" value="" id="goal_name" /></td> + </tr> + <tr> + <td>Goal is triggered when visitors:</td> + <td> + <input type="radio" id="match_attribute_url" value="url" name="match_attribute"/> + <label for="match_attribute_url">Visit a given URL (page or group of pages)</label> + <br> + <input type="radio" id="match_attribute_file" value="file" name="match_attribute"/> + <label for="match_attribute_file">Download a file</label> + <br> + <input type="radio" id="match_attribute_external_website" value="external_website" name="match_attribute"/> + <label for="match_attribute_external_website">Click on a Link to an external website </label> + </td> + </tr> + <tr> + <td>where the <span id="match_attribute_name"></span></td> + <td> + <select name="pattern_type"> + <option value="contains">contains</option> + <option value="exact">is exactly</option> + <option value="regex">matches the expression</option> + </select> + + <input type="text" name="pattern" value=""/> + <br> + <div id="examples_pattern" class="goalInlineHelp"></div> + <br> + <span style="float:right"> + (optional) <input type="checkbox" id="case_sensitive"/> + <label for="case_sensitive">Case sensitive match</label> + </span> + </td> + </tr> + <tr> + <td>(optional) Goal default value is </td> + <td>{$currency} <input type="text" name="revenue" size="1" value="0"/> + <div class="goalInlineHelp"> + For example, a Contact Form submitted by a visitor <br> + may be worth $10 on average. Piwik will help you understand <br> + how well your visitors segments are performing.</div> + </td> + </tr> + <tr> + <td colspan="2" style="border:0"> + <div class="submit"> + <input type="hidden" name="methodGoalAPI" value=""> + <input type="hidden" name="goalIdUpdate" value=""> + <input type="submit" value="Add Goal" name="submit" id="goal_submit" class="submit" /> + </div> + </td> + </tr> + </table> +</form> +</span>
\ No newline at end of file diff --git a/plugins/Goals/templates/list_goal_edit.tpl b/plugins/Goals/templates/list_goal_edit.tpl new file mode 100644 index 0000000000..081497cade --- /dev/null +++ b/plugins/Goals/templates/list_goal_edit.tpl @@ -0,0 +1,22 @@ +<span id='EditGoals' style="display:none;"> + <table class="tableForm"> + <thead style="font-weight:bold"> + <td>Id</td> + <td>Goal Name</td> + <td>Goal is Triggered when</td> + <td>Revenue</td> + <td>Edit</td> + <td>Delete</td> + </thead> + {foreach from=$goals item=goal} + <tr> + <td>{$goal.idgoal}</td> + <td>{$goal.name}</td> + <td>{$goal.match_attribute} <br>Pattern {$goal.pattern_type}: {$goal.pattern}</b></td> + <td>{if $goal.revenue==0}-{else}{$currency}{$goal.revenue}{/if}</td> + <td><a href='#' name="linkEditGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/edit.png' border=0> Edit</a></td> + <td><a href='#' name="linkDeleteGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/remove.png' border=0> Delete</a></td> + </tr> + {/foreach} + </table> +</span>
\ No newline at end of file diff --git a/plugins/Goals/templates/list_top_segment.tpl b/plugins/Goals/templates/list_top_segment.tpl new file mode 100644 index 0000000000..6dbe69813f --- /dev/null +++ b/plugins/Goals/templates/list_top_segment.tpl @@ -0,0 +1,5 @@ + +{foreach from=$topSegment item=element name=topGoalElements} +<span class='goalTopElement' title='<b>{$element.nb_conversions}</b> conversions, <b>{$element.conversion_rate}%</b> conversion rate'> +{$element.name}</span>{logoHtml metadata=$element.metadata alt=$element.name}{if $smarty.foreach.topGoalElements.iteration == $smarty.foreach.topGoalElements.total-1} and {elseif $smarty.foreach.topGoalElements.iteration < $smarty.foreach.topGoalElements.total-1}, {else}{/if} +{/foreach} {* (<a href=''>more</a>) *} diff --git a/plugins/Goals/templates/overview.tpl b/plugins/Goals/templates/overview.tpl new file mode 100644 index 0000000000..04bf1af90d --- /dev/null +++ b/plugins/Goals/templates/overview.tpl @@ -0,0 +1,27 @@ + +{include file="Goals/templates/title_and_evolution_graph.tpl"} + +{foreach from=$goalMetrics item=goal} +{assign var=nb_conversions value=$goal.nb_conversions} +{assign var=conversion_rate value=$goal.conversion_rate} +<h2 style="padding-top: 30px;">{$goal.name} (goal)</h3> +<table width=700px> + <tr><td> + <p>{sparkline src=$goal.urlSparklineConversions}<span> + {'%s conversions'|translate:"<strong>$nb_conversions</strong>"}</span></p> + </td><td> + <p>{sparkline src=$goal.urlSparklineConversionRate}<span> + {'%s conversion rate'|translate:"<strong>$conversion_rate%</strong>"}</span></p> + </td><td> + {* (<a href=''>more</a>) *} + </td></tr> +</table> + +{/foreach} + +{if $userCanEditGoals} + <hr style="margin:30px 0px"> + {include file=Goals/templates/add_edit_goal.tpl} +{/if} + +{include file="Goals/templates/release_notes.tpl}
\ No newline at end of file diff --git a/plugins/Goals/templates/release_notes.tpl b/plugins/Goals/templates/release_notes.tpl new file mode 100644 index 0000000000..dce9ec63b2 --- /dev/null +++ b/plugins/Goals/templates/release_notes.tpl @@ -0,0 +1,20 @@ +<hr> +<b>About the Goal Tracking Plugin</b><br> +<pre> +The Goal Tracking Plugin is in alpha release. There is more coming soon! +- The Goal Report page will display conversion table by search engines, country, keyword, campaign, etc. +- The Goal Overview page will link to a Goal Report page with a "(more)" link that will ajax reload the page +- Goals could be triggered using javascript event, with custom revenue +- internationalization of all strings +- provide documentation, screenshots, blog post + add screenshot and inline help in "Add a New Goal" +- provide widgets for the dashboard, general goal overview, and one widget for each goal. With: graph evolution, sparklines. Widget with top segments for each goal. + +Known bugs +- The Goal total nb conversions should be sum of all goal conversions (wrong number when deleting a Goal) +- After adding goal, the window should refresh to the goal report page, and not to the dashboard +- Outlink trailing slash is automatically deleted from the URL, there would be a problem when trying to exact match a URL with trailing slash +- All graph labelling are not correct (always printing nb_uniq_visitors even when showing conversion or conversion_rate) see <a href='http://dev.piwik.org/trac/ticket/322'>#322</a> + +Give us Feedback! +If you find any other bug, or if you have suggestions, please send us a message using the "Give us feedback" link at the top of the Piwik pages. +</pre>
\ No newline at end of file diff --git a/plugins/Goals/templates/single_goal.tpl b/plugins/Goals/templates/single_goal.tpl new file mode 100644 index 0000000000..b605c17490 --- /dev/null +++ b/plugins/Goals/templates/single_goal.tpl @@ -0,0 +1,37 @@ +{include file="Goals/templates/title_and_evolution_graph.tpl"} + +{if $nb_conversions > 0} + <h2>Conversions Overview</h2> + <ul class="ulGoalTopElements"> + <li>Your best converting countries are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.country}</li> + {if count($topSegments.keyword)>0}<li>Your top converting keywords are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.keyword}</li>{/if} + {if count($topSegments.website)>0}<li>Your best converting websites referers are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.website}</li>{/if} + <li>Returning visitors conversion rate is <b>{$conversion_rate_returning}%</b>, New Visitors conversion rate is <b>{$conversion_rate_new}%</b></li> + </ul> +{/if} + + +{literal} +<style> +ul.ulGoalTopElements { + list-style-type:circle; + margin-left:30px; +} +.ulGoalTopElements a { + text-decoration:none; + color:#0033CC; + border-bottom:1px dotted #0033CC; + line-height:2em; +} +.goalTopElement { + border-bottom:1px dotted; +} +</style> +<script> +$(document).ready( function() { + $('.goalTopElement') + .Tooltip() + ; + }); +</script> +{/literal}
\ No newline at end of file diff --git a/plugins/Goals/templates/title_and_evolution_graph.tpl b/plugins/Goals/templates/title_and_evolution_graph.tpl new file mode 100644 index 0000000000..0b1b8d2c7b --- /dev/null +++ b/plugins/Goals/templates/title_and_evolution_graph.tpl @@ -0,0 +1,20 @@ +<script type="text/javascript" src="plugins/CoreHome/templates/sparkline.js"></script> + +<a name="evolutionGraph" graphId="{$nameGraphEvolution}"></a> +<h2>{$title}</h2> +{$graphEvolution} + +<table> + <tr><td> + <p>{sparkline src=$urlSparklineConversions}<span> + {'%s conversions'|translate:"<strong>$nb_conversions</strong>"}</span></p> + {if $revenue != 0 } + <p>{sparkline src=$urlSparklineRevenue}<span> + {'%s overall revenue'|translate:"<strong>$currency$revenue</strong>"}</span></p> + {/if} + </td><td valign="top"> + <p>{sparkline src=$urlSparklineConversionRate}<span> + {'%s overall conversion rate (visits with a completed goal)'|translate:"<strong>$conversion_rate%</strong>"}</span></p> + </td></tr> +</table> + diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index f843263eb9..1bee5cdbbf 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -1,135 +1,135 @@ -<?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$
- *
- * @package Piwik_Installation
- */
-
-require_once "Installation/View.php";
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_Installation_Controller extends Piwik_Controller
-{
- // public so plugins can add/delete installation steps
- public $steps = array(
- 'welcome',
- 'systemCheck',
- 'databaseSetup',
- 'tablesCreation',
- 'generalSetup',
- 'firstWebsiteSetup',
- 'displayJavascriptCode',
- 'finished'
- );
-
- protected $pathView = 'Installation/templates/';
-
- public function __construct()
- {
- if(!isset($_SESSION['currentStepDone']))
- {
- $_SESSION['currentStepDone'] = '';
- }
-
- Piwik_PostEvent('InstallationController.construct', $this);
- }
-
- public function getInstallationSteps()
- {
- return $this->steps;
- }
-
- function getDefaultAction()
- {
- return $this->steps[0];
- }
-
- function welcome()
+<?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$ + * + * @package Piwik_Installation + */ + +require_once "Installation/View.php"; + +/** + * + * @package Piwik_Installation + */ +class Piwik_Installation_Controller extends Piwik_Controller +{ + // public so plugins can add/delete installation steps + public $steps = array( + 'welcome', + 'systemCheck', + 'databaseSetup', + 'tablesCreation', + 'generalSetup', + 'firstWebsiteSetup', + 'displayJavascriptCode', + 'finished' + ); + + protected $pathView = 'Installation/templates/'; + + public function __construct() + { + if(!isset($_SESSION['currentStepDone'])) + { + $_SESSION['currentStepDone'] = ''; + } + + Piwik_PostEvent('InstallationController.construct', $this); + } + + public function getInstallationSteps() + { + return $this->steps; + } + + function getDefaultAction() + { + return $this->steps[0]; + } + + function welcome() { require_once "Login/Controller.php"; Piwik_Login_Controller::clearSession(); -
- $view = new Piwik_Install_View(
- $this->pathView . 'welcome.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->skipThisStep( __FUNCTION__ );
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function systemCheck()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'systemCheck.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->infos = $this->getSystemInformation();
- $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
-
- $view->showNextStep = !$view->problemWithSomeDirectories
- && $view->infos['phpVersion_ok']
- && $view->infos['pdo_ok']
- && $view->infos['pdo_mysql_ok']
-
- ;
- $_SESSION['currentStepDone'] = __FUNCTION__;
-
- echo $view->render();
- }
-
-
- function databaseSetup()
- {
- // case the user hits the back button
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
-
- $view = new Piwik_Install_View(
- $this->pathView . 'databaseSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->showNextStep = false;
- require_once "FormDatabaseSetup.php";
- $form = new Piwik_Installation_FormDatabaseSetup;
-
- if($form->validate())
- {
- $dbInfos = array(
- 'host' => $form->getSubmitValue('host'),
- 'username' => $form->getSubmitValue('username'),
- 'password' => $form->getSubmitValue('password'),
- 'dbname' => $form->getSubmitValue('dbname'),
- 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
- 'adapter' => Zend_Registry::get('config')->database->adapter,
- 'port' => Zend_Registry::get('config')->database->port,
- );
-
- $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"';
-
- if(($portIndex = strpos($dbInfos['host'],':')) !== false)
- {
- $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
- $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
- }
+ + $view = new Piwik_Install_View( + $this->pathView . 'welcome.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->skipThisStep( __FUNCTION__ ); + $view->showNextStep = true; + + $_SESSION['currentStepDone'] = __FUNCTION__; + echo $view->render(); + } + + function systemCheck() + { + $view = new Piwik_Install_View( + $this->pathView . 'systemCheck.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + + $view->infos = $this->getSystemInformation(); + $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories'])); + + $view->showNextStep = !$view->problemWithSomeDirectories + && $view->infos['phpVersion_ok'] + && $view->infos['pdo_ok'] + && $view->infos['pdo_mysql_ok'] + + ; + $_SESSION['currentStepDone'] = __FUNCTION__; + + echo $view->render(); + } + + + function databaseSetup() + { + // case the user hits the back button + $_SESSION['skipThisStep']['firstWebsiteSetup'] = false; + $_SESSION['skipThisStep']['displayJavascriptCode'] = false; + + $view = new Piwik_Install_View( + $this->pathView . 'databaseSetup.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + + $view->showNextStep = false; + require_once "FormDatabaseSetup.php"; + $form = new Piwik_Installation_FormDatabaseSetup; + + if($form->validate()) + { + $dbInfos = array( + 'host' => $form->getSubmitValue('host'), + 'username' => $form->getSubmitValue('username'), + 'password' => $form->getSubmitValue('password'), + 'dbname' => $form->getSubmitValue('dbname'), + 'tables_prefix' => $form->getSubmitValue('tables_prefix'), + 'adapter' => Zend_Registry::get('config')->database->adapter, + 'port' => Zend_Registry::get('config')->database->port, + ); + + $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"'; + + if(($portIndex = strpos($dbInfos['host'],':')) !== false) + { + $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 ); + $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex); + } try{ try { @@ -152,64 +152,64 @@ class Piwik_Installation_Controller extends Piwik_Controller { throw new Exception(vsprintf("Your MySQL version is %s but Piwik requires at least %s.", array($mysqlVersion, $minimumMysqlVersion))); } -
+ $_SESSION['db_infos'] = $dbInfos; - $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
- }
- $view->addForm($form);
-
- $view->infos = $this->getSystemInformation();
-
- echo $view->render();
- }
-
- function tablesCreation()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'tablesCreation.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->createDbFromSessionInformation();
-
- if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
- {
- Piwik::dropTables();
- $view->existingTablesDeleted = true;
-
- // when the user decides to drop the tables then we dont skip the next steps anymore
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
- }
-
- $tablesInstalled = Piwik::getTablesInstalled();
- $tablesToInstall = Piwik::getTablesNames();
-
- if(count($tablesInstalled) > 0)
- {
- $view->someTablesInstalled = true;
- $view->tablesInstalled = implode(", ", $tablesInstalled);
-
- // when the user reuses the same tables we skip the website creation step
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = true;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = true;
- }
- else
- {
- Piwik::createTables();
- Piwik::createAnonymousUser();
+ $this->redirectToNextStep( __FUNCTION__ ); + } catch(Exception $e) { + $view->errorMessage = $e->getMessage(); + } + } + $view->addForm($form); + + $view->infos = $this->getSystemInformation(); + + echo $view->render(); + } + + function tablesCreation() + { + $view = new Piwik_Install_View( + $this->pathView . 'tablesCreation.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + $this->createDbFromSessionInformation(); + + if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1) + { + Piwik::dropTables(); + $view->existingTablesDeleted = true; + + // when the user decides to drop the tables then we dont skip the next steps anymore + $_SESSION['skipThisStep']['firstWebsiteSetup'] = false; + $_SESSION['skipThisStep']['displayJavascriptCode'] = false; + } + + $tablesInstalled = Piwik::getTablesInstalled(); + $tablesToInstall = Piwik::getTablesNames(); + + if(count($tablesInstalled) > 0) + { + $view->someTablesInstalled = true; + $view->tablesInstalled = implode(", ", $tablesInstalled); + + // when the user reuses the same tables we skip the website creation step + $_SESSION['skipThisStep']['firstWebsiteSetup'] = true; + $_SESSION['skipThisStep']['displayJavascriptCode'] = true; + } + else + { + Piwik::createTables(); + Piwik::createAnonymousUser(); require_once "Version.php"; - require_once "Updater.php";
+ require_once "Updater.php"; $updater = new Piwik_Updater(); - $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
- $view->tablesCreated = true;
- $view->showNextStep = true;
- }
+ $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION); + $view->tablesCreated = true; + $view->showNextStep = true; + } if(isset($_SESSION['databaseCreated']) && $_SESSION['databaseCreated'] === true) @@ -218,294 +218,294 @@ class Piwik_Installation_Controller extends Piwik_Controller $view->databaseCreated = true; $_SESSION['databaseCreated'] = null; } -
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function generalSetup()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'generalSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormGeneralSetup.php";
- $form = new Piwik_Installation_FormGeneralSetup;
-
- if($form->validate())
- {
- $superUserInfos = array(
- 'login' => $form->getSubmitValue('login'),
- 'password' => md5( $form->getSubmitValue('password') ),
- 'email' => $form->getSubmitValue('email'),
- );
-
- $_SESSION['superuser_infos'] = $superUserInfos;
- $this->redirectToNextStep( __FUNCTION__ );
- }
- $view->addForm($form);
-
- echo $view->render();
- }
-
- public function firstWebsiteSetup()
- {
-
- $view = new Piwik_Install_View(
- $this->pathView . 'firstWebsiteSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormFirstWebsiteSetup.php";
- $form = new Piwik_Installation_FormFirstWebsiteSetup;
-
- if( !isset($_SESSION['generalSetupSuccessMessage']))
- {
- $view->displayGeneralSetupSuccess = true;
- $_SESSION['generalSetupSuccessMessage'] = true;
- }
-
- if($form->validate())
- {
- // we setup the superuser login & password in the config that will be checked by the
- // API authentication process
- Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos'];
-
- $name = urlencode($form->getSubmitValue('siteName'));
- $url = urlencode($form->getSubmitValue('url'));
-
- $this->initObjectsToCallAPI();
-
- require_once "API/Request.php";
- $request = new Piwik_API_Request("
- method=SitesManager.addSite
- &siteName=$name
- &urls=$url
- &format=original
- ");
-
- try {
- $result = $request->process();
- $_SESSION['site_idSite'] = $result;
- $_SESSION['site_name'] = $name;
- $_SESSION['site_url'] = $url;
-
- $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
-
- }
- $view->addForm($form);
- echo $view->render();
+ + $_SESSION['currentStepDone'] = __FUNCTION__; + echo $view->render(); + } + + function generalSetup() + { + $view = new Piwik_Install_View( + $this->pathView . 'generalSetup.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + + require_once "FormGeneralSetup.php"; + $form = new Piwik_Installation_FormGeneralSetup; + + if($form->validate()) + { + $superUserInfos = array( + 'login' => $form->getSubmitValue('login'), + 'password' => md5( $form->getSubmitValue('password') ), + 'email' => $form->getSubmitValue('email'), + ); + + $_SESSION['superuser_infos'] = $superUserInfos; + $this->redirectToNextStep( __FUNCTION__ ); + } + $view->addForm($form); + + echo $view->render(); } -
- public function displayJavascriptCode()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'displayJavascriptCode.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- if( !isset($_SESSION['firstWebsiteSetupSuccessMessage']))
- {
- $view->displayfirstWebsiteSetupSuccess = true;
- $_SESSION['firstWebsiteSetupSuccessMessage'] = true;
- }
-
-
- $view->websiteName = urldecode($_SESSION['site_name']);
-
- $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName());
-
- $view->javascriptTag = $jsTag;
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- public function finished()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'finished.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->writeConfigFileFromSession();
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- $view->showNextStep = false;
-
- setcookie(session_name(), session_id(), 1, '/');
- @session_destroy();
- echo $view->render();
- }
-
- protected function initObjectsToCallAPI()
- {
- // connect to the database using the DB infos currently in the session
- $this->createDbFromSessionInformation();
-
- // create the fake access to grant super user privilege
- Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser);
-
- // we need to create the logs otherwise the API request throws an exception
- Piwik::createLogObject();
- }
-
- protected function writeConfigFileFromSession()
+ + public function firstWebsiteSetup() + { + + $view = new Piwik_Install_View( + $this->pathView . 'firstWebsiteSetup.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + + require_once "FormFirstWebsiteSetup.php"; + $form = new Piwik_Installation_FormFirstWebsiteSetup; + + if( !isset($_SESSION['generalSetupSuccessMessage'])) + { + $view->displayGeneralSetupSuccess = true; + $_SESSION['generalSetupSuccessMessage'] = true; + } + + if($form->validate()) + { + // we setup the superuser login & password in the config that will be checked by the + // API authentication process + Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos']; + + $name = urlencode($form->getSubmitValue('siteName')); + $url = urlencode($form->getSubmitValue('url')); + + $this->initObjectsToCallAPI(); + + require_once "API/Request.php"; + $request = new Piwik_API_Request(" + method=SitesManager.addSite + &siteName=$name + &urls=$url + &format=original + "); + + try { + $result = $request->process(); + $_SESSION['site_idSite'] = $result; + $_SESSION['site_name'] = $name; + $_SESSION['site_url'] = $url; + + $this->redirectToNextStep( __FUNCTION__ ); + } catch(Exception $e) { + $view->errorMessage = $e->getMessage(); + } + + } + $view->addForm($form); + echo $view->render(); + } + + public function displayJavascriptCode() + { + $view = new Piwik_Install_View( + $this->pathView . 'displayJavascriptCode.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + + if( !isset($_SESSION['firstWebsiteSetupSuccessMessage'])) + { + $view->displayfirstWebsiteSetupSuccess = true; + $_SESSION['firstWebsiteSetupSuccessMessage'] = true; + } + + + $view->websiteName = urldecode($_SESSION['site_name']); + + $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName()); + + $view->javascriptTag = $jsTag; + $view->showNextStep = true; + + $_SESSION['currentStepDone'] = __FUNCTION__; + echo $view->render(); + } + + public function finished() + { + $view = new Piwik_Install_View( + $this->pathView . 'finished.tpl', + $this->getInstallationSteps(), + __FUNCTION__ + ); + $this->checkPreviousStepIsValid( __FUNCTION__ ); + $this->skipThisStep( __FUNCTION__ ); + $this->writeConfigFileFromSession(); + + $_SESSION['currentStepDone'] = __FUNCTION__; + $view->showNextStep = false; + + setcookie(session_name(), session_id(), 1, '/'); + @session_destroy(); + echo $view->render(); + } + + protected function initObjectsToCallAPI() + { + // connect to the database using the DB infos currently in the session + $this->createDbFromSessionInformation(); + + // create the fake access to grant super user privilege + Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser); + + // we need to create the logs otherwise the API request throws an exception + Piwik::createLogObject(); + } + + protected function writeConfigFileFromSession() { if(!isset($_SESSION['superuser_infos']) || !isset($_SESSION['db_infos'])) { return; - }
- $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
- $configFile .= "; file automatically generated during the piwik installation process\n";
-
- // super user information
- $configFile .= "[superuser]\n";
- foreach( $_SESSION['superuser_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
- $configFile .= "\n";
-
- // database information
- $configFile .= "[database]\n";
- foreach($_SESSION['db_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
-
- file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile);
- }
- /**
- * The previous step is valid if it is either
- * - any step before (OK to go back)
- * - the current step (case when validating a form)
- */
- function checkPreviousStepIsValid( $currentStep )
+ } + $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n"; + $configFile .= "; file automatically generated during the piwik installation process\n"; + + // super user information + $configFile .= "[superuser]\n"; + foreach( $_SESSION['superuser_infos'] as $key => $value) + { + $configFile .= "$key = $value\n"; + } + $configFile .= "\n"; + + // database information + $configFile .= "[database]\n"; + foreach($_SESSION['db_infos'] as $key => $value) + { + $configFile .= "$key = $value\n"; + } + + file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile); + } + /** + * The previous step is valid if it is either + * - any step before (OK to go back) + * - the current step (case when validating a form) + */ + function checkPreviousStepIsValid( $currentStep ) { if(empty($_SESSION['currentStepDone'])) { return; - }
- // the currentStep
- $currentStepId = array_search($currentStep, $this->steps);
-
- // the step before
- $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps);
+ } + // the currentStep + $currentStepId = array_search($currentStep, $this->steps); + + // the step before + $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps); - // not OK if currentStepId > previous+1
- if( $currentStepId > $previousStepId + 1 )
- {
- $message = "Error: it seems you try to skip a step of the Installation process,
- or your cookies are disabled.
- <br /><b>Make sure your cookies are enabled</b> and go back
- <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'>
- to the first page of the installation</a>.";
- Piwik::exitWithErrorMessage( $message );
- }
- }
-
- protected function redirectToNextStep($currentStep)
- {
- $_SESSION['currentStepDone'] = $currentStep;
- $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)];
- Piwik::redirectToModule('Installation' , $nextStep);
- }
-
- protected function createDbFromSessionInformation()
- {
- $dbInfos = $_SESSION['db_infos'];
-
- Zend_Registry::get('config')->database = $dbInfos;
- Piwik::createDatabaseObject($dbInfos);
- }
-
- protected function getSystemInformation()
- {
- $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version;
- $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
-
- $infos = array();
-
- $infos['directories'] = Piwik::checkDirectoriesWritable();
- $infos['phpVersion_minimum'] = $minimumPhpVersion;
- $infos['phpVersion'] = phpversion();
- $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1;
-
- $extensions = @get_loaded_extensions();
-
- $infos['pdo_ok'] = false;
- if (in_array('PDO', $extensions))
- {
- $infos['pdo_ok'] = true;
- }
-
- $infos['pdo_mysql_ok'] = false;
- if (in_array('pdo_mysql', $extensions))
- {
- $infos['pdo_mysql_ok'] = true;
- }
- - $infos['gd_ok'] = false;
- if (in_array('gd', $extensions))
- {
- $gdInfo = gd_info();
- $infos['gd_version'] = $gdInfo['GD Version'];
- ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion);
- if($gdVersion[0] >= 2)
- {
- $infos['gd_ok'] = true;
- }
- }
-
- $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']);
- $infos['serverOs'] = @php_uname();
- $infos['serverTime'] = date('H:i:s');
-
- $infos['setTimeLimit_ok'] = false;
- if(function_exists( 'set_time_limit'))
- {
- $infos['setTimeLimit_ok'] = true;
- }
-
- $infos['mail_ok'] = false;
- if(function_exists('mail'))
- {
- $infos['mail_ok'] = true;
- }
-
- $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
- $infos['memoryMinimum'] = $minimumMemoryLimit;
-
- $infos['memory_ok'] = true;
- // on windows the ini_get is not working?
- $infos['memoryCurrent'] = '?M';
-
- $raised = Piwik::raiseMemoryLimitIfNecessary();
- if( $memoryValue = Piwik::getMemoryLimitValue() )
- {
- $infos['memoryCurrent'] = $memoryValue."M";
- $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
- }
-
- return $infos;
+ // not OK if currentStepId > previous+1 + if( $currentStepId > $previousStepId + 1 ) + { + $message = "Error: it seems you try to skip a step of the Installation process, + or your cookies are disabled. + <br /><b>Make sure your cookies are enabled</b> and go back + <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'> + to the first page of the installation</a>."; + Piwik::exitWithErrorMessage( $message ); + } + } + + protected function redirectToNextStep($currentStep) + { + $_SESSION['currentStepDone'] = $currentStep; + $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)]; + Piwik::redirectToModule('Installation' , $nextStep); + } + + protected function createDbFromSessionInformation() + { + $dbInfos = $_SESSION['db_infos']; + + Zend_Registry::get('config')->database = $dbInfos; + Piwik::createDatabaseObject($dbInfos); + } + + protected function getSystemInformation() + { + $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version; + $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit; + + $infos = array(); + + $infos['directories'] = Piwik::checkDirectoriesWritable(); + $infos['phpVersion_minimum'] = $minimumPhpVersion; + $infos['phpVersion'] = phpversion(); + $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1; + + $extensions = @get_loaded_extensions(); + + $infos['pdo_ok'] = false; + if (in_array('PDO', $extensions)) + { + $infos['pdo_ok'] = true; + } + + $infos['pdo_mysql_ok'] = false; + if (in_array('pdo_mysql', $extensions)) + { + $infos['pdo_mysql_ok'] = true; + } + + $infos['gd_ok'] = false; + if (in_array('gd', $extensions)) + { + $gdInfo = gd_info(); + $infos['gd_version'] = $gdInfo['GD Version']; + ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion); + if($gdVersion[0] >= 2) + { + $infos['gd_ok'] = true; + } + } + + $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']); + $infos['serverOs'] = @php_uname(); + $infos['serverTime'] = date('H:i:s'); + + $infos['setTimeLimit_ok'] = false; + if(function_exists( 'set_time_limit')) + { + $infos['setTimeLimit_ok'] = true; + } + + $infos['mail_ok'] = false; + if(function_exists('mail')) + { + $infos['mail_ok'] = true; + } + + $infos['registerGlobals_ok'] = ini_get('register_globals') == 0; + $infos['memoryMinimum'] = $minimumMemoryLimit; + + $infos['memory_ok'] = true; + // on windows the ini_get is not working? + $infos['memoryCurrent'] = '?M'; + + $raised = Piwik::raiseMemoryLimitIfNecessary(); + if( $memoryValue = Piwik::getMemoryLimitValue() ) + { + $infos['memoryCurrent'] = $memoryValue."M"; + $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit; + } + + return $infos; } @@ -516,18 +516,18 @@ class Piwik_Installation_Controller extends Piwik_Controller { $this->redirectToNextStep($step); } - }
-}
-
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_FakeAccess_SetSuperUser {
- function checkUserIsSuperUser()
- {
- return true;
- }
- function loadAccess() {}
-}
+ } +} + + +/** + * + * @package Piwik_Installation + */ +class Piwik_FakeAccess_SetSuperUser { + function checkUserIsSuperUser() + { + return true; + } + function loadAccess() {} +} diff --git a/plugins/Installation/templates/firstWebsiteSetup.tpl b/plugins/Installation/templates/firstWebsiteSetup.tpl index ca83f4ccd8..3c0446bc3c 100644 --- a/plugins/Installation/templates/firstWebsiteSetup.tpl +++ b/plugins/Installation/templates/firstWebsiteSetup.tpl @@ -9,8 +9,6 @@ <h1>{'Installation_SetupWebsite'|translate}</h1>
-
-
{if isset($errorMessage)}
<div class="error">
<img src="themes/default/images/error_medium.png">
@@ -20,7 +18,6 @@ </div>
{/if}
-
{if isset($form_data)}
{include file=default/genericForm.tpl}
{/if}
diff --git a/plugins/LanguagesManager/API.php b/plugins/LanguagesManager/API.php index 20411a7021..edb5d1aa7b 100644 --- a/plugins/LanguagesManager/API.php +++ b/plugins/LanguagesManager/API.php @@ -2,7 +2,7 @@ /** * @package Piwik_LanguagesManager */ -class Piwik_LanguagesManager_API extends Piwik_Apiable +class Piwik_LanguagesManager_API { static private $instance = null; static public function getInstance() diff --git a/plugins/Live/API.php b/plugins/Live/API.php new file mode 100644 index 0000000000..3ff93c223a --- /dev/null +++ b/plugins/Live/API.php @@ -0,0 +1,143 @@ +<?php +require_once "Live/Visitor.php"; + +class Piwik_Live_API +{ + static private $instance = null; + + /* + * @return Piwik_Live_API + */ + static public function getInstance() + { + if (self::$instance == null) + { + $c = __CLASS__; + self::$instance = new $c(); + } + return self::$instance; + } + + /* + * @return Piwik_DataTable + */ + public function getLastVisitForVisitor( $visitorId, $idSite = null ) + { + return $this->getLastVisitsForVisitor($visitorId, $idSite, 1); + } + + /* + * @return Piwik_DataTable + */ + public function getLastVisitsForVisitor( $visitorId, $idSite, $limit = 10 ) + { + if(is_null($idSite)) + { + Piwik::checkUserIsSuperUser(); + } + else + { + Piwik::checkUserHasViewAccess($idSite); + } + $visitorDetails = self::loadLastVisitorDetailsFromDatabase($visitorId, $idSite, $limit); + $table = self::getCleanedVisitorsFromDetails($visitorDetails); + return $table; + } + + /* + * @return Piwik_DataTable + */ + public function getLastVisits( $idSite = false, $limit = 10, $minIdVisit = false ) + { + if(is_null($idSite)) + { + Piwik::checkUserIsSuperUser(); + } + else + { + Piwik::checkUserHasViewAccess($idSite); + } + $visitorDetails = self::loadLastVisitorDetailsFromDatabase(null, $idSite, $limit, $minIdVisit); + $table = self::getCleanedVisitorsFromDetails($visitorDetails); + return $table; + } + + /* + * @return Piwik_DataTable + */ + static private function getCleanedVisitorsFromDetails($visitorDetails) + { + $table = new Piwik_DataTable(); + foreach($visitorDetails as $visitorDetail) + { + self::cleanVisitorDetails($visitorDetail); + $visitor = new Piwik_Live_Visitor($visitorDetail); + $visitorDetailsArray = $visitor->getAllVisitorDetails(); + $dateTimeVisit = Piwik_Date::factory($visitorDetailsArray['firstActionTimestamp']); + $visitorDetailsArray['serverDatePretty'] = $dateTimeVisit->getLocalized('%a %d %b'); + $visitorDetailsArray['serverTimePretty'] = $dateTimeVisit->getLocalized('%X'); + $table->addRowFromArray( array(Piwik_DataTable_Row::COLUMNS => $visitorDetailsArray)); + } + return $table; + } + + /* + * @return array + */ + private function loadLastVisitorDetailsFromDatabase($visitorId = null, $idSite = null, $limit = null, $minIdVisit = false ) + { + $where = $whereBind = array(); + + if(!is_null($idSite)) + { + $where[] = " idsite = ? "; + $whereBind[] = $idSite; + } + + if(!is_null($visitorId)) + { + $where[] = " visitor_idcookie = ? "; + $whereBind[] = $visitorId; + } + + if(!$minIdVisit) + { + $where[] = " idvisit > ? "; + $whereBind[] = $minIdVisit; + } + + $sqlWhere = ""; + if(count($where) > 0) + { + $sqlWhere = " WHERE " . join(' AND ', $where); + } + + $sql = "SELECT * + FROM " . Piwik::prefixTable('log_visit') . " + $sqlWhere + ORDER BY idvisit DESC + LIMIT $limit"; + + return Piwik_FetchAll($sql, $whereBind); + } + + /* + * @return void + */ + static private function cleanVisitorDetails( &$visitorDetails ) + { + $toUnset = array('config_md5config'); + if(!Piwik::isUserIsSuperUser()) + { + $toUnset[] = 'visitor_idcookie'; + $toUnset[] = 'location_ip'; + } + foreach($toUnset as $keyName) + { + if(isset($visitorDetails[$keyName])) + { + unset($visitorDetails[$keyName]); + } + } + } +} diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php new file mode 100644 index 0000000000..aeb13829d9 --- /dev/null +++ b/plugins/Live/Controller.php @@ -0,0 +1,37 @@ +<?php +require_once 'Live/API.php'; + +Piwik_AddWidget('Live', 'widget', 'Live Visitors!'); + +class Piwik_Live_Controller extends Piwik_Controller +{ + function widget() + { + echo "Live Visitors!"; + } + + function getLastVisits($fetch = false) + { + $idSite = Piwik_Common::getRequestVar('idSite', null, 'int'); + $limit = 10; + $api = new Piwik_API_Request("method=Live.getLastVisits&idSite=$idSite&limit=$limit&format=php&serialize=0&disable_generic_filters=1"); + + $view = new Piwik_View('Live/templates/lastVisits.tpl'); + $view->visitors = $api->process(); + $rendered = $view->render($fetch); + + if($fetch) + { + return $rendered; + } + echo $rendered; + } + + function index() + { + $view = new Piwik_View('Live/templates/index.tpl'); + $this->setGeneralVariablesView($view); + $view->visitors = $this->getLastVisits($fetch = true); + echo $view->render(); + } +} diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php new file mode 100644 index 0000000000..d6432bf447 --- /dev/null +++ b/plugins/Live/Live.php @@ -0,0 +1,14 @@ +<?php +class Piwik_Live extends Piwik_Plugin +{ + public function getInformation() + { + return array( + 'name' => 'Live Visitors', + 'description' => 'Live Visitors!', + 'author' => 'Piwik', + 'homepage' => 'http://piwik.org/', + 'version' => '0.1', + ); + } +} diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php new file mode 100644 index 0000000000..0145641a69 --- /dev/null +++ b/plugins/Live/Visitor.php @@ -0,0 +1,262 @@ +<?php +//TODO add api to get actions name/count/first/last/etc +require_once "Referers/functions.php"; +require_once "UserCountry/functions.php"; +require_once "UserSettings/functions.php"; +require_once "Provider/functions.php"; + +class Piwik_Live_Visitor +{ + function __construct($visitorRawData) + { + $this->details = $visitorRawData; + } + + function getAllVisitorDetails() + { + return array( + 'ip' => $this->getIp(), + 'idVisit' => $this->getIdVisit(), + 'countActions' => $this->getNumberOfActions(), + 'isVisitorReturning' => $this->isVisitorReturning(), + 'country' => $this->getCountryName(), + 'countryFlag' => $this->getCountryFlag(), + 'continent' => $this->getContinent(), + 'provider' => $this->getProvider(), + 'providerUrl' => $this->getProviderUrl(), + 'idSite' => $this->getIdSite(), + 'serverDate' => $this->getServerDate(), + 'visitLength' => $this->getVisitLength(), + 'visitLengthPretty' => $this->getVisitLengthPretty(), + 'firstActionTimestamp' => $this->getTimestampFirstAction(), + 'lastActionTimestamp' => $this->getTimestampLastAction(), + + 'refererType' => $this->getRefererType(), + 'refererName' => $this->getRefererTypeName(), + 'keywords' => $this->getKeywords(), + 'refererUrl' => $this->getRefererUrl(), + 'refererName' => $this->getRefererName(), + 'searchEngineUrl' => $this->getSearchEngineUrl(), + 'searchEngineIcon' => $this->getSearchEngineIcon(), + + 'operatingSystem' => $this->getOperatingSystem(), + 'operatingSystemShortName' => $this->getOperatingSystemShortName(), + 'operatingSystemIcon' => $this->getOperatingSystemIcon(), + 'browserFamily' => $this->getBrowserFamily(), + 'browserFamilyDescription' => $this->getBrowserFamilyDescription(), + 'browser' => $this->getBrowser(), + 'browserIcon' => $this->getBrowserIcon(), + 'screen' => $this->getScreenType(), + 'resolution' => $this->getResolution(), + 'screenIcon' => $this->getScreenTypeIcon(), + 'plugins' => $this->getPlugins(), + ); + } + + function getServerDate() + { + return $this->details['visit_server_date']; + } + + function getIp() + { + if(isset($this->details['location_ip'])) + { + return long2ip($this->details['location_ip']); + } + return false; + } + + function getIdVisit() + { + return $this->details['idvisit']; + } + + function getIdSite() + { + return $this->details['idsite']; + } + + function getNumberOfActions() + { + return $this->details['visit_total_actions']; + } + + function getVisitLength() + { + return $this->details['visit_total_time']; + } + + function getVisitLengthPretty() + { + return Piwik::getPrettyTimeFromSeconds($this->details['visit_total_time']); + } + + function isVisitorReturning() + { + return $this->details['visitor_returning']; + } + + function getTimestampFirstAction() + { + return strtotime($this->details['visit_first_action_time']); + } + + function getTimestampLastAction() + { + return strtotime($this->details['visit_last_action_time']); + } + + function getCountryName() + { + return Piwik_CountryTranslate($this->details['location_country']); + } + + function getCountryFlag() + { + return Piwik_getFlagFromCode($this->details['location_country']); + } + + function getContinent() + { + return Piwik_ContinentTranslate($this->details['location_continent']); + } + + function getRefererType() + { + $map = array( + Piwik_Common::REFERER_TYPE_SEARCH_ENGINE => 'searchEngine', + Piwik_Common::REFERER_TYPE_WEBSITE => 'website', + Piwik_Common::REFERER_TYPE_DIRECT_ENTRY => 'directEntry', + Piwik_Common::REFERER_TYPE_CAMPAIGN => 'campaign', + ); + if(isset($map[$this->details['referer_type']])) + { + return $map[$this->details['referer_type']]; + } + return $map[Piwik_Common::REFERER_TYPE_DIRECT_ENTRY]; + } + + function getRefererTypeName() + { + return Piwik_getRefererTypeLabel($this->details['referer_type']); + } + + function getKeywords() + { + return $this->details['referer_keyword']; + } + + function getRefererUrl() + { + return $this->details['referer_url']; + } + + function getRefererName() + { + return $this->details['referer_name']; + } + + function getSearchEngineUrl() + { + if($this->getRefererType() == 'searchEngine' + && !empty($this->details['referer_name'])) + { + return Piwik_getSearchEngineUrlFromName($this->details['referer_name']); + } + return null; + } + + function getSearchEngineIcon() + { + $searchEngine = $this->getSearchEngineUrl(); + if( !is_null($searchEngine) ) + { + return Piwik_getSearchEngineLogoFromName($searchEngine); + } + return null; + } + + function getPlugins() + { + $plugins = array( + 'config_pdf', + 'config_flash', + 'config_java', + 'config_director', + 'config_quicktime', + 'config_realplayer', + 'config_windowsmedia' + ); + $return = array(); + foreach($plugins as $plugin) + { + if($this->details[$plugin] == 1) + { + $pluginShortName = substr($plugin, 7); + $return[] = $pluginShortName; + } + } + return implode(", ", $return); + } + + function getOperatingSystem() + { + return Piwik_getOSLabel($this->details['config_os']); + } + + function getOperatingSystemShortName() + { + return Piwik_getOSShortLabel($this->details['config_os']); + } + + function getOperatingSystemIcon() + { + return Piwik_getOSLogo($this->details['config_os']); + } + + function getBrowserFamilyDescription() + { + return Piwik_getBrowserTypeLabel($this->getBrowserFamily()); + } + + function getBrowserFamily() + { + return Piwik_getBrowserFamily($this->details['config_browser_name']); + } + + function getBrowser() + { + return Piwik_getBrowserLabel($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']); + } + + function getBrowserIcon() + { + return Piwik_getBrowsersLogo($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']); + } + + function getScreenType() + { + return Piwik_getScreenTypeFromResolution($this->details['config_resolution']); + } + + function getResolution() + { + return $this->details['config_resolution']; + } + + function getScreenTypeIcon() + { + return Piwik_getScreensLogo($this->getScreenType()); + } + + function getProvider() + { + return Piwik_getHostnameName($this->details['location_provider']); + } + + function getProviderUrl() + { + return Piwik_getHostnameUrl($this->details['location_provider']); + } +} diff --git a/plugins/Live/templates/images/pause.gif b/plugins/Live/templates/images/pause.gif Binary files differnew file mode 100644 index 0000000000..5954f9f545 --- /dev/null +++ b/plugins/Live/templates/images/pause.gif diff --git a/plugins/Live/templates/images/pause_disabled.gif b/plugins/Live/templates/images/pause_disabled.gif Binary files differnew file mode 100644 index 0000000000..98b79f7402 --- /dev/null +++ b/plugins/Live/templates/images/pause_disabled.gif diff --git a/plugins/Live/templates/images/play.gif b/plugins/Live/templates/images/play.gif Binary files differnew file mode 100644 index 0000000000..87eded433b --- /dev/null +++ b/plugins/Live/templates/images/play.gif diff --git a/plugins/Live/templates/images/play_disabled.gif b/plugins/Live/templates/images/play_disabled.gif Binary files differnew file mode 100644 index 0000000000..ef69513d69 --- /dev/null +++ b/plugins/Live/templates/images/play_disabled.gif diff --git a/plugins/Live/templates/images/returningVisitor.gif b/plugins/Live/templates/images/returningVisitor.gif Binary files differnew file mode 100644 index 0000000000..bc71867e55 --- /dev/null +++ b/plugins/Live/templates/images/returningVisitor.gif diff --git a/plugins/Live/templates/index.tpl b/plugins/Live/templates/index.tpl new file mode 100644 index 0000000000..a30eef0739 --- /dev/null +++ b/plugins/Live/templates/index.tpl @@ -0,0 +1,83 @@ +{assign var=showSitesSelection value=true} +{assign var=showPeriodSelection value=false} +{include file="CoreAdminHome/templates/header.tpl"} + +<h1> Plugin Development version </h1> + +{literal} +<script type="text/javascript" src="plugins/Live/templates/scripts/spy.js"></script> + +<script type="text/javascript" charset="utf-8"> + $(document).ready(function() { + $('#visits').spy({ limit: 10, 'fadeInSpeed': '1400', ajax: 'index.php?module=Live&idSite=1&action=getLastVisits', timeout: 5000, customParameterName: 'minIdVisit', customParameterValueCallback: lastIdVisit, fadeInSpeed: 1400 }); + }); + + function lastIdVisit() + { + return $('#visits > div:lt(2) .idvisit').html(); + } + var pauseImage = "plugins/Live/templates/images/pause.gif"; + var pauseDisabledImage = "plugins/Live/templates/images/pause_disabled.gif"; + var playImage = "plugins/Live/templates/images/play.gif"; + var playDisabledImage = "plugins/Live/templates/images/play_disabled.gif"; + + function onClickPause() + { + $('#pauseImage').attr('src', pauseImage); + $('#playImage').attr('src', playDisabledImage); + return pauseSpy(); + } + function onClickPlay() + { + $('#playImage').attr('src', playImage); + $('#pauseImage').attr('src', pauseDisabledImage); + return playSpy(); + } + +</script> + +<style> +#visits { + text-align:left; +} +#visits .datetime, #visits .country, #visits .referer, #visits .settings, #visits .returning { + float:left; + margin-right:10px; + overflow:hidden; + padding-left:1px; + max-width:700px; +} +#visits .datetime { + width:110px; +} +#visits .country { + width:30px; +} +#visits .referer { + width:200px; +} +#visits .settings { + width:100px; +} +#visits .returning { + width:30px; +} +#visits .visit { + border-bottom:1px solid #C1DAD7; + background-color:#F9FAFA; + padding:10px; + line-height:24px; + height:40px; +} +#visits .alt { + background-color:#FFFFFF; +} +</style> +{/literal} + +{$visitors} + +<div> + <a href="#?" onclick="onClickPause();"><img id="pauseImage" border="0" src="plugins/Live/templates/images/pause_disabled.gif"></a> + <a href="#?" onclick="onClickPlay();"><img id="playImage" border="0" src="plugins/Live/templates/images/play.gif"></a> +</div> diff --git a/plugins/Live/templates/lastVisits.tpl b/plugins/Live/templates/lastVisits.tpl new file mode 100644 index 0000000000..ac515f2d63 --- /dev/null +++ b/plugins/Live/templates/lastVisits.tpl @@ -0,0 +1,15 @@ +<div id="visits"> +{foreach from=$visitors item=visitor} + <div class="visit{if $visitor.idVisit % 2} alt{/if}"> + <div style="display:none" class="idvisit">{$visitor.idVisit}</div> + <div class="datetime">{$visitor.serverDatePretty}<br/>{$visitor.serverTimePretty}</div> + <div class="country"><img src="{$visitor.countryFlag}" title="{$visitor.country}, Provider {$visitor.provider}"></div> + <div class="referer">{if $visitor.refererType != 'directEntry'}from <a href="{$visitor.refererUrl}">{$visitor.refererName}</a> {if !empty($visitor.keywords)}"{$visitor.keywords}"{/if}{/if}</div> + <div class="settings"> + <img src="{$visitor.browserIcon}" title="{$visitor.browser} with plugins {$visitor.plugins} enabled"> + <img src="{$visitor.operatingSystemIcon}" title="{$visitor.operatingSystem}, {$visitor.resolution}"> + </div> + <div class="returning">{if $visitor.isVisitorReturning}<img src="plugins/Live/templates/images/returningVisitor.gif" title="Returning Visitor">{/if}</div> + </div> +{/foreach} +</div> diff --git a/plugins/Live/templates/scripts/spy.js b/plugins/Live/templates/scripts/spy.js new file mode 100644 index 0000000000..ac296ab02f --- /dev/null +++ b/plugins/Live/templates/scripts/spy.js @@ -0,0 +1,139 @@ +/* + jQuery Plugin spy (leftlogic.com/info/articles/jquery_spy2) + (c) 2006 Remy Sharp (leftlogic.com) + $Id$ +*/ +var spyRunning = 1; + +$.fn.spy = function(settings) { + var spy = this; + spy.epoch = new Date(1970, 0, 1); + spy.last = ''; + spy.parsing = 0; + spy.waitTimer = 0; + spy.json = null; + + if (!settings.ajax) { + alert("An AJAX/AJAH URL must be set for the spy to work."); + return; + } + + spy.attachHolder = function() { + // not mad on this, but the only way to parse HTML collections + if (o.method == 'html') + $('body').append('<div style="display: none!important;" id="_spyTmp"></div>'); + } + + // returns true for 'no dupe', and false for 'dupe found' + // latest = is latest ajax return value (raw) + // last = is previous ajax return value (raw) + // note that comparing latest and last if they're JSON objects + // always returns false, so you need to implement it manually. + spy.isDupe = function(latest, last) { + if ((last.constructor == Object) && (o.method == 'html')) + return (latest.html() == last.html()); + else if (last.constructor == String) + return (latest == last); + else + return 0; + } + + spy.parse = function(e, r) { + spy.parsing = 1; // flag to stop pull via ajax + if (o.method == 'html') { + $('div#_spyTmp').html(r); // add contents to hidden div + } else if (o.method == 'json') { + eval('spy.json = ' + r); // convert text to json + } + + if ((o.method == 'json' && spy.json.constructor == Array) || o.method == 'html') { + if (spy.parseItem(e)) { + spy.waitTimer = window.setInterval(function() { + if (spyRunning) { + if (!spy.parseItem(e)) { + spy.parsing = 0; + clearInterval(spy.waitTimer); + } + } + }, o.pushTimeout); + } else { + spy.parsing = 0; + } + } else if (o.method == 'json') { // we just have 1 + eval('spy.json = ' + r) + spy.addItem(e, spy.json); + spy.parsing = 0; + } + } + + // returns true if there's more to parse + spy.parseItem = function(e) { + if (o.method == 'html') { + // note: pre jq-1.0 doesn't return the object + var i = $('div#_spyTmp').find('div:first').remove(); + if (i.size() > 0) { + i.hide(); + spy.addItem(e, i); + } + return ($('div#_spyTmp').find('div').size() != 0); + } else { + if (spy.json.length) { + var i = spy.json.shift(); + spy.addItem(e, i); + } + + return (spy.json.length != 0); + } + } + + spy.addItem = function(e, i) { + if (! o.isDupe.call(this, i, spy.last)) { + spy.last = i; // note i is a pointer - so when it gets modified, so does spy.last + $('#' + e.id + ' > div:gt(' + (o.limit - 1) + ')').remove(); + o.push.call(e, i); + $('#' + e.id + ' > div:first').fadeIn(o.fadeInSpeed); + } + } + + spy.push = function(r) { + $('#' + this.id).prepend(r); + } + + var o = { + limit: (settings.limit || 10), + ajax: settings.ajax, + timeout: (settings.timeout || 3000), + pushTimeout: (settings.pushTimeout || settings.timeout || 3000), + method: (settings.method || 'html').toLowerCase(), + push: (settings.push || spy.push), + fadeInSpeed: (settings.fadeInSpeed || 'slow'), // 1400 = crawl + customParameterName: settings.customParameterName, + customParameterValueCallback: settings.customParameterValueCallback, + isDupe: (settings.isDupe || spy.isDupe), + }; + + spy.attachHolder(); + + return this.each(function() { + var e = this; + var lr = ''; // last ajax return + var parameters = new Object; + spy.ajaxTimer = window.setInterval(function() { + if (spyRunning && (!spy.parsing)) { + var customParameterValue = o.customParameterValueCallback.call(); + parameters[o.customParameterName] = customParameterValue; + $.get(o.ajax, parameters, function(r) { + spy.parse(e, r); + }); + } + }, o.timeout); + }); +}; + +function pauseSpy() { + spyRunning = 0; return false; +} + +function playSpy() { + spyRunning = 1; return false; +} diff --git a/plugins/Login/Controller.php b/plugins/Login/Controller.php index fbee6a38e0..54557e9563 100644 --- a/plugins/Login/Controller.php +++ b/plugins/Login/Controller.php @@ -100,70 +100,97 @@ class Piwik_Login_Controller extends Piwik_Controller if($form->validate()) { $loginMail = $form->getSubmitValue('form_login'); - Piwik::setUserIsSuperUser(); - - $user = null; - - if( Piwik_UsersManager_API::userExists($loginMail) ) - { - $user = Piwik_UsersManager_API::getUser($loginMail); - } - else if( Piwik_UsersManager_API::userEmailExists($loginMail) ) - { - $user = Piwik_UsersManager_API::getUserByEmail($loginMail); - } + $this->lostPasswordFormValidated($loginMail, $urlToRedirect); + return; + } + $view = new Piwik_View('Login/templates/lostPassword.tpl'); + $view->AccessErrorString = $messageNoAccess; + // make navigation login form -> reset password -> login form remember your first url + $view->urlToRedirect = $urlToRedirect; + $view->linkTitle = Piwik::getRandomTitle(); + $view->addForm( $form ); + $view->subTemplate = 'genericForm.tpl'; + echo $view->render(); + } + + protected function lostPasswordFormValidated($loginMail, $urlToRedirect) + { + Piwik::setUserIsSuperUser(); + $user = null; + $isSuperUser = false; + + if( $loginMail == Zend_Registry::get('config')->superuser->email + || $loginMail == Zend_Registry::get('config')->superuser->login ) + { + $isSuperUser = true; + $user = array( + 'login' => Zend_Registry::get('config')->superuser->login, + 'email' => Zend_Registry::get('config')->superuser->email); + } + else if( Piwik_UsersManager_API::userExists($loginMail) ) + { + $user = Piwik_UsersManager_API::getUser($loginMail); + } + else if( Piwik_UsersManager_API::userEmailExists($loginMail) ) + { + $user = Piwik_UsersManager_API::getUserByEmail($loginMail); + } - if( $user === null ) + if( $user === null ) + { + $messageNoAccess = Piwik_Translate('Login_InvalidUsernameEmail'); + } + else + { + $view = new Piwik_View('Login/templates/passwordsent.tpl'); + + $login = $user['login']; + $email = $user['email']; + $randomPassword = Piwik_Common::getRandomString(8); + + if($isSuperUser) { - $messageNoAccess = Piwik_Translate('Login_InvalidUsernameEmail'); + $user['password'] = md5($randomPassword); + Zend_Registry::get('config')->superuser = $user; } else { - $view = new Piwik_View('Login/templates/passwordsent.tpl'); - - $login = $user['login']; - $email = $user['email']; - $randomPassword = Piwik_Common::getRandomString(8); Piwik_UsersManager_API::updateUser($login, $randomPassword); + } - // send email with new password - try - { - $mail = new Piwik_Mail(); - $mail->addTo($email, $login); - $mail->setSubject(Piwik_Translate('Login_MailTopicPasswordRecovery')); - $mail->setBodyText(sprintf(Piwik_Translate('Login_MailPasswordRecoveryBody'), - $login, $randomPassword, Piwik_Url::getCurrentUrlWithoutQueryString())); + // send email with new password + try + { + $mail = new Piwik_Mail(); + $mail->addTo($email, $login); + $mail->setSubject(Piwik_Translate('Login_MailTopicPasswordRecovery')); + $mail->setBodyText( + str_replace( + '\n', + "\n", + sprintf(Piwik_Translate('Login_MailPasswordRecoveryBody'), $login, $randomPassword, Piwik_Url::getCurrentUrlWithoutQueryString()) + ) + ); - $host = $_SERVER['HTTP_HOST']; - if(strlen($host) == 0) - { - $host = 'piwik.org'; - } - $mail->setFrom('password-recovery@'.$host, 'Piwik'); - @$mail->send(); - } - catch(Exception $e) + $host = $_SERVER['HTTP_HOST']; + if(strlen($host) == 0) { - $view->ErrorString = $e->getMessage(); + $host = 'piwik.org'; } - - $view->linkTitle = Piwik::getRandomTitle(); - $view->urlToRedirect = $urlToRedirect; - echo $view->render(); - return; + $mail->setFrom('password-recovery@'.$host, 'Piwik'); + @$mail->send(); + } + catch(Exception $e) + { + $view->ErrorString = $e->getMessage(); } + + $view->linkTitle = Piwik::getRandomTitle(); + $view->urlToRedirect = $urlToRedirect; + echo $view->render(); } - $view = new Piwik_View('Login/templates/lostPassword.tpl'); - $view->AccessErrorString = $messageNoAccess; - // make navigation login form -> reset password -> login form remember your first url - $view->urlToRedirect = $urlToRedirect; - $view->linkTitle = Piwik::getRandomTitle(); - $view->addForm( $form ); - $view->subTemplate = 'genericForm.tpl'; - echo $view->render(); } - + static public function clearSession() { $authCookieName = 'piwik-auth'; diff --git a/plugins/Login/templates/login.tpl b/plugins/Login/templates/login.tpl index 4b3ef37de9..0484425181 100644 --- a/plugins/Login/templates/login.tpl +++ b/plugins/Login/templates/login.tpl @@ -35,7 +35,7 @@ <p id="nav">
-<a href="?module=Login&action=lostPassword&form_url={$urlToRedirect}" title="{'Login_LostYourPassword'|translate}">{'Login_LostYourPassword'|translate}</a>
+<a href="?module=Login&action=lostPassword&form_url={$urlToRedirect|escape:url}" title="{'Login_LostYourPassword'|translate}">{'Login_LostYourPassword'|translate}</a>
</p>
</div>
diff --git a/plugins/Provider/API.php b/plugins/Provider/API.php index 7f7c83f569..074ca64994 100644 --- a/plugins/Provider/API.php +++ b/plugins/Provider/API.php @@ -14,7 +14,7 @@ require_once "Provider/functions.php"; * * @package Piwik_Provider */ -class Piwik_Provider_API extends Piwik_Apiable +class Piwik_Provider_API { static private $instance = null; @@ -38,18 +38,5 @@ class Piwik_Provider_API extends Piwik_Apiable $dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames'); return $dataTable; } - - /** - * Example of getting a RAW BLOB - * - * @return blob - */ - public function getProviderBlob( $idSite, $period, $date ) - { - Piwik::checkUserHasViewAccess( $idSite ); - $archive = Piwik_Archive::build($idSite, $period, $date ); - $dataTable = $archive->getBlob('Provider_hostnameExt'); - return $dataTable; - } } diff --git a/plugins/Provider/Controller.php b/plugins/Provider/Controller.php index cc08f0b3e9..90d9674cc3 100644 --- a/plugins/Provider/Controller.php +++ b/plugins/Provider/Controller.php @@ -1,6 +1,4 @@ <?php -require_once "ViewDataTable.php"; - class Piwik_Provider_Controller extends Piwik_Controller { /** @@ -9,12 +7,10 @@ class Piwik_Provider_Controller extends Piwik_Controller function getProvider($fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( 'Provider', __FUNCTION__, "Provider.getProvider" ); - + $view->init( $this->pluginName, __FUNCTION__, "Provider.getProvider" ); $view->setColumnsToDisplay( array('label','nb_uniq_visitors') ); $view->setSortedColumn( 1 ); $view->setLimit( 5 ); - return $this->renderView($view, $fetch); } diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php index a819797c31..0de4d5b8f8 100644 --- a/plugins/Provider/Provider.php +++ b/plugins/Provider/Provider.php @@ -97,7 +97,8 @@ class Piwik_Provider extends Piwik_Plugin $recordName = 'Provider_hostnameExt'; $labelSQL = "location_provider"; - $tableProvider = $archiveProcessing->getDataTableInterestForLabel($labelSQL); + $interestByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableProvider = $archiveProcessing->getDataTableFromArray($interestByProvider); $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableProvider->getSerialized()); } diff --git a/plugins/Referers/API.php b/plugins/Referers/API.php index 8a5b8b5bca..ab60cc8c83 100644 --- a/plugins/Referers/API.php +++ b/plugins/Referers/API.php @@ -15,7 +15,7 @@ require_once "Referers/functions.php"; * * @package Piwik_Referers */ -class Piwik_Referers_API extends Piwik_Apiable +class Piwik_Referers_API { static private $instance = null; static public function getInstance() @@ -56,10 +56,10 @@ class Piwik_Referers_API extends Piwik_Apiable $dataTable->queueFilter('Piwik_DataTable_Filter_ColumnCallbackReplace', array('label', 'Piwik_getRefererTypeLabel')); return $dataTable; } - + function getKeywords($idSite, $period, $date, $expanded = false) { - $dataTable = $this->getDataTable('Referers_searchEngineByKeyword',$idSite, $period, $date, $expanded); + $dataTable = $this->getDataTable('Referers_searchEngineByKeyword', $idSite, $period, $date, $expanded); return $dataTable; } diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php index c76d596b19..c064e8b83e 100644 --- a/plugins/Referers/Controller.php +++ b/plugins/Referers/Controller.php @@ -1,10 +1,9 @@ <?php -require_once "ViewDataTable.php"; class Piwik_Referers_Controller extends Piwik_Controller { function index() { - $view = new Piwik_View('Referers/index.tpl'); + $view = new Piwik_View('Referers/templates/index.tpl'); $view->graphEvolutionReferers = $this->getLastDirectEntryGraph(true); $view->nameGraphEvolutionReferers = 'ReferersgetLastDirectEntryGraph'; // must be the function name used above @@ -40,25 +39,24 @@ class Piwik_Referers_Controller extends Piwik_Controller function getSearchEnginesAndKeywords() { - $view = new Piwik_View('Referers/searchEngines_Keywords.tpl'); + $view = new Piwik_View('Referers/templates/searchEngines_Keywords.tpl'); $view->searchEngines = $this->getSearchEngines(true) ; $view->keywords = $this->getKeywords(true); echo $view->render(); } - /** - * Referers - */ + function getRefererType( $fetch = false) { $view = Piwik_ViewDataTable::factory('cloud'); $view->init( $this->pluginName, - 'getRefererType', + __FUNCTION__, 'Referers.getRefererType' ); $view->disableSearchBox(); $view->disableOffsetInformation(); $view->disableExcludeLowPopulation(); $view->doNotShowFooter(); + $view->enableShowGoals(); $view->setColumnsToDisplay( array('label','nb_uniq_visitors', 'nb_visits') ); @@ -68,21 +66,21 @@ class Piwik_Referers_Controller extends Piwik_Controller function getKeywords( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - - $view->init( $this->pluginName, 'getKeywords', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getKeywords', 'getSearchEnginesFromKeywordId' ); $view->disableExcludeLowPopulation(); $view->setColumnsToDisplay( array('label','nb_visits') ); - + $view->enableShowGoals(); + $view->disableSubTableWhenShowGoals(); return $this->renderView($view, $fetch); } function getSearchEnginesFromKeywordId( $fetch = false ) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getSearchEnginesFromKeywordId', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getSearchEnginesFromKeywordId' ); $view->disableSearchBox(); @@ -96,34 +94,36 @@ class Piwik_Referers_Controller extends Piwik_Controller function getSearchEngines( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getSearchEngines', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getSearchEngines', 'getKeywordsFromSearchEngineId' ); $view->disableSearchBox(); $view->disableExcludeLowPopulation(); + $view->enableShowGoals(); + $view->disableSubTableWhenShowGoals(); $view->setColumnsToDisplay( array('label','nb_visits') ); return $this->renderView($view, $fetch); } - public function getSearchEnginesEvolution($fetch = false)
- {
- $view = Piwik_ViewDataTable::factory('graphEvolution');
- $view->init( 'Referers', __FUNCTION__, 'Referers.getSearchEngines' );
-
- $view->setColumnsToDisplay( 'nb_uniq_visitors' );
- $view->setExactPattern( array('Google','Yahoo!'), 'label');
- //$view->setExactPattern( array('Google'), 'label');
-
- return $this->renderView($view, $fetch);
- }
+ public function getSearchEnginesEvolution($fetch = false) + { + $view = Piwik_ViewDataTable::factory('graphEvolution'); + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getSearchEngines' ); + + $view->setColumnsToDisplay( 'nb_uniq_visitors' ); + $view->setExactPattern( array('Google','Yahoo!'), 'label'); + //$view->setExactPattern( array('Google'), 'label'); + + return $this->renderView($view, $fetch); + } function getKeywordsFromSearchEngineId( $fetch = false ) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getKeywordsFromSearchEngineId', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getKeywordsFromSearchEngineId' ); $view->disableSearchBox(); @@ -136,20 +136,23 @@ class Piwik_Referers_Controller extends Piwik_Controller function getWebsites( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getWebsites', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getWebsites', 'getUrlsFromWebsiteId' ); $view->disableExcludeLowPopulation(); $view->setColumnsToDisplay( array('label','nb_visits') ); $view->setLimit(10); + $view->enableShowGoals(); + $view->disableSubTableWhenShowGoals(); + return $this->renderView($view, $fetch); } function getCampaigns( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getCampaigns', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getCampaigns', 'getKeywordsFromCampaignId' ); @@ -157,16 +160,15 @@ class Piwik_Referers_Controller extends Piwik_Controller $view->disableSearchBox(); $view->disableExcludeLowPopulation(); $view->setLimit( 5 ); - + $view->enableShowGoals(); $view->setColumnsToDisplay( array('label','nb_visits') ); - return $this->renderView($view, $fetch); } function getKeywordsFromCampaignId( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getKeywordsFromCampaignId', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getKeywordsFromCampaignId' ); @@ -180,7 +182,7 @@ class Piwik_Referers_Controller extends Piwik_Controller function getUrlsFromWebsiteId( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( $this->pluginName, 'getUrlsFromWebsiteId', + $view->init( $this->pluginName, __FUNCTION__, 'Referers.getUrlsFromWebsiteId' ); $view->disableSearchBox(); @@ -189,7 +191,7 @@ class Piwik_Referers_Controller extends Piwik_Controller return $this->renderView($view, $fetch); } - function getReferersType() + protected function getReferersVisitorsByType() { // we disable the queued filters because here we want to get the visits coming from search engines // if the filters were applied we would have to look up for a label looking like "Search Engines" @@ -198,13 +200,7 @@ class Piwik_Referers_Controller extends Piwik_Controller &format=original &disable_queued_filters=1"; $request = new Piwik_API_Request($requestString); - return $request->process(); - } - - protected function getReferersVisitorsByType() - { - // this is raw data (no filters applied, on purpose) so we select the data using the magic integers ID - $dataTableReferersType = $this->getReferersType(true); + $dataTableReferersType = $request->process(); $nameToColumnId = array( 'visitorsFromSearchEngines' => Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php index fe23422512..339a75f73f 100644 --- a/plugins/Referers/Referers.php +++ b/plugins/Referers/Referers.php @@ -122,10 +122,22 @@ class Piwik_Referers extends Piwik_Plugin ); } } - + + public function archiveDay( $notification ) { + /** + * @var Piwik_ArchiveProcessing_Day + */ $archiveProcessing = $notification->getNotificationObject(); + + $this->archiveDayAggregateVisits($archiveProcessing); + $this->archiveDayAggregateGoals($archiveProcessing); + $this->archiveDayRecordInDatabase($archiveProcessing); + } + + protected function archiveDayAggregateVisits($archiveProcessing) + { $query = "SELECT referer_type, referer_name, referer_keyword, @@ -135,7 +147,8 @@ class Piwik_Referers extends Piwik_Plugin sum(visit_total_actions) as nb_actions, max(visit_total_actions) as max_actions, sum(visit_total_time) as sum_visit_length, - sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count + sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count, + sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted FROM ".$archiveProcessing->logTable." WHERE visit_server_date = ? AND idsite = ? @@ -143,111 +156,164 @@ class Piwik_Referers extends Piwik_Plugin ORDER BY nb_visits DESC"; $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); - $interestBySearchEngine = - $interestByKeyword = - $keywordBySearchEngine = - $searchEngineByKeyword = - $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] = - $urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] = - $keywordByCampaign = - $interestByCampaign = - $interestByType = - $distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE] = array(); + $this->interestBySearchEngine = + $this->interestByKeyword = + $this->interestBySearchEngineAndKeyword = + $this->interestByKeywordAndSearchEngine = + $this->interestByWebsite = + $this->interestByWebsiteAndUrl = + $this->interestByCampaignAndKeyword = + $this->interestByCampaign = + $this->interestByType = + $this->distinctUrls = array(); - while($rowBefore = $query->fetch() ) + while($row = $query->fetch() ) { - $row = array( - Piwik_Archive::INDEX_NB_UNIQ_VISITORS => $rowBefore['nb_uniq_visitors'], - Piwik_Archive::INDEX_NB_VISITS => $rowBefore['nb_visits'], - Piwik_Archive::INDEX_NB_ACTIONS => $rowBefore['nb_actions'], - Piwik_Archive::INDEX_MAX_ACTIONS => $rowBefore['max_actions'], - Piwik_Archive::INDEX_SUM_VISIT_LENGTH => $rowBefore['sum_visit_length'], - Piwik_Archive::INDEX_BOUNCE_COUNT => $rowBefore['bounce_count'], - 'referer_type' => $rowBefore['referer_type'], - 'referer_name' => $rowBefore['referer_name'], - 'referer_keyword' => $rowBefore['referer_keyword'], - 'referer_url' => $rowBefore['referer_url'], - ); - - switch($row['referer_type']) + if(empty($row['referer_type'])) { - case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: - - if(!isset($interestBySearchEngine[$row['referer_name']])) $interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow(); - if(!isset($interestByKeyword[$row['referer_keyword']])) $interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); - if(!isset($keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']])) $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); - if(!isset($searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']])) $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow(); - - $archiveProcessing->updateInterestStats( $row, $interestBySearchEngine[$row['referer_name']]); - $archiveProcessing->updateInterestStats( $row, $interestByKeyword[$row['referer_keyword']]); - $archiveProcessing->updateInterestStats( $row, $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]); - $archiveProcessing->updateInterestStats( $row, $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]); - break; - - case Piwik_Common::REFERER_TYPE_WEBSITE: + $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY; + } + else + { + switch($row['referer_type']) + { + case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: - if(!isset($interestByWebsite[$row['referer_type']][$row['referer_name']])) $interestByWebsite[$row['referer_type']][$row['referer_name']]= $archiveProcessing->getNewInterestRow(); - $archiveProcessing->updateInterestStats( $row, $interestByWebsite[$row['referer_type']][$row['referer_name']]); + if(!isset($this->interestBySearchEngine[$row['referer_name']])) $this->interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow(); + if(!isset($this->interestByKeyword[$row['referer_keyword']])) $this->interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); + if(!isset($this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); + if(!isset($this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']])) $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow(); - if(!isset($urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']])) $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow(); - $archiveProcessing->updateInterestStats( $row, $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]); - - if(!isset($distinctUrls[$row['referer_type']][$row['referer_url']])) - { - $distinctUrls[$row['referer_type']][$row['referer_url']] = true; - } + $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngine[$row['referer_name']]); + $archiveProcessing->updateInterestStats( $row, $this->interestByKeyword[$row['referer_keyword']]); + $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]); + $archiveProcessing->updateInterestStats( $row, $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]); + break; + + case Piwik_Common::REFERER_TYPE_WEBSITE: + + if(!isset($this->interestByWebsite[$row['referer_name']])) $this->interestByWebsite[$row['referer_name']]= $archiveProcessing->getNewInterestRow(); + $archiveProcessing->updateInterestStats( $row, $this->interestByWebsite[$row['referer_name']]); + + if(!isset($this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']])) $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow(); + $archiveProcessing->updateInterestStats( $row, $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]); - break; + if(!isset($this->distinctUrls[$row['referer_url']])) + { + $this->distinctUrls[$row['referer_url']] = true; + } + + break; + + case Piwik_Common::REFERER_TYPE_CAMPAIGN: + if(!empty($row['referer_keyword'])) + { + if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); + $archiveProcessing->updateInterestStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]); + } + if(!isset($this->interestByCampaign[$row['referer_name']])) $this->interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow(); + $archiveProcessing->updateInterestStats( $row, $this->interestByCampaign[$row['referer_name']]); + break; + + case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY: + // direct entry are aggregated below in $this->interestByType array + break; + + default: + throw new Exception("Non expected referer_type = " . $row['referer_type']); + break; + } + } + if(!isset($this->interestByType[$row['referer_type']] )) $this->interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow(); + $archiveProcessing->updateInterestStats($row, $this->interestByType[$row['referer_type']]); + } + } + + protected function archiveDayAggregateGoals($archiveProcessing) + { + $query = $archiveProcessing->queryConversionsBySegment("referer_type,referer_name,referer_keyword"); + while($row = $query->fetch() ) + { + if(empty($row['referer_type'])) + { + $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY; + } + else + { + switch($row['referer_type']) + { + case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: + if(!isset($this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + if(!isset($this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + + $archiveProcessing->updateGoalStats( $row, $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + $archiveProcessing->updateGoalStats( $row, $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + break; + + case Piwik_Common::REFERER_TYPE_WEBSITE: + if(!isset($this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats( $row, $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + break; + + case Piwik_Common::REFERER_TYPE_CAMPAIGN: + if(!empty($row['referer_keyword'])) + { + if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + if(!isset($this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats( $row, $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + break; - case Piwik_Common::REFERER_TYPE_CAMPAIGN: - if(!empty($row['referer_keyword'])) - { - if(!isset($keywordByCampaign[$row['referer_name']][$row['referer_keyword']])) $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow(); - $archiveProcessing->updateInterestStats( $row, $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]); - } - if(!isset($interestByCampaign[$row['referer_name']])) $interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow(); - $archiveProcessing->updateInterestStats( $row, $interestByCampaign[$row['referer_name']]); - break; + default: + throw new Exception("Non expected referer_type = " . $row['referer_type']); + break; + } } - if(!isset($interestByType[$row['referer_type']] )) $interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow(); - $archiveProcessing->updateInterestStats($row, $interestByType[$row['referer_type']]); + if(!isset($this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] )) $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats($row, $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); } - - $numberOfDistinctSearchEngines = count($keywordBySearchEngine); - $numberOfDistinctKeywords = count($searchEngineByKeyword); - - $numberOfDistinctCampaigns = count($interestByCampaign); - $numberOfDistinctWebsites = count($interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE]); - $numberOfDistinctWebsitesUrls = count($distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE]); - + + $archiveProcessing->enrichConversionsByLabelArray($this->interestByType); + $archiveProcessing->enrichConversionsByLabelArray($this->interestBySearchEngine); + $archiveProcessing->enrichConversionsByLabelArray($this->interestByKeyword); + $archiveProcessing->enrichConversionsByLabelArray($this->interestByWebsite); + $archiveProcessing->enrichConversionsByLabelArray($this->interestByCampaign); + $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->interestByCampaignAndKeyword); + } + + protected function archiveDayRecordInDatabase($archiveProcessing) + { $numericRecords = array( - 'Referers_distinctSearchEngines' => $numberOfDistinctSearchEngines, - 'Referers_distinctKeywords' => $numberOfDistinctKeywords, - 'Referers_distinctCampaigns' => $numberOfDistinctCampaigns, - 'Referers_distinctWebsites' => $numberOfDistinctWebsites, - 'Referers_distinctWebsitesUrls' => $numberOfDistinctWebsitesUrls, + 'Referers_distinctSearchEngines' => count($this->interestBySearchEngineAndKeyword), + 'Referers_distinctKeywords' => count($this->interestByKeywordAndSearchEngine), + 'Referers_distinctCampaigns' => count($this->interestByCampaign), + 'Referers_distinctWebsites' => count($this->interestByWebsite), + 'Referers_distinctWebsitesUrls' => count($this->distinctUrls), ); + foreach($numericRecords as $name => $value) { $record = new Piwik_ArchiveProcessing_Record_Numeric($name, $value); } - $data = $archiveProcessing->getDataTableSerialized($interestByType); + $data = $archiveProcessing->getDataTableSerialized($this->interestByType); $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_type', $data); $maximumRowsInDataTableLevelZero = 500; $maximumRowsInSubDataTable = 50; - $data = $archiveProcessing->getDataTablesSerialized($keywordBySearchEngine, $interestBySearchEngine, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); - $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordBySearchEngine', $data); - - $data = $archiveProcessing->getDataTablesSerialized($searchEngineByKeyword, $interestByKeyword, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); - $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_searchEngineByKeyword', $data); - - $data = $archiveProcessing->getDataTablesSerialized($keywordByCampaign, $interestByCampaign, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); - $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordByCampaign', $data); + $blobRecords = array( + 'Referers_keywordBySearchEngine' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestBySearchEngineAndKeyword, $this->interestBySearchEngine), + 'Referers_searchEngineByKeyword' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByKeywordAndSearchEngine, $this->interestByKeyword), + 'Referers_keywordByCampaign' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByCampaignAndKeyword, $this->interestByCampaign), + 'Referers_urlByWebsite' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByWebsiteAndUrl, $this->interestByWebsite), + ); - $data = $archiveProcessing->getDataTablesSerialized($urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); - $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_urlByWebsite', $data); + foreach($blobRecords as $recordName => $table ) + { + $dataToRecord = $table->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable); + $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $dataToRecord); + } } } diff --git a/plugins/Referers/functions.php b/plugins/Referers/functions.php index 9df808e0b1..735e7865e1 100644 --- a/plugins/Referers/functions.php +++ b/plugins/Referers/functions.php @@ -63,4 +63,5 @@ function Piwik_getRefererTypeLabel($label) break; } return Piwik_Translate($indexTranslation); -}
\ No newline at end of file +} + diff --git a/plugins/Referers/index.tpl b/plugins/Referers/templates/index.tpl index df1995c81e..df1995c81e 100644 --- a/plugins/Referers/index.tpl +++ b/plugins/Referers/templates/index.tpl diff --git a/plugins/Referers/searchEngines_Keywords.tpl b/plugins/Referers/templates/searchEngines_Keywords.tpl index a664aefb50..a664aefb50 100644 --- a/plugins/Referers/searchEngines_Keywords.tpl +++ b/plugins/Referers/templates/searchEngines_Keywords.tpl diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index cfd4e8b0c7..6ff1ff9a8b 100755 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -13,7 +13,7 @@ * * @package Piwik_SitesManager */ -class Piwik_SitesManager_API extends Piwik_Apiable +class Piwik_SitesManager_API { static private $instance = null; static public function getInstance() @@ -26,8 +26,6 @@ class Piwik_SitesManager_API extends Piwik_Apiable return self::$instance; } - static public $methodsNotToPublish = array(); - /** * Returns the javascript tag for the given idSite. * This tag must be included on every page to be tracked by Piwik diff --git a/plugins/SitesManager/templates/SitesManager.js b/plugins/SitesManager/templates/SitesManager.js index df6b3ed9f1..8ebfedd3b3 100644 --- a/plugins/SitesManager/templates/SitesManager.js +++ b/plugins/SitesManager/templates/SitesManager.js @@ -1,15 +1,3 @@ - -function getEncoded(siteName) -{ - // compatible with old browsers but wouldnt work for UTF8 strings - if (encodeURIComponent) { - siteName = encodeURIComponent(siteName); - } else { - siteName = escape(siteName); - } - return siteName; -} - function getDeleteSiteAJAX( idSite ) { var ajaxRequest = getStandardAjaxConf(); @@ -41,7 +29,7 @@ function getAddSiteAJAX( row ) request += '&module=API'; request += '&format=json'; request += '&method=SitesManager.addSite'; - siteName = getEncoded(siteName); + siteName = encodeURIComponent(siteName); request += '&siteName='+siteName; $.each(urls, function (key,value){ request+= '&urls[]='+escape(value);} ); request += '&token_auth=' + piwik.token_auth; @@ -64,7 +52,7 @@ function getUpdateSiteAJAX( row ) request += '&module=API'; request += '&format=json'; request += '&method=SitesManager.updateSite'; - siteName = getEncoded(siteName); + siteName = encodeURIComponent(siteName); request += '&siteName='+siteName; request += '&idSite='+idSite; $.each(urls, function (key,value){ if(value.length>1) request+= '&urls[]='+value;} ); diff --git a/plugins/UserCountry/API.php b/plugins/UserCountry/API.php index 404dc0cbc4..6c6f00c857 100644 --- a/plugins/UserCountry/API.php +++ b/plugins/UserCountry/API.php @@ -15,7 +15,7 @@ require_once "UserCountry/functions.php"; * * @package Piwik_UserCountry */ -class Piwik_UserCountry_API extends Piwik_Apiable +class Piwik_UserCountry_API { static private $instance = null; static public function getInstance() diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php index 29e7f56b07..a2395620f8 100644 --- a/plugins/UserCountry/Controller.php +++ b/plugins/UserCountry/Controller.php @@ -19,39 +19,41 @@ class Piwik_UserCountry_Controller extends Piwik_Controller function getCountry( $fetch = false) { $view = Piwik_ViewDataTable::factory(); - $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getCountry" ); + $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getCountry" ); $view->disableExcludeLowPopulation(); $view->setColumnsToDisplay( array('label','nb_uniq_visitors') ); $view->setSortedColumn( 1 ); $view->disableSearchBox(); $view->setLimit( 5 ); + $view->enableShowGoals(); return $this->renderView($view, $fetch); } - function getNumberOfDistinctCountries( $fetch = false) - { - return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries'); - } - - function getLastDistinctCountriesGraph( $fetch = false ) - { - $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries"); - return $this->renderView($view, $fetch); - } - function getContinent( $fetch = false) { $view = Piwik_ViewDataTable::factory( 'graphVerticalBar' ); - $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getContinent" ); + $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getContinent" ); $view->disableExcludeLowPopulation(); $view->disableSearchBox(); $view->disableOffsetInformation(); $view->disableSort(); $view->setColumnsToDisplay( array('label','nb_uniq_visitors') ); $view->setSortedColumn( 1 ); + $view->enableShowGoals(); return $this->renderView($view, $fetch); } + + function getNumberOfDistinctCountries( $fetch = false) + { + return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries'); + } + + function getLastDistinctCountriesGraph( $fetch = false ) + { + $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries"); + return $this->renderView($view, $fetch); + } } diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php index bd69f64067..93a052ca1e 100644 --- a/plugins/UserCountry/UserCountry.php +++ b/plugins/UserCountry/UserCountry.php @@ -68,17 +68,42 @@ class Piwik_UserCountry extends Piwik_Plugin function archiveDay($notification) { $archiveProcessing = $notification->getNotificationObject(); - - $recordName = 'UserCountry_country'; + $this->archiveDayAggregateVisits($archiveProcessing); + $this->archiveDayAggregateGoals($archiveProcessing); + $this->archiveDayRecordInDatabase($archiveProcessing); + } + + protected function archiveDayAggregateVisits($archiveProcessing) + { $labelSQL = "location_country"; - $tableCountry = $archiveProcessing->getDataTableInterestForLabel($labelSQL); - $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount()); - $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableCountry->getSerialized()); - - $recordName = 'UserCountry_continent'; + $this->interestByCountry = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $labelSQL = "location_continent"; - $tableContinent = $archiveProcessing->getDataTableInterestForLabel($labelSQL); - $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableContinent->getSerialized()); + $this->interestByContinent = $archiveProcessing->getArrayInterestForLabel($labelSQL); + } + + protected function archiveDayAggregateGoals($archiveProcessing) + { + $query = $archiveProcessing->queryConversionsBySegment("location_continent,location_country"); + while($row = $query->fetch() ) + { + if(!isset($this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + if(!isset($this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow(); + $archiveProcessing->updateGoalStats($row, $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + $archiveProcessing->updateGoalStats($row, $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + $archiveProcessing->enrichConversionsByLabelArray($this->interestByCountry); + $archiveProcessing->enrichConversionsByLabelArray($this->interestByContinent); + } + + protected function archiveDayRecordInDatabase($archiveProcessing) + { + $tableCountry = $archiveProcessing->getDataTableFromArray($this->interestByCountry); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_country', $tableCountry->getSerialized()); + $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount()); + + $tableContinent = $archiveProcessing->getDataTableFromArray($this->interestByContinent); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_continent', $tableContinent->getSerialized()); } } diff --git a/plugins/UserSettings/API.php b/plugins/UserSettings/API.php index c31f941ced..d283c83870 100644 --- a/plugins/UserSettings/API.php +++ b/plugins/UserSettings/API.php @@ -16,7 +16,7 @@ require_once "UserSettings/functions.php"; /** * @package Piwik_UserSettings */ -class Piwik_UserSettings_API extends Piwik_Apiable +class Piwik_UserSettings_API { static private $instance = null; static public function getInstance() diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php index 6b0895145f..b56ed2d8b2 100644 --- a/plugins/UserSettings/UserSettings.php +++ b/plugins/UserSettings/UserSettings.php @@ -30,8 +30,8 @@ class Piwik_UserSettings extends Piwik_Plugin // source: http://en.wikipedia.org/wiki/List_of_web_browsers static public $browserType = array( "ie" => array("IE"), - "gecko" => array("NS", "PX", "FF", "FB", "CA", "CH", "GA", "KM", "MO", "SM"), - "khtml" => array("SF", "KO", "OW"), + "gecko" => array("NS", "PX", "FF", "FB", "CA", "GA", "KM", "MO", "SM"), + "khtml" => array("SF", "KO", "OW", "CH"), "opera" => array("OP") ); @@ -78,17 +78,20 @@ class Piwik_UserSettings extends Piwik_Plugin $recordName = 'UserSettings_configuration'; $labelSQL = "CONCAT(config_os, ';', config_browser_name, ';', config_resolution)"; - $tableConfiguration = $archiveProcessing->getDataTableInterestForLabel($labelSQL); + $interestByConfiguration = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableConfiguration = $archiveProcessing->getDataTableFromArray($interestByConfiguration); $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableConfiguration->getSerialized()); $recordName = 'UserSettings_os'; $labelSQL = "config_os"; - $tableOs = $archiveProcessing->getDataTableInterestForLabel($labelSQL); + $interestByOs = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableOs = $archiveProcessing->getDataTableFromArray($interestByOs); $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableOs->getSerialized()); $recordName = 'UserSettings_browser'; $labelSQL = "CONCAT(config_browser_name, ';', config_browser_version)"; - $tableBrowser = $archiveProcessing->getDataTableInterestForLabel($labelSQL); + $interestByBrowser = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableBrowser = $archiveProcessing->getDataTableFromArray($interestByBrowser); $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableBrowser->getSerialized()); $recordName = 'UserSettings_browserType'; @@ -97,7 +100,8 @@ class Piwik_UserSettings extends Piwik_Plugin $recordName = 'UserSettings_resolution'; $labelSQL = "config_resolution"; - $tableResolution = $archiveProcessing->getDataTableInterestForLabel($labelSQL); + $interestByResolution = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableResolution = $archiveProcessing->getDataTableFromArray($interestByResolution); $filter = new Piwik_DataTable_Filter_ColumnCallbackDeleteRow($tableResolution, 'label', 'Piwik_UserSettings_keepStrlenGreater'); $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableResolution->getSerialized()); diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php index 46024d1295..235562c11c 100755 --- a/plugins/UsersManager/API.php +++ b/plugins/UsersManager/API.php @@ -13,7 +13,7 @@ * * @package Piwik_UsersManager */ -class Piwik_UsersManager_API extends Piwik_Apiable +class Piwik_UsersManager_API { static private $instance = null; static public function getInstance() @@ -26,8 +26,6 @@ class Piwik_UsersManager_API extends Piwik_Apiable return self::$instance; } - static public $methodsNotToPublish = array(); - /** * Returns the list of all the users * diff --git a/plugins/UsersManager/templates/UsersManager.js b/plugins/UsersManager/templates/UsersManager.js index a4e772ab97..966ea73ea5 100644 --- a/plugins/UsersManager/templates/UsersManager.js +++ b/plugins/UsersManager/templates/UsersManager.js @@ -185,7 +185,7 @@ $(document).ready( function() { .toggle() .parent() .prepend( $('<img src="plugins/UsersManager/images/ok.png" class="updateuser">') - .click( function(){ $.ajax( getUpdateUserAJAX( $('tr#'+idRow) ) ); } ) + .click( function(){ $.ajax( getUpdateUserAJAX( $('tr#'+idRow) ) ); } ) ); }); diff --git a/plugins/VisitFrequency/API.php b/plugins/VisitFrequency/API.php index c1e92bcc01..70e6010a02 100644 --- a/plugins/VisitFrequency/API.php +++ b/plugins/VisitFrequency/API.php @@ -13,7 +13,7 @@ * * @package Piwik_VisitFrequency */ -class Piwik_VisitFrequency_API extends Piwik_Apiable +class Piwik_VisitFrequency_API { static private $instance = null; static public function getInstance() @@ -36,6 +36,7 @@ class Piwik_VisitFrequency_API extends Piwik_Apiable 'max_actions_returning', 'sum_visit_length_returning', 'bounce_count_returning', + 'nb_visits_converted_returning', ); $dataTable = $archive->getDataTableFromNumeric($toFetch); return $dataTable; @@ -73,4 +74,9 @@ class Piwik_VisitFrequency_API extends Piwik_Apiable { return $this->getNumeric( $idSite, $period, $date, 'bounce_count_returning'); } + + public function getConvertedVisitsReturning( $idSite, $period, $date ) + { + return $this->getNumeric( $idSite, $period, $date, 'nb_visits_converted_returning'); + } } diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php index c3ce1a01bb..366ed17ab4 100644 --- a/plugins/VisitFrequency/Controller.php +++ b/plugins/VisitFrequency/Controller.php @@ -37,8 +37,7 @@ class Piwik_VisitFrequency_Controller extends Piwik_Controller protected function getSummary() { - $requestString = "method=VisitFrequency.getSummary - &format=original"; + $requestString = "method=VisitFrequency.getSummary&format=original"; $request = new Piwik_API_Request($requestString); return $request->process(); } diff --git a/plugins/VisitFrequency/VisitFrequency.php b/plugins/VisitFrequency/VisitFrequency.php index 94aa1329d9..68bb7fb02a 100644 --- a/plugins/VisitFrequency/VisitFrequency.php +++ b/plugins/VisitFrequency/VisitFrequency.php @@ -58,6 +58,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin 'nb_actions_returning', 'sum_visit_length_returning', 'bounce_count_returning', + 'nb_visits_converted_returning', ); $archiveProcessing->archiveNumericValuesSum($numericToSum); $archiveProcessing->archiveNumericValuesMax('max_actions_returning'); @@ -72,7 +73,8 @@ class Piwik_VisitFrequency extends Piwik_Plugin sum(visit_total_actions) as nb_actions_returning, max(visit_total_actions) as max_actions_returning, sum(visit_total_time) as sum_visit_length_returning, - sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning + sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning, + sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted_returning FROM ".$archiveProcessing->logTable." WHERE visit_server_date = ? AND idsite = ? @@ -87,6 +89,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin $row['max_actions_returning'] = 0; $row['sum_visit_length_returning'] = 0; $row['bounce_count_returning'] = 0; + $row['nb_visits_converted_returning'] = 0; } foreach($row as $name => $value) diff --git a/plugins/VisitTime/API.php b/plugins/VisitTime/API.php index 86fe3d6224..47dc678216 100644 --- a/plugins/VisitTime/API.php +++ b/plugins/VisitTime/API.php @@ -14,7 +14,7 @@ * * @package Piwik_VisitTime */ -class Piwik_VisitTime_API extends Piwik_Apiable +class Piwik_VisitTime_API { static private $instance = null; static public function getInstance() diff --git a/plugins/VisitTime/Controller.php b/plugins/VisitTime/Controller.php index d08458a706..923c406a1e 100644 --- a/plugins/VisitTime/Controller.php +++ b/plugins/VisitTime/Controller.php @@ -23,6 +23,7 @@ class Piwik_VisitTime_Controller extends Piwik_Controller $view->disableSearchBox(); $view->disableExcludeLowPopulation(); $view->disableOffsetInformation(); + $view->enableShowGoals(); return $this->renderView($view, $fetch); } diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php index 0160b838c4..9ee7f006d9 100644 --- a/plugins/VisitTime/VisitTime.php +++ b/plugins/VisitTime/VisitTime.php @@ -52,41 +52,58 @@ class Piwik_VisitTime extends Piwik_Plugin function archivePeriod( $notification ) { $archiveProcessing = $notification->getNotificationObject(); - $dataTableToSum = array( 'VisitTime_localTime', 'VisitTime_serverTime', ); - $archiveProcessing->archiveDataTable($dataTableToSum); } public function archiveDay( $notification ) { $archiveProcessing = $notification->getNotificationObject(); - - $this->archiveProcessing = $archiveProcessing; - - $recordName = 'VisitTime_localTime'; + $this->archiveDayAggregateVisits($archiveProcessing); + $this->archiveDayAggregateGoals($archiveProcessing); + $this->archiveDayRecordInDatabase($archiveProcessing); + } + + protected function archiveDayAggregateVisits($archiveProcessing) + { $labelSQL = "HOUR(visitor_localtime)"; - $tableLocalTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL); - $this->makeSureAllHoursAreSet($tableLocalTime); - $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableLocalTime->getSerialized()); + $this->interestByLocalTime = $archiveProcessing->getArrayInterestForLabel($labelSQL); - $recordName = 'VisitTime_serverTime'; $labelSQL = "HOUR(visit_first_action_time)"; - $tableServerTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL); - $this->makeSureAllHoursAreSet($tableServerTime); - $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableServerTime->getSerialized()); + $this->interestByServerTime = $archiveProcessing->getArrayInterestForLabel($labelSQL); + } + + protected function archiveDayAggregateGoals($archiveProcessing) + { + $query = $archiveProcessing->queryConversionsBySingleSegment("HOUR(server_time)"); + while($row = $query->fetch()) + { + $this->interestByServerTime[$row['label']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getGoalRowFromQueryRow($row); + } + $archiveProcessing->enrichConversionsByLabelArray($this->interestByServerTime); } - private function makeSureAllHoursAreSet($table) + protected function archiveDayRecordInDatabase($archiveProcessing) + { + $tableLocalTime = $archiveProcessing->getDataTableFromArray($this->interestByLocalTime); + $this->makeSureAllHoursAreSet($tableLocalTime, $archiveProcessing); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_localTime', $tableLocalTime->getSerialized()); + + $tableServerTime = $archiveProcessing->getDataTableFromArray($this->interestByServerTime); + $this->makeSureAllHoursAreSet($tableServerTime, $archiveProcessing); + $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_serverTime', $tableServerTime->getSerialized()); + } + + private function makeSureAllHoursAreSet($table, $archiveProcessing) { for($i=0;$i<=23;$i++) { if($table->getRowFromLabel($i) === false) { - $row = $this->archiveProcessing->getNewInterestRowLabeled($i); + $row = $archiveProcessing->getNewInterestRowLabeled($i); $table->addRow( $row ); } } diff --git a/plugins/VisitorInterest/API.php b/plugins/VisitorInterest/API.php index fc2af110ff..2903c3eabf 100644 --- a/plugins/VisitorInterest/API.php +++ b/plugins/VisitorInterest/API.php @@ -14,7 +14,7 @@ * * @package Piwik_VisitorInterest */ -class Piwik_VisitorInterest_API extends Piwik_Apiable +class Piwik_VisitorInterest_API { static private $instance = null; static public function getInstance() diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php index 72df24bfbf..ed9a75df7c 100644 --- a/plugins/VisitsSummary/API.php +++ b/plugins/VisitsSummary/API.php @@ -12,7 +12,7 @@ /** * @package Piwik_VisitsSummary */ -class Piwik_VisitsSummary_API extends Piwik_Apiable +class Piwik_VisitsSummary_API { static private $instance = null; static public function getInstance() @@ -36,6 +36,7 @@ class Piwik_VisitsSummary_API extends Piwik_Apiable 'nb_actions', 'sum_visit_length', 'bounce_count', + 'nb_visits_converted', ); $dataTable = $archive->getDataTableFromNumeric($toFetch); return $dataTable; @@ -83,4 +84,9 @@ class Piwik_VisitsSummary_API extends Piwik_Apiable { return self::getNumeric( $idSite, $period, $date, 'bounce_count'); } + + public function getVisitsConverted( $idSite, $period, $date ) + { + return self::getNumeric( $idSite, $period, $date, 'nb_visits_converted'); + } } |