/** * @param string $period * @param string $date * @param string|false $segment */ public function __construct($period, $date, $segment) { $sites = API::getInstance()->getAll($period, $date, $segment, $_restrictSitesToLogin = false, $enhanced = true, $searchTerm = false, $this->displayedMetricColumns); $sites->deleteRow(DataTable::ID_SUMMARY_ROW); /** @var DataTable $pastData */ $pastData = $sites->getMetadata('pastData'); $sites->filter(function (DataTable $table) use($pastData) { $pastRow = null; foreach ($table->getRows() as $row) { $idSite = $row->getColumn('label'); $site = Site::getSite($idSite); // we cannot queue label and group as we might need them for search and sorting! $row->setColumn('label', $site['name']); $row->setMetadata('group', $site['group']); if ($pastData) { // if we do not update the pastData labels, the evolution cannot be calculated correctly. $pastRow = $pastData->getRowFromLabel($idSite); if ($pastRow) { $pastRow->setColumn('label', $site['name']); } } } if ($pastData && $pastRow) { $pastData->setLabelsHaveChanged(); } }); $this->setSitesTable($sites); }
/** * Testing that getOne returns a row even when there are no data * This is necessary otherwise ResponseBuilder throws 'Call to a member function getColumns() on a non-object' * * @group Plugins */ public function testWhenNoDataGetOneReturnsRow() { $dataTable = APIMultiSites::getInstance()->getOne($this->idSiteAccess, 'month', '01-01-2010'); $this->assertEquals(1, $dataTable->getRowsCount()); // safety net $this->assertEquals(0, $dataTable->getFirstRow()->getColumn('nb_visits')); }
/** * @group Benchmarks */ public function testArchivingProcess() { if ($this->archivingLaunched) { echo "NOTE: Had to archive data, memory results will not be accurate. Run again for better results."; } Rules::$archivingDisabledByTests = true; APIMultiSites::getInstance()->getAll(self::$fixture->period, self::$fixture->date); }
protected function init() { $this->category = 'General_MultiSitesSummary'; $metadataMetrics = array(); foreach (API::getApiMetrics($enhanced = true) as $metricName => $metricSettings) { $metadataMetrics[$metricName] = Piwik::translate($metricSettings[API::METRIC_TRANSLATION_KEY]); $metadataMetrics[$metricSettings[API::METRIC_EVOLUTION_COL_NAME_KEY]] = Piwik::translate($metricSettings[API::METRIC_TRANSLATION_KEY]) . " " . Piwik::translate('MultiSites_Evolution'); } $this->metrics = array_keys($metadataMetrics); }
public function getReportMetadata(&$reports) { $metadataMetrics = array(); foreach (API::getApiMetrics($enhanced = true) as $metricName => $metricSettings) { $metadataMetrics[$metricName] = Piwik::translate($metricSettings[API::METRIC_TRANSLATION_KEY]); $metadataMetrics[$metricSettings[API::METRIC_EVOLUTION_COL_NAME_KEY]] = Piwik::translate($metricSettings[API::METRIC_TRANSLATION_KEY]) . " " . Piwik::translate('MultiSites_Evolution'); } $reports[] = array('category' => Piwik::translate('General_MultiSitesSummary'), 'name' => Piwik::translate('General_AllWebsitesDashboard'), 'module' => 'MultiSites', 'action' => 'getAll', 'dimension' => Piwik::translate('General_Website'), 'metrics' => $metadataMetrics, 'processedMetrics' => false, 'constantRowsCount' => false, 'order' => 5); $reports[] = array('category' => Piwik::translate('General_MultiSitesSummary'), 'name' => Piwik::translate('General_SingleWebsitesDashboard'), 'module' => 'MultiSites', 'action' => 'getOne', 'dimension' => Piwik::translate('General_Website'), 'metrics' => $metadataMetrics, 'processedMetrics' => false, 'constantRowsCount' => false, 'order' => 5); }
public function renderReport($processedReport) { $isGoalPluginEnabled = Common::isGoalPluginEnabled(); $prettyDate = $processedReport['prettyDate']; $reportData = $processedReport['reportData']; $evolutionMetrics = array(); $multiSitesAPIMetrics = API::getApiMetrics($enhanced = true); foreach ($multiSitesAPIMetrics as $metricSettings) { $evolutionMetrics[] = $metricSettings[API::METRIC_EVOLUTION_COL_NAME_KEY]; } $floatRegex = self::FLOAT_REGEXP; // no decimal for all metrics to shorten SMS content (keeps the monetary sign for revenue metrics) $reportData->filter('ColumnCallbackReplace', array(array_merge(array_keys($multiSitesAPIMetrics), $evolutionMetrics), function ($value) use($floatRegex) { return preg_replace_callback($floatRegex, function ($matches) { return round($matches[0]); }, $value); })); // evolution metrics formatting : // - remove monetary, percentage and white spaces to shorten SMS content // (this is also needed to be able to test $value != 0 and see if there is an evolution at all in SMSReport.twig) // - adds a plus sign $reportData->filter('ColumnCallbackReplace', array($evolutionMetrics, function ($value) use($floatRegex) { $matched = preg_match($floatRegex, $value, $matches); $formatted = $matched ? sprintf("%+d", $matches[0]) : $value; return \Piwik\NumberFormatter::getInstance()->formatPercentEvolution($formatted); })); $dataRows = $reportData->getRows(); $reportMetadata = $processedReport['reportMetadata']; $reportRowsMetadata = $reportMetadata->getRows(); $siteHasECommerce = array(); foreach ($reportRowsMetadata as $rowMetadata) { $idSite = $rowMetadata->getColumn('idsite'); $siteHasECommerce[$idSite] = Site::isEcommerceEnabledFor($idSite); } $view = new View('@MobileMessaging/SMSReport'); $view->assign("isGoalPluginEnabled", $isGoalPluginEnabled); $view->assign("reportRows", $dataRows); $view->assign("reportRowsMetadata", $reportRowsMetadata); $view->assign("prettyDate", $prettyDate); $view->assign("siteHasECommerce", $siteHasECommerce); $view->assign("displaySiteName", $processedReport['metadata']['action'] == 'getAll'); // segment $segment = $processedReport['segment']; $displaySegment = $segment != null; $view->assign("displaySegment", $displaySegment); if ($displaySegment) { $view->assign("segmentName", $segment['name']); } $this->rendering .= $view->render(); }
public function processReports(&$processedReports, $reportType, $outputType, $report) { if (!self::manageEvent($reportType)) { return; } $displayFormat = $report['parameters'][self::DISPLAY_FORMAT_PARAMETER]; $evolutionGraph = $report['parameters'][self::EVOLUTION_GRAPH_PARAMETER]; foreach ($processedReports as &$processedReport) { $metadata = $processedReport['metadata']; $isAggregateReport = !empty($metadata['dimension']); $processedReport['displayTable'] = $displayFormat != self::DISPLAY_FORMAT_GRAPHS_ONLY; $processedReport['displayGraph'] = ($isAggregateReport ? $displayFormat == self::DISPLAY_FORMAT_GRAPHS_ONLY || $displayFormat == self::DISPLAY_FORMAT_TABLES_AND_GRAPHS : $displayFormat != self::DISPLAY_FORMAT_TABLES_ONLY) && \Piwik\SettingsServer::isGdExtensionEnabled() && \Piwik\Plugin\Manager::getInstance()->isPluginActivated('ImageGraph') && !empty($metadata['imageGraphUrl']); $processedReport['evolutionGraph'] = $evolutionGraph; // remove evolution metrics from MultiSites.getAll if ($metadata['module'] == 'MultiSites') { $columns = $processedReport['columns']; foreach (\Piwik\Plugins\MultiSites\API::getApiMetrics($enhanced = true) as $metricSettings) { unset($columns[$metricSettings[\Piwik\Plugins\MultiSites\API::METRIC_EVOLUTION_COL_NAME_KEY]]); } $processedReport['metadata'] = $metadata; $processedReport['columns'] = $columns; } } }
private function buildDataTable($sitesToProblablyAdd, $period, $date, $segment, $_restrictSitesToLogin, $enhanced, $multipleWebsitesRequested, $showColumns) { $idSites = array(); if (!empty($sitesToProblablyAdd)) { foreach ($sitesToProblablyAdd as $site) { $idSites[] = $site['idsite']; } } // build the archive type used to query archive data $archive = Archive::build($idSites, $period, $date, $segment, $_restrictSitesToLogin); // determine what data will be displayed $fieldsToGet = array(); $columnNameRewrites = array(); $apiECommerceMetrics = array(); $apiMetrics = API::getApiMetrics($enhanced); foreach ($apiMetrics as $metricName => $metricSettings) { if (!empty($showColumns) && !in_array($metricName, $showColumns)) { unset($apiMetrics[$metricName]); continue; } $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; } } $dataTable = $archive->getDataTableFromNumericAndMergeChildren($fieldsToGet); $this->populateLabel($dataTable); $totalMetrics = $this->preformatApiMetricsForTotalsCalculation($apiMetrics); $this->setMetricsTotalsMetadata($dataTable, $totalMetrics); // 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) = 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\Map::metadata is removed, and metadata that is // put there is put directly in DataTable::metadata. $dataTable->setMetadata(self::getLastPeriodMetadataName('date'), $lastPeriod); } $pastArchive = Archive::build($idSites, $period, $strLastDate, $segment, $_restrictSitesToLogin); $pastData = $pastArchive->getDataTableFromNumericAndMergeChildren($fieldsToGet); $this->populateLabel($pastData); // labels are needed to calculate evolution $this->calculateEvolutionPercentages($dataTable, $pastData, $apiMetrics); $this->setPastTotalVisitsMetadata($dataTable, $pastData); if ($dataTable instanceof DataTable) { // needed for MultiSites\Dashboard $dataTable->setMetadata('pastData', $pastData); } } // move the site id to a metadata column $dataTable->queueFilter('MetadataCallbackAddMetadata', array('idsite', 'group', array('\\Piwik\\Site', 'getGroupFor'), array())); $dataTable->queueFilter('MetadataCallbackAddMetadata', array('idsite', 'main_url', array('\\Piwik\\Site', 'getMainUrlFor'), array())); // set the label of each row to the site name if ($multipleWebsitesRequested) { $dataTable->queueFilter('ColumnCallbackReplace', array('label', '\\Piwik\\Site::getNameFor')); } else { $dataTable->queueFilter('ColumnDelete', array('label')); } // replace record names with user friendly metric names $dataTable->queueFilter('ReplaceColumnNames', array($columnNameRewrites)); // filter rows without visits // note: if only one website is queried and there are no visits, we can not remove the row otherwise // ResponseBuilder throws 'Call to a member function getColumns() on a non-object' if ($multipleWebsitesRequested && !$enhanced) { $dataTable->filter('ColumnCallbackDeleteRow', array(self::NB_VISITS_METRIC, function ($value) { return $value == 0; })); } if ($multipleWebsitesRequested && $dataTable->getRowsCount() === 1 && $dataTable instanceof DataTable\Simple) { $simpleTable = $dataTable; $dataTable = $simpleTable->getEmptyClone(); $dataTable->addRow($simpleTable->getFirstRow()); unset($simpleTable); } return $dataTable; }
private function buildDataTable($idSitesOrIdSite, $period, $date, $segment, $_restrictSitesToLogin, $enhanced, $multipleWebsitesRequested) { $allWebsitesRequested = $idSitesOrIdSite == 'all'; if ($allWebsitesRequested) { // First clear cache Site::clearCache(); // Then, warm the cache with only the data we should have access to if (Piwik::isUserIsSuperUser() && !TaskScheduler::isTaskBeingExecuted()) { $sites = APISitesManager::getInstance()->getAllSites(); } else { $sites = APISitesManager::getInstance()->getSitesWithAtLeastViewAccess($limit = false, $_restrictSitesToLogin); } // Both calls above have called Site::setSitesFromArray. We now get these sites: $sitesToProblablyAdd = Site::getSites(); } else { $sitesToProblablyAdd = array(APISitesManager::getInstance()->getSiteFromId($idSitesOrIdSite)); } // build the archive type used to query archive data $archive = Archive::build($idSitesOrIdSite, $period, $date, $segment, $_restrictSitesToLogin); // determine what data will be displayed $fieldsToGet = array(); $columnNameRewrites = array(); $apiECommerceMetrics = array(); $apiMetrics = 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 Set $dataTable = $archive->getDataTableFromNumeric($fieldsToGet); $dataTable = $this->mergeDataTableMapAndPopulateLabel($idSitesOrIdSite, $multipleWebsitesRequested, $dataTable); if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { $this->addMissingWebsites($table, $fieldsToGet, $sitesToProblablyAdd); } } else { $this->addMissingWebsites($dataTable, $fieldsToGet, $sitesToProblablyAdd); } // 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) = 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\Map::metadata is removed, and metadata that is // put there is put directly in DataTable::metadata. $dataTable->setMetadata(self::getLastPeriodMetadataName('date'), $lastPeriod); } $pastArchive = Archive::build($idSitesOrIdSite, $period, $strLastDate, $segment, $_restrictSitesToLogin); $pastData = $pastArchive->getDataTableFromNumeric($fieldsToGet); $pastData = $this->mergeDataTableMapAndPopulateLabel($idSitesOrIdSite, $multipleWebsitesRequested, $pastData); // 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) { if ($dataTable instanceof DataTable\Map) { foreach ($dataTable->getDataTables() as $table) { $this->removeEcommerceRelatedMetricsOnNonEcommercePiwikSites($table, $apiECommerceMetrics); } } else { $this->removeEcommerceRelatedMetricsOnNonEcommercePiwikSites($dataTable, $apiECommerceMetrics); } } // 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) { $dataTable->filter('ColumnCallbackReplace', array('label', '\\Piwik\\Site::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 // ResponseBuilder throws 'Call to a member function getColumns() on a non-object' if ($multipleWebsitesRequested && !$enhanced) { $dataTable->filter('ColumnCallbackDeleteRow', array(self::NB_VISITS_METRIC, function ($value) { return $value == 0; })); } return $dataTable; }
public function getSitesInfo($isWidgetized = false) { Piwik::checkUserHasSomeViewAccess(); $displayRevenueColumn = Common::isGoalPluginEnabled(); $date = Common::getRequestVar('date', 'today'); $period = Common::getRequestVar('period', 'day'); $siteIds = APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess(); list($minDate, $maxDate) = Site::getMinMaxDateAcrossWebsites($siteIds); // overwrites the default Date set in the parent controller // Instead of the default current website's local date, // we set "today" or "yesterday" based on the default Piwik timezone $piwikDefaultTimezone = APISitesManager::getInstance()->getDefaultTimezone(); if ($period != 'range') { $date = $this->getDateParameterInTimezone($date, $piwikDefaultTimezone); $this->setDate($date); $date = $date->toString(); } $dataTable = APIMultiSites::getInstance()->getAll($period, $date, $segment = false); // put data into a form the template will understand better $digestableData = array(); foreach ($siteIds as $idSite) { $isEcommerceEnabled = Site::isEcommerceEnabledFor($idSite); $digestableData[$idSite] = array('idsite' => $idSite, 'main_url' => Site::getMainUrlFor($idSite), 'name' => Site::getNameFor($idSite), 'visits' => 0, 'pageviews' => 0); if ($period != 'range') { $digestableData[$idSite]['visits_evolution'] = 0; $digestableData[$idSite]['pageviews_evolution'] = 0; } if ($displayRevenueColumn) { $revenueDefault = $isEcommerceEnabled ? 0 : "'-'"; if ($period != 'range') { $digestableData[$idSite]['revenue_evolution'] = $revenueDefault; } } } foreach ($dataTable->getRows() as $row) { $idsite = (int) $row->getMetadata('idsite'); $site =& $digestableData[$idsite]; $site['visits'] = (int) $row->getColumn('nb_visits'); $site['pageviews'] = (int) $row->getColumn('nb_pageviews'); if ($displayRevenueColumn) { if ($row->getColumn('revenue') !== false) { $site['revenue'] = $row->getColumn('revenue'); } } if ($period != 'range') { $site['visits_evolution'] = $row->getColumn('visits_evolution'); $site['pageviews_evolution'] = $row->getColumn('pageviews_evolution'); if ($displayRevenueColumn) { $site['revenue_evolution'] = $row->getColumn('revenue_evolution'); } } } $this->applyPrettyMoney($digestableData); $view = new View("@MultiSites/getSitesInfo"); $view->isWidgetized = $isWidgetized; $view->sitesData = array_values($digestableData); $view->evolutionBy = $this->evolutionBy; $view->period = $period; $view->page = $this->page; $view->limit = $this->limit; $view->orderBy = $this->orderBy; $view->order = $this->order; $view->totalVisits = $dataTable->getMetadata('total_nb_visits'); $view->totalRevenue = $dataTable->getMetadata('total_revenue'); $view->displayRevenueColumn = $displayRevenueColumn; $view->totalPageviews = $dataTable->getMetadata('total_nb_pageviews'); $view->pastTotalVisits = $dataTable->getMetadata('last_period_total_nb_visits'); $view->totalVisitsEvolution = $dataTable->getMetadata('total_visits_evolution'); if ($view->totalVisitsEvolution > 0) { $view->totalVisitsEvolution = '+' . $view->totalVisitsEvolution; } if ($period != 'range') { $lastPeriod = Period::factory($period, $dataTable->getMetadata('last_period_date')); $view->pastPeriodPretty = self::getCalendarPrettyDate($lastPeriod); } $params = $this->getGraphParamsModified(); $view->dateSparkline = $period == 'range' ? $date : $params['date']; $view->autoRefreshTodayReport = false; // if the current date is today, or yesterday, // in case the website is set to UTC-12), or today in UTC+14, we refresh the page every 5min if (in_array($date, array('today', date('Y-m-d'), 'yesterday', Date::factory('yesterday')->toString('Y-m-d'), Date::factory('now', 'UTC+14')->toString('Y-m-d')))) { $view->autoRefreshTodayReport = Config::getInstance()->General['multisites_refresh_after_seconds']; } $this->setGeneralVariablesView($view); $this->setMinDateView($minDate, $view); $this->setMaxDateView($maxDate, $view); $view->show_sparklines = Config::getInstance()->General['show_multisites_sparklines']; return $view->render(); }