Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MultiSites/API.php')
-rwxr-xr-xplugins/MultiSites/API.php930
1 files changed, 445 insertions, 485 deletions
diff --git a/plugins/MultiSites/API.php b/plugins/MultiSites/API.php
index 3f4176bbc0..2277291598 100755
--- a/plugins/MultiSites/API.php
+++ b/plugins/MultiSites/API.php
@@ -1,10 +1,10 @@
<?php
/**
* Piwik - Open source web analytics
- *
+ *
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
+ *
* @category Piwik_Plugins
* @package Piwik_MultiSites
*/
@@ -14,487 +14,447 @@
*/
class Piwik_MultiSites_API
{
- const METRIC_TRANSLATION_KEY = 'translation';
- const METRIC_EVOLUTION_COL_NAME_KEY = 'evolution_column_name';
- const METRIC_RECORD_NAME_KEY = 'record_name';
- const METRIC_IS_ECOMMERCE_KEY = 'is_ecommerce';
-
- const NB_VISITS_METRIC = 'nb_visits';
- const NB_ACTIONS_METRIC = 'nb_actions';
- const NB_PAGEVIEWS_LABEL = 'nb_pageviews';
- const NB_PAGEVIEWS_METRIC = 'Actions_nb_pageviews';
- const GOAL_REVENUE_METRIC = 'revenue';
- const GOAL_CONVERSION_METRIC = 'nb_conversions';
- const ECOMMERCE_ORDERS_METRIC = 'orders';
- const ECOMMERCE_REVENUE_METRIC = 'ecommerce_revenue';
-
- static private $baseMetrics = array(
- self::NB_VISITS_METRIC => array (
- self::METRIC_TRANSLATION_KEY => 'General_ColumnNbVisits',
- self::METRIC_EVOLUTION_COL_NAME_KEY => 'visits_evolution',
- self::METRIC_RECORD_NAME_KEY => self::NB_VISITS_METRIC,
- self::METRIC_IS_ECOMMERCE_KEY => false,
- ),
- self::NB_ACTIONS_METRIC => array (
- self::METRIC_TRANSLATION_KEY => 'General_ColumnNbActions',
- self::METRIC_EVOLUTION_COL_NAME_KEY => 'actions_evolution',
- self::METRIC_RECORD_NAME_KEY => self::NB_ACTIONS_METRIC,
- self::METRIC_IS_ECOMMERCE_KEY => false,
- ),
- self::NB_PAGEVIEWS_LABEL => array (
- self::METRIC_TRANSLATION_KEY => 'General_ColumnPageviews',
- self::METRIC_EVOLUTION_COL_NAME_KEY => 'pageviews_evolution',
- self::METRIC_RECORD_NAME_KEY => self::NB_PAGEVIEWS_METRIC,
- self::METRIC_IS_ECOMMERCE_KEY => false,
- )
- );
-
- /**
- * The singleton instance of this class.
- */
- static private $instance = null;
-
- /**
- * Returns the singleton instance of this class. The instance is created
- * if it hasn't been already.
- *
- * @return Piwik_MultiSites_API
- */
- static public function getInstance()
- {
- if (self::$instance == null)
- {
- self::$instance = new self;
- }
-
- return self::$instance;
- }
-
- /**
- * Returns a report displaying the total visits, actions and revenue, as
- * well as the evolution of these values, of all existing sites over a
- * specified period of time.
- *
- * If the specified period is not a 'range', this function will calculcate
- * evolution metrics. Evolution metrics are metrics that display the
- * percent increase/decrease of another metric since the last period.
- *
- * This function will merge the result of the archive query so each
- * row in the result DataTable will correspond to the metrics of a single
- * site. If a date range is specified, the result will be a
- * DataTable_Array, but it will still be merged.
- *
- * @param string $period The period type to get data for.
- * @param string $date The date(s) to get data for.
- * @param bool|string $segment The segments to get data for.
- * @param bool|string $_restrictSitesToLogin Hack used to enforce we restrict the returned data to the specified username
- * Only used when a scheduled task is running
- * @param bool|string $enhanced When true, return additional goal & ecommerce metrics
- * @param bool|string $pattern If specified, only the website which names (or site ID) match the pattern will be returned using SitesManager.getPatternMatchSites
- * @return Piwik_DataTable
- */
- public function getAll($period, $date, $segment = false, $_restrictSitesToLogin = false, $enhanced = false, $pattern = false)
- {
- Piwik::checkUserHasSomeViewAccess();
-
- $idSites = $this->getSitesIdFromPattern($pattern);
-
- return $this->buildDataTable(
- $idSites,
- $period,
- $date,
- $segment,
- $_restrictSitesToLogin,
- $enhanced,
- $multipleWebsitesRequested = true
- );
- }
-
- /**
- * Fetches the list of sites which names match the string pattern
- *
- * @param $pattern
- * @return array|string
- */
- private function getSitesIdFromPattern($pattern)
- {
- $idSites = 'all';
- if (!empty($pattern)) {
- $sites = Piwik_API_Request::processRequest('SitesManager.getPatternMatchSites',
- array('pattern' => $pattern,
- // added because caller could overwrite these
- 'serialize' => 0,
- 'format' => 'original'));
- if (!empty($sites)) {
- $idSites = array();
- foreach ($sites as $site) {
- $idSites[] = $site['idsite'];
- }
- }
- }
- return $idSites;
- }
-
- /**
- * Same as getAll but for a unique Piwik site
- * @see Piwik_MultiSites_API::getAll()
- *
- * @param int $idSite Id of the Piwik site
- * @param string $period The period type to get data for.
- * @param string $date The date(s) to get data for.
- * @param bool|string $segment The segments to get data for.
- * @param bool|string $_restrictSitesToLogin Hack used to enforce we restrict the returned data to the specified username
- * Only used when a scheduled task is running
- * @param bool|string $enhanced When true, return additional goal & ecommerce metrics
- * @return Piwik_DataTable
- */
- public function getOne($idSite, $period, $date, $segment = false, $_restrictSitesToLogin = false, $enhanced = false)
- {
- Piwik::checkUserHasViewAccess($idSite);
- return $this->buildDataTable(
- $idSite,
- $period,
- $date,
- $segment,
- $_restrictSitesToLogin,
- $enhanced,
- $multipleWebsitesRequested = false
- );
- }
-
- private function buildDataTable($sites, $period, $date, $segment, $_restrictSitesToLogin, $enhanced, $multipleWebsitesRequested)
- {
- $allWebsitesRequested = ($sites == 'all');
- if($allWebsitesRequested)
- {
- if (Piwik::isUserIsSuperUser()
- // Hack: when this API function is called as a Scheduled Task, Super User status is enforced.
- // This means this function would return ALL websites in all cases.
- // Instead, we make sure that only the right set of data is returned
- && !Piwik_TaskScheduler::isTaskBeingExecuted())
- {
- Piwik_Site::setSites(
- Piwik_SitesManager_API::getInstance()->getAllSites()
- );
- }
- else
- {
- Piwik_Site::setSitesFromArray(
- Piwik_SitesManager_API::getInstance()->getSitesWithAtLeastViewAccess($limit = false, $_restrictSitesToLogin)
- );
- }
- }
-
- // build the archive type used to query archive data
- $archive = Piwik_Archive::build(
- $sites,
- $period,
- $date,
- $segment,
- $_restrictSitesToLogin
- );
-
- // determine what data will be displayed
- $fieldsToGet = array();
- $columnNameRewrites = array();
- $apiECommerceMetrics = array();
- $apiMetrics = Piwik_MultiSites_API::getApiMetrics($enhanced);
- foreach($apiMetrics as $metricName => $metricSettings)
- {
- $fieldsToGet[] = $metricSettings[self::METRIC_RECORD_NAME_KEY];
- $columnNameRewrites[$metricSettings[self::METRIC_RECORD_NAME_KEY]] = $metricName;
-
- if($metricSettings[self::METRIC_IS_ECOMMERCE_KEY])
- {
- $apiECommerceMetrics[$metricName] = $metricSettings;
- }
- }
-
- // get the data
- // $dataTable instanceOf Piwik_DataTable_Array
- $dataTable = $archive->getDataTableFromNumeric($fieldsToGet);
-
- // get rid of the DataTable_Array that is created by the IndexedBySite archive type
- if($dataTable instanceof Piwik_DataTable_Array
- && $multipleWebsitesRequested)
- {
- $dataTable = $dataTable->mergeChildren();
- }
- else
- {
- if(!$dataTable instanceof Piwik_DataTable_Array)
- {
- $firstDataTableRow = $dataTable->getFirstRow();
- $firstDataTableRow->setColumn('label', $sites);
- }
- }
-
- // calculate total visits/actions/revenue
- $this->setMetricsTotalsMetadata($dataTable, $apiMetrics);
-
- // if the period isn't a range & a lastN/previousN date isn't used, we get the same
- // data for the last period to show the evolution of visits/actions/revenue
- list($strLastDate, $lastPeriod) = Piwik_Period_Range::getLastDate($date, $period);
- if ($strLastDate !== false)
- {
- if ($lastPeriod !== false)
- {
- // NOTE: no easy way to set last period date metadata when range of dates is requested.
- // will be easier if DataTable_Array::metadata is removed, and metadata that is
- // put there is put directly in Piwik_DataTable::metadata.
- $dataTable->setMetadata(self::getLastPeriodMetadataName('date'), $lastPeriod);
- }
-
- $pastArchive = Piwik_Archive::build('all', $period, $strLastDate, $segment, $_restrictSitesToLogin);
- $pastData = $pastArchive->getDataTableFromNumeric($fieldsToGet);
-
- $pastData = $pastData->mergeChildren();
-
- // use past data to calculate evolution percentages
- $this->calculateEvolutionPercentages($dataTable, $pastData, $apiMetrics);
-
- $this->setPastDataMetadata($dataTable, $pastData, $apiMetrics);
- }
-
- // remove eCommerce related metrics on non eCommerce Piwik sites
- // note: this is not optimal in terms of performance: those metrics should not be retrieved in the first place
- if($enhanced)
- {
- // $dataTableRows instanceOf Piwik_DataTable_Row[]
- $dataTableRows = $dataTable->getRows();
-
- foreach($dataTableRows as $dataTableRow)
- {
- $siteId = $dataTableRow->getColumn('label');
- if(!Piwik_Site::isEcommerceEnabledFor($siteId))
- {
- foreach($apiECommerceMetrics as $metricSettings)
- {
- $dataTableRow->deleteColumn($metricSettings[self::METRIC_RECORD_NAME_KEY]);
- $dataTableRow->deleteColumn($metricSettings[self::METRIC_EVOLUTION_COL_NAME_KEY]);
- }
- }
- }
- }
-
- // move the site id to a metadata column
- $dataTable->filter('ColumnCallbackAddMetadata', array('label', 'idsite'));
-
- // set the label of each row to the site name
- if($multipleWebsitesRequested)
- {
- $getNameFor = array('Piwik_Site', 'getNameFor');
- $dataTable->filter('ColumnCallbackReplace', array('label', $getNameFor));
- }
- else
- {
- $dataTable->filter('ColumnDelete', array('label'));
- }
-
- // replace record names with user friendly metric names
- $dataTable->filter('ReplaceColumnNames', array($columnNameRewrites));
-
- // Ensures data set sorted, for Metadata output
- $dataTable->filter('Sort', array(self::NB_VISITS_METRIC, 'desc', $naturalSort = false));
-
- // filter rows without visits
- // note: if only one website is queried and there are no visits, we can not remove the row otherwise Piwik_API_ResponseBuilder throws 'Call to a member function getColumns() on a non-object'
- if($multipleWebsitesRequested)
- {
- $dataTable->filter(
- 'ColumnCallbackDeleteRow',
- array(
- self::NB_VISITS_METRIC,
- create_function ( '$value', 'return $value != 0;')
- )
- );
- }
-
- return $dataTable;
- }
-
- /**
- * Performs a binary filter of two
- * DataTables in order to correctly calculate evolution metrics.
- *
- * @param Piwik_DataTable|Piwik_DataTable_Array $currentData
- * @param Piwik_DataTable|Piwik_DataTable_Array $pastData
- * @param array $fields The array of string fields to calculate evolution
- * metrics for.
- */
- private function calculateEvolutionPercentages($currentData, $pastData, $apiMetrics)
- {
- if ($currentData instanceof Piwik_DataTable_Array)
- {
- $pastArray = $pastData->getArray();
- foreach ($currentData->getArray() as $subTable)
- {
- $this->calculateEvolutionPercentages($subTable, current($pastArray), $apiMetrics);
- next($pastArray);
- }
- }
- else
- {
- foreach ($apiMetrics as $metricSettings)
- {
- $currentData->filter(
- 'CalculateEvolutionFilter',
- array(
- $pastData,
- $metricSettings[self::METRIC_EVOLUTION_COL_NAME_KEY],
- $metricSettings[self::METRIC_RECORD_NAME_KEY],
- $quotientPrecision = 1)
- );
- }
- }
- }
-
- /**
- * Sets the total visits, actions & revenue for a DataTable returned by
- * $this->buildDataTable.
- *
- * @param Piwik_DataTable $dataTable
- * @param array $apiMetrics Metrics info.
- * @return array Array of three values: total visits, total actions, total revenue
- */
- private function setMetricsTotalsMetadata( $dataTable, $apiMetrics )
- {
- if ($dataTable instanceof Piwik_DataTable_Array)
- {
- foreach ($dataTable->getArray() as $table)
- {
- $this->setMetricsTotalsMetadata($table, $apiMetrics);
- }
- }
- else
- {
- $revenueMetric = '';
- if (Piwik_Common::isGoalPluginEnabled())
- {
- $revenueMetric = Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC);
- }
-
- $totals = array();
- foreach ($apiMetrics as $label => $metricInfo)
- {
- $totalMetadataName = self::getTotalMetadataName($label);
- $totals[$totalMetadataName] = 0;
- }
-
- foreach ($dataTable->getRows() as $row)
- {
- foreach ($apiMetrics as $label => $metricInfo)
- {
- $totalMetadataName = self::getTotalMetadataName($label);
- $totals[$totalMetadataName] += $row->getColumn($metricInfo[self::METRIC_RECORD_NAME_KEY]);
- }
- }
-
- foreach ($totals as $name => $value)
- {
- $dataTable->setMetadata($name, $value);
- }
- }
- }
-
- /**
- * Sets the total evolution metadata for a datatable returned by $this->buildDataTable
- * given data for the last period.
- *
- * @param Piwik_DataTable $dataTable
- * @param Piwik_DataTable $pastData
- * @param array $apiMetrics Metrics info.
- */
- private function setPastDataMetadata( $dataTable, $pastData, $apiMetrics )
- {
- if ($dataTable instanceof Piwik_DataTable_Array)
- {
- $pastArray = $pastData->getArray();
- foreach ($dataTable->getArray() as $subTable)
- {
- $this->setPastDataMetadata($subTable, current($pastArray), $apiMetrics);
- next($pastArray);
- }
- }
- else
- {
- // calculate total visits/actions/revenue for past data
- $this->setMetricsTotalsMetadata($pastData, $apiMetrics);
-
- foreach ($apiMetrics as $label => $metricInfo)
- {
- // get the names of metadata to set
- $totalMetadataName = self::getTotalMetadataName($label);
- $lastPeriodTotalMetadataName = self::getLastPeriodMetadataName($totalMetadataName);
- $totalEvolutionMetadataName =
- self::getTotalMetadataName($metricInfo[self::METRIC_EVOLUTION_COL_NAME_KEY]);
-
- // set last period total
- $pastTotal = $pastData->getMetadata($totalMetadataName);
- $dataTable->setMetadata($lastPeriodTotalMetadataName, $pastTotal);
-
- // calculate & set evolution
- $currentTotal = $dataTable->getMetadata($totalMetadataName);
- $evolution = Piwik_DataTable_Filter_CalculateEvolutionFilter::calculate($currentTotal, $pastTotal);
- $dataTable->setMetadata($totalEvolutionMetadataName, $evolution);
- }
- }
- }
-
- /**
- * @ignore
- */
- public static function getApiMetrics($enhanced)
- {
- $metrics = self::$baseMetrics;
- if (Piwik_Common::isGoalPluginEnabled())
- {
- // goal revenue metric
- $metrics[self::GOAL_REVENUE_METRIC] = array(
- self::METRIC_TRANSLATION_KEY => 'Goals_ColumnRevenue',
- self::METRIC_EVOLUTION_COL_NAME_KEY => self::GOAL_REVENUE_METRIC . '_evolution',
- self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC),
- self::METRIC_IS_ECOMMERCE_KEY => false,
- );
-
- if($enhanced)
- {
- // number of goal conversions metric
- $metrics[self::GOAL_CONVERSION_METRIC] = array(
- self::METRIC_TRANSLATION_KEY => 'Goals_ColumnConversions',
- self::METRIC_EVOLUTION_COL_NAME_KEY => self::GOAL_CONVERSION_METRIC . '_evolution',
- self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_CONVERSION_METRIC),
- self::METRIC_IS_ECOMMERCE_KEY => false,
- );
-
- // number of orders
- $metrics[self::ECOMMERCE_ORDERS_METRIC] = array(
- self::METRIC_TRANSLATION_KEY => 'General_EcommerceOrders',
- self::METRIC_EVOLUTION_COL_NAME_KEY => self::ECOMMERCE_ORDERS_METRIC . '_evolution',
- self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_CONVERSION_METRIC ,0),
- self::METRIC_IS_ECOMMERCE_KEY => true,
- );
-
- // eCommerce revenue
- $metrics[self::ECOMMERCE_REVENUE_METRIC] = array(
- self::METRIC_TRANSLATION_KEY => 'General_ProductRevenue',
- self::METRIC_EVOLUTION_COL_NAME_KEY => self::ECOMMERCE_REVENUE_METRIC . '_evolution',
- self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC ,0),
- self::METRIC_IS_ECOMMERCE_KEY => true,
- );
- }
- }
-
- return $metrics;
- }
-
- private static function getTotalMetadataName( $name )
- {
- return 'total_'.$name;
- }
-
- private static function getLastPeriodMetadataName( $name )
- {
- return 'last_period_'.$name;
- }
+ const METRIC_TRANSLATION_KEY = 'translation';
+ const METRIC_EVOLUTION_COL_NAME_KEY = 'evolution_column_name';
+ const METRIC_RECORD_NAME_KEY = 'record_name';
+ const METRIC_IS_ECOMMERCE_KEY = 'is_ecommerce';
+
+ const NB_VISITS_METRIC = 'nb_visits';
+ const NB_ACTIONS_METRIC = 'nb_actions';
+ const NB_PAGEVIEWS_LABEL = 'nb_pageviews';
+ const NB_PAGEVIEWS_METRIC = 'Actions_nb_pageviews';
+ const GOAL_REVENUE_METRIC = 'revenue';
+ const GOAL_CONVERSION_METRIC = 'nb_conversions';
+ const ECOMMERCE_ORDERS_METRIC = 'orders';
+ const ECOMMERCE_REVENUE_METRIC = 'ecommerce_revenue';
+
+ static private $baseMetrics = array(
+ self::NB_VISITS_METRIC => array(
+ self::METRIC_TRANSLATION_KEY => 'General_ColumnNbVisits',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => 'visits_evolution',
+ self::METRIC_RECORD_NAME_KEY => self::NB_VISITS_METRIC,
+ self::METRIC_IS_ECOMMERCE_KEY => false,
+ ),
+ self::NB_ACTIONS_METRIC => array(
+ self::METRIC_TRANSLATION_KEY => 'General_ColumnNbActions',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => 'actions_evolution',
+ self::METRIC_RECORD_NAME_KEY => self::NB_ACTIONS_METRIC,
+ self::METRIC_IS_ECOMMERCE_KEY => false,
+ ),
+ self::NB_PAGEVIEWS_LABEL => array(
+ self::METRIC_TRANSLATION_KEY => 'General_ColumnPageviews',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => 'pageviews_evolution',
+ self::METRIC_RECORD_NAME_KEY => self::NB_PAGEVIEWS_METRIC,
+ self::METRIC_IS_ECOMMERCE_KEY => false,
+ )
+ );
+
+ /**
+ * The singleton instance of this class.
+ */
+ static private $instance = null;
+
+ /**
+ * Returns the singleton instance of this class. The instance is created
+ * if it hasn't been already.
+ *
+ * @return Piwik_MultiSites_API
+ */
+ static public function getInstance()
+ {
+ if (self::$instance == null) {
+ self::$instance = new self;
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Returns a report displaying the total visits, actions and revenue, as
+ * well as the evolution of these values, of all existing sites over a
+ * specified period of time.
+ *
+ * If the specified period is not a 'range', this function will calculcate
+ * evolution metrics. Evolution metrics are metrics that display the
+ * percent increase/decrease of another metric since the last period.
+ *
+ * This function will merge the result of the archive query so each
+ * row in the result DataTable will correspond to the metrics of a single
+ * site. If a date range is specified, the result will be a
+ * DataTable_Array, but it will still be merged.
+ *
+ * @param string $period The period type to get data for.
+ * @param string $date The date(s) to get data for.
+ * @param bool|string $segment The segments to get data for.
+ * @param bool|string $_restrictSitesToLogin Hack used to enforce we restrict the returned data to the specified username
+ * Only used when a scheduled task is running
+ * @param bool|string $enhanced When true, return additional goal & ecommerce metrics
+ * @param bool|string $pattern If specified, only the website which names (or site ID) match the pattern will be returned using SitesManager.getPatternMatchSites
+ * @return Piwik_DataTable
+ */
+ public function getAll($period, $date, $segment = false, $_restrictSitesToLogin = false, $enhanced = false, $pattern = false)
+ {
+ Piwik::checkUserHasSomeViewAccess();
+
+ $idSites = $this->getSitesIdFromPattern($pattern);
+
+ return $this->buildDataTable(
+ $idSites,
+ $period,
+ $date,
+ $segment,
+ $_restrictSitesToLogin,
+ $enhanced,
+ $multipleWebsitesRequested = true
+ );
+ }
+
+ /**
+ * Fetches the list of sites which names match the string pattern
+ *
+ * @param $pattern
+ * @return array|string
+ */
+ private function getSitesIdFromPattern($pattern)
+ {
+ $idSites = 'all';
+ if (!empty($pattern)) {
+ $sites = Piwik_API_Request::processRequest('SitesManager.getPatternMatchSites',
+ array('pattern' => $pattern,
+ // added because caller could overwrite these
+ 'serialize' => 0,
+ 'format' => 'original'));
+ if (!empty($sites)) {
+ $idSites = array();
+ foreach ($sites as $site) {
+ $idSites[] = $site['idsite'];
+ }
+ }
+ }
+ return $idSites;
+ }
+
+ /**
+ * Same as getAll but for a unique Piwik site
+ * @see Piwik_MultiSites_API::getAll()
+ *
+ * @param int $idSite Id of the Piwik site
+ * @param string $period The period type to get data for.
+ * @param string $date The date(s) to get data for.
+ * @param bool|string $segment The segments to get data for.
+ * @param bool|string $_restrictSitesToLogin Hack used to enforce we restrict the returned data to the specified username
+ * Only used when a scheduled task is running
+ * @param bool|string $enhanced When true, return additional goal & ecommerce metrics
+ * @return Piwik_DataTable
+ */
+ public function getOne($idSite, $period, $date, $segment = false, $_restrictSitesToLogin = false, $enhanced = false)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+ return $this->buildDataTable(
+ $idSite,
+ $period,
+ $date,
+ $segment,
+ $_restrictSitesToLogin,
+ $enhanced,
+ $multipleWebsitesRequested = false
+ );
+ }
+
+ private function buildDataTable($sites, $period, $date, $segment, $_restrictSitesToLogin, $enhanced, $multipleWebsitesRequested)
+ {
+ $allWebsitesRequested = ($sites == 'all');
+ if ($allWebsitesRequested) {
+ if (Piwik::isUserIsSuperUser()
+ // Hack: when this API function is called as a Scheduled Task, Super User status is enforced.
+ // This means this function would return ALL websites in all cases.
+ // Instead, we make sure that only the right set of data is returned
+ && !Piwik_TaskScheduler::isTaskBeingExecuted()
+ ) {
+ Piwik_Site::setSites(
+ Piwik_SitesManager_API::getInstance()->getAllSites()
+ );
+ } else {
+ Piwik_Site::setSitesFromArray(
+ Piwik_SitesManager_API::getInstance()->getSitesWithAtLeastViewAccess($limit = false, $_restrictSitesToLogin)
+ );
+ }
+ }
+
+ // build the archive type used to query archive data
+ $archive = Piwik_Archive::build(
+ $sites,
+ $period,
+ $date,
+ $segment,
+ $_restrictSitesToLogin
+ );
+
+ // determine what data will be displayed
+ $fieldsToGet = array();
+ $columnNameRewrites = array();
+ $apiECommerceMetrics = array();
+ $apiMetrics = Piwik_MultiSites_API::getApiMetrics($enhanced);
+ foreach ($apiMetrics as $metricName => $metricSettings) {
+ $fieldsToGet[] = $metricSettings[self::METRIC_RECORD_NAME_KEY];
+ $columnNameRewrites[$metricSettings[self::METRIC_RECORD_NAME_KEY]] = $metricName;
+
+ if ($metricSettings[self::METRIC_IS_ECOMMERCE_KEY]) {
+ $apiECommerceMetrics[$metricName] = $metricSettings;
+ }
+ }
+
+ // get the data
+ // $dataTable instanceOf Piwik_DataTable_Array
+ $dataTable = $archive->getDataTableFromNumeric($fieldsToGet);
+
+ // get rid of the DataTable_Array that is created by the IndexedBySite archive type
+ if ($dataTable instanceof Piwik_DataTable_Array
+ && $multipleWebsitesRequested
+ ) {
+ $dataTable = $dataTable->mergeChildren();
+ } else {
+ if (!$dataTable instanceof Piwik_DataTable_Array) {
+ $firstDataTableRow = $dataTable->getFirstRow();
+ $firstDataTableRow->setColumn('label', $sites);
+ }
+ }
+
+ // calculate total visits/actions/revenue
+ $this->setMetricsTotalsMetadata($dataTable, $apiMetrics);
+
+ // if the period isn't a range & a lastN/previousN date isn't used, we get the same
+ // data for the last period to show the evolution of visits/actions/revenue
+ list($strLastDate, $lastPeriod) = Piwik_Period_Range::getLastDate($date, $period);
+ if ($strLastDate !== false) {
+ if ($lastPeriod !== false) {
+ // NOTE: no easy way to set last period date metadata when range of dates is requested.
+ // will be easier if DataTable_Array::metadata is removed, and metadata that is
+ // put there is put directly in Piwik_DataTable::metadata.
+ $dataTable->setMetadata(self::getLastPeriodMetadataName('date'), $lastPeriod);
+ }
+
+ $pastArchive = Piwik_Archive::build('all', $period, $strLastDate, $segment, $_restrictSitesToLogin);
+ $pastData = $pastArchive->getDataTableFromNumeric($fieldsToGet);
+
+ $pastData = $pastData->mergeChildren();
+
+ // use past data to calculate evolution percentages
+ $this->calculateEvolutionPercentages($dataTable, $pastData, $apiMetrics);
+
+ $this->setPastDataMetadata($dataTable, $pastData, $apiMetrics);
+ }
+
+ // remove eCommerce related metrics on non eCommerce Piwik sites
+ // note: this is not optimal in terms of performance: those metrics should not be retrieved in the first place
+ if ($enhanced) {
+ // $dataTableRows instanceOf Piwik_DataTable_Row[]
+ $dataTableRows = $dataTable->getRows();
+
+ foreach ($dataTableRows as $dataTableRow) {
+ $siteId = $dataTableRow->getColumn('label');
+ if (!Piwik_Site::isEcommerceEnabledFor($siteId)) {
+ foreach ($apiECommerceMetrics as $metricSettings) {
+ $dataTableRow->deleteColumn($metricSettings[self::METRIC_RECORD_NAME_KEY]);
+ $dataTableRow->deleteColumn($metricSettings[self::METRIC_EVOLUTION_COL_NAME_KEY]);
+ }
+ }
+ }
+ }
+
+ // move the site id to a metadata column
+ $dataTable->filter('ColumnCallbackAddMetadata', array('label', 'idsite'));
+
+ // set the label of each row to the site name
+ if ($multipleWebsitesRequested) {
+ $getNameFor = array('Piwik_Site', 'getNameFor');
+ $dataTable->filter('ColumnCallbackReplace', array('label', $getNameFor));
+ } else {
+ $dataTable->filter('ColumnDelete', array('label'));
+ }
+
+ // replace record names with user friendly metric names
+ $dataTable->filter('ReplaceColumnNames', array($columnNameRewrites));
+
+ // Ensures data set sorted, for Metadata output
+ $dataTable->filter('Sort', array(self::NB_VISITS_METRIC, 'desc', $naturalSort = false));
+
+ // filter rows without visits
+ // note: if only one website is queried and there are no visits, we can not remove the row otherwise Piwik_API_ResponseBuilder throws 'Call to a member function getColumns() on a non-object'
+ if ($multipleWebsitesRequested) {
+ $dataTable->filter(
+ 'ColumnCallbackDeleteRow',
+ array(
+ self::NB_VISITS_METRIC,
+ create_function('$value', 'return $value != 0;')
+ )
+ );
+ }
+
+ return $dataTable;
+ }
+
+ /**
+ * Performs a binary filter of two
+ * DataTables in order to correctly calculate evolution metrics.
+ *
+ * @param Piwik_DataTable|Piwik_DataTable_Array $currentData
+ * @param Piwik_DataTable|Piwik_DataTable_Array $pastData
+ * @param array $fields The array of string fields to calculate evolution
+ * metrics for.
+ */
+ private function calculateEvolutionPercentages($currentData, $pastData, $apiMetrics)
+ {
+ if ($currentData instanceof Piwik_DataTable_Array) {
+ $pastArray = $pastData->getArray();
+ foreach ($currentData->getArray() as $subTable) {
+ $this->calculateEvolutionPercentages($subTable, current($pastArray), $apiMetrics);
+ next($pastArray);
+ }
+ } else {
+ foreach ($apiMetrics as $metricSettings) {
+ $currentData->filter(
+ 'CalculateEvolutionFilter',
+ array(
+ $pastData,
+ $metricSettings[self::METRIC_EVOLUTION_COL_NAME_KEY],
+ $metricSettings[self::METRIC_RECORD_NAME_KEY],
+ $quotientPrecision = 1)
+ );
+ }
+ }
+ }
+
+ /**
+ * Sets the total visits, actions & revenue for a DataTable returned by
+ * $this->buildDataTable.
+ *
+ * @param Piwik_DataTable $dataTable
+ * @param array $apiMetrics Metrics info.
+ * @return array Array of three values: total visits, total actions, total revenue
+ */
+ private function setMetricsTotalsMetadata($dataTable, $apiMetrics)
+ {
+ if ($dataTable instanceof Piwik_DataTable_Array) {
+ foreach ($dataTable->getArray() as $table) {
+ $this->setMetricsTotalsMetadata($table, $apiMetrics);
+ }
+ } else {
+ $revenueMetric = '';
+ if (Piwik_Common::isGoalPluginEnabled()) {
+ $revenueMetric = Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC);
+ }
+
+ $totals = array();
+ foreach ($apiMetrics as $label => $metricInfo) {
+ $totalMetadataName = self::getTotalMetadataName($label);
+ $totals[$totalMetadataName] = 0;
+ }
+
+ foreach ($dataTable->getRows() as $row) {
+ foreach ($apiMetrics as $label => $metricInfo) {
+ $totalMetadataName = self::getTotalMetadataName($label);
+ $totals[$totalMetadataName] += $row->getColumn($metricInfo[self::METRIC_RECORD_NAME_KEY]);
+ }
+ }
+
+ foreach ($totals as $name => $value) {
+ $dataTable->setMetadata($name, $value);
+ }
+ }
+ }
+
+ /**
+ * Sets the total evolution metadata for a datatable returned by $this->buildDataTable
+ * given data for the last period.
+ *
+ * @param Piwik_DataTable $dataTable
+ * @param Piwik_DataTable $pastData
+ * @param array $apiMetrics Metrics info.
+ */
+ private function setPastDataMetadata($dataTable, $pastData, $apiMetrics)
+ {
+ if ($dataTable instanceof Piwik_DataTable_Array) {
+ $pastArray = $pastData->getArray();
+ foreach ($dataTable->getArray() as $subTable) {
+ $this->setPastDataMetadata($subTable, current($pastArray), $apiMetrics);
+ next($pastArray);
+ }
+ } else {
+ // calculate total visits/actions/revenue for past data
+ $this->setMetricsTotalsMetadata($pastData, $apiMetrics);
+
+ foreach ($apiMetrics as $label => $metricInfo) {
+ // get the names of metadata to set
+ $totalMetadataName = self::getTotalMetadataName($label);
+ $lastPeriodTotalMetadataName = self::getLastPeriodMetadataName($totalMetadataName);
+ $totalEvolutionMetadataName =
+ self::getTotalMetadataName($metricInfo[self::METRIC_EVOLUTION_COL_NAME_KEY]);
+
+ // set last period total
+ $pastTotal = $pastData->getMetadata($totalMetadataName);
+ $dataTable->setMetadata($lastPeriodTotalMetadataName, $pastTotal);
+
+ // calculate & set evolution
+ $currentTotal = $dataTable->getMetadata($totalMetadataName);
+ $evolution = Piwik_DataTable_Filter_CalculateEvolutionFilter::calculate($currentTotal, $pastTotal);
+ $dataTable->setMetadata($totalEvolutionMetadataName, $evolution);
+ }
+ }
+ }
+
+ /**
+ * @ignore
+ */
+ public static function getApiMetrics($enhanced)
+ {
+ $metrics = self::$baseMetrics;
+ if (Piwik_Common::isGoalPluginEnabled()) {
+ // goal revenue metric
+ $metrics[self::GOAL_REVENUE_METRIC] = array(
+ self::METRIC_TRANSLATION_KEY => 'Goals_ColumnRevenue',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => self::GOAL_REVENUE_METRIC . '_evolution',
+ self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC),
+ self::METRIC_IS_ECOMMERCE_KEY => false,
+ );
+
+ if ($enhanced) {
+ // number of goal conversions metric
+ $metrics[self::GOAL_CONVERSION_METRIC] = array(
+ self::METRIC_TRANSLATION_KEY => 'Goals_ColumnConversions',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => self::GOAL_CONVERSION_METRIC . '_evolution',
+ self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_CONVERSION_METRIC),
+ self::METRIC_IS_ECOMMERCE_KEY => false,
+ );
+
+ // number of orders
+ $metrics[self::ECOMMERCE_ORDERS_METRIC] = array(
+ self::METRIC_TRANSLATION_KEY => 'General_EcommerceOrders',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => self::ECOMMERCE_ORDERS_METRIC . '_evolution',
+ self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_CONVERSION_METRIC, 0),
+ self::METRIC_IS_ECOMMERCE_KEY => true,
+ );
+
+ // eCommerce revenue
+ $metrics[self::ECOMMERCE_REVENUE_METRIC] = array(
+ self::METRIC_TRANSLATION_KEY => 'General_ProductRevenue',
+ self::METRIC_EVOLUTION_COL_NAME_KEY => self::ECOMMERCE_REVENUE_METRIC . '_evolution',
+ self::METRIC_RECORD_NAME_KEY => Piwik_Goals::getRecordName(self::GOAL_REVENUE_METRIC, 0),
+ self::METRIC_IS_ECOMMERCE_KEY => true,
+ );
+ }
+ }
+
+ return $metrics;
+ }
+
+ private static function getTotalMetadataName($name)
+ {
+ return 'total_' . $name;
+ }
+
+ private static function getLastPeriodMetadataName($name)
+ {
+ return 'last_period_' . $name;
+ }
}