PDF rausgenommen
This commit is contained in:
352
msd2/tracking/piwik/plugins/MultiSites/Dashboard.php
Normal file
352
msd2/tracking/piwik/plugins/MultiSites/Dashboard.php
Normal file
@ -0,0 +1,352 @@
|
||||
<?php
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\MultiSites;
|
||||
|
||||
use Piwik\API\DataTablePostProcessor;
|
||||
use Piwik\API\Request;
|
||||
use Piwik\API\ResponseBuilder;
|
||||
use Piwik\Config;
|
||||
use Piwik\Metrics\Formatter;
|
||||
use Piwik\NumberFormatter;
|
||||
use Piwik\Period;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Row;
|
||||
use Piwik\DataTable\Row\DataTableSummaryRow;
|
||||
use Piwik\Site;
|
||||
use Piwik\View;
|
||||
|
||||
/**
|
||||
* Fetches and formats the response of `MultiSites.getAll` in a way that it can be used by the All Websites AngularJS
|
||||
* widget. Eg sites are moved into groups if one is assigned, stats are calculated for groups, etc.
|
||||
*/
|
||||
class Dashboard
|
||||
{
|
||||
/** @var DataTable */
|
||||
private $sitesByGroup;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $numSites = 0;
|
||||
|
||||
/**
|
||||
* Array of metrics that will be displayed and will be number formatted
|
||||
* @var array
|
||||
*/
|
||||
private $displayedMetricColumns = array('nb_visits', 'nb_pageviews', 'nb_actions', 'revenue');
|
||||
|
||||
/**
|
||||
* @param string $period
|
||||
* @param string $date
|
||||
* @param string|false $segment
|
||||
*/
|
||||
public function __construct($period, $date, $segment)
|
||||
{
|
||||
$sites = Request::processRequest('MultiSites.getAll', [
|
||||
'period' => $period,
|
||||
'date' => $date,
|
||||
'segment' => $segment,
|
||||
'enhanced' => '1',
|
||||
// NOTE: have to select everything since with queued filters disabled some metrics won't be renamed to
|
||||
// their display name, and so showColumns will end up removing those.
|
||||
'showColumns' => '',
|
||||
'disable_queued_filters' => '1',
|
||||
'filter_limit' => '-1',
|
||||
'filter_offset' => '0',
|
||||
'totals' => 0
|
||||
], $default = []);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
public function setSitesTable(DataTable $sites)
|
||||
{
|
||||
$this->sitesByGroup = $this->moveSitesHavingAGroupIntoSubtables($sites);
|
||||
$this->rememberNumberOfSites();
|
||||
}
|
||||
|
||||
public function getSites($request, $limit)
|
||||
{
|
||||
$request['filter_limit'] = $limit;
|
||||
$request['filter_offset'] = isset($request['filter_offset']) ? $request['filter_offset'] : 0;
|
||||
|
||||
$this->makeSitesFlatAndApplyGenericFilters($this->sitesByGroup, $request);
|
||||
$sites = $this->convertDataTableToArrayAndApplyQueuedFilters($this->sitesByGroup, $request);
|
||||
$sites = $this->enrichValues($sites);
|
||||
|
||||
return $sites;
|
||||
}
|
||||
|
||||
public function getTotals()
|
||||
{
|
||||
$totals = array(
|
||||
'nb_pageviews' => $this->sitesByGroup->getMetadata('total_nb_pageviews'),
|
||||
'nb_visits' => $this->sitesByGroup->getMetadata('total_nb_visits'),
|
||||
'nb_actions' => $this->sitesByGroup->getMetadata('total_nb_actions'),
|
||||
'revenue' => $this->sitesByGroup->getMetadata('total_revenue'),
|
||||
'nb_visits_lastdate' => $this->sitesByGroup->getMetadata('total_nb_visits_lastdate') ? : 0,
|
||||
);
|
||||
$this->formatMetrics($totals);
|
||||
return $totals;
|
||||
}
|
||||
|
||||
private function formatMetrics(&$metrics)
|
||||
{
|
||||
$formatter = NumberFormatter::getInstance();
|
||||
foreach($metrics as $metricName => &$value) {
|
||||
if(in_array($metricName, $this->displayedMetricColumns)) {
|
||||
|
||||
if( strpos($metricName, 'revenue') !== false) {
|
||||
$currency = isset($metrics['idsite']) ? Site::getCurrencySymbolFor($metrics['idsite']) : '';
|
||||
$value = $formatter->formatCurrency($value, $currency);
|
||||
continue;
|
||||
}
|
||||
$value = $formatter->format($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getNumSites()
|
||||
{
|
||||
return $this->numSites;
|
||||
}
|
||||
|
||||
public function search($pattern)
|
||||
{
|
||||
$this->nestedSearch($this->sitesByGroup, $pattern);
|
||||
$this->rememberNumberOfSites();
|
||||
}
|
||||
|
||||
private function rememberNumberOfSites()
|
||||
{
|
||||
$this->numSites = $this->sitesByGroup->getRowsCountRecursive();
|
||||
}
|
||||
|
||||
private function nestedSearch(DataTable $sitesByGroup, $pattern)
|
||||
{
|
||||
foreach ($sitesByGroup->getRows() as $index => $site) {
|
||||
|
||||
$label = strtolower($site->getColumn('label'));
|
||||
$labelMatches = false !== strpos($label, $pattern);
|
||||
|
||||
if ($site->getMetadata('isGroup')) {
|
||||
$subtable = $site->getSubtable();
|
||||
$this->nestedSearch($subtable, $pattern);
|
||||
|
||||
if (!$labelMatches && !$subtable->getRowsCount()) {
|
||||
// we keep the group if at least one site within the group matches the pattern
|
||||
$sitesByGroup->deleteRow($index);
|
||||
}
|
||||
|
||||
} elseif (!$labelMatches) {
|
||||
$group = $site->getMetadata('group');
|
||||
|
||||
if (!$group || false === strpos(strtolower($group), $pattern)) {
|
||||
$sitesByGroup->deleteRow($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLastDate()
|
||||
{
|
||||
$lastPeriod = $this->sitesByGroup->getMetadata('last_period_date');
|
||||
|
||||
if (!empty($lastPeriod)) {
|
||||
$lastPeriod = $lastPeriod->toString();
|
||||
} else {
|
||||
$lastPeriod = '';
|
||||
}
|
||||
|
||||
return $lastPeriod;
|
||||
}
|
||||
|
||||
private function convertDataTableToArrayAndApplyQueuedFilters(DataTable $table, $request)
|
||||
{
|
||||
$request['serialize'] = 0;
|
||||
$request['expanded'] = 0;
|
||||
$request['totals'] = 0;
|
||||
$request['format_metrics'] = 1;
|
||||
$request['disable_generic_filters'] = 1;
|
||||
|
||||
$responseBuilder = new ResponseBuilder('php', $request);
|
||||
$rows = $responseBuilder->getResponse($table, 'MultiSites', 'getAll');
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private function moveSitesHavingAGroupIntoSubtables(DataTable $sites)
|
||||
{
|
||||
/** @var DataTableSummaryRow[] $groups */
|
||||
$groups = array();
|
||||
|
||||
$sitesByGroup = $this->makeCloneOfDataTableSites($sites);
|
||||
$sitesByGroup->enableRecursiveFilters(); // we need to make sure filters get applied to subtables (groups)
|
||||
|
||||
foreach ($sites->getRows() as $site) {
|
||||
|
||||
$group = $site->getMetadata('group');
|
||||
|
||||
if (!empty($group) && !array_key_exists($group, $groups)) {
|
||||
$row = new DataTableSummaryRow();
|
||||
$row->setColumn('label', $group);
|
||||
$row->setMetadata('isGroup', 1);
|
||||
$row->setSubtable($this->createGroupSubtable($sites));
|
||||
$sitesByGroup->addRow($row);
|
||||
|
||||
$groups[$group] = $row;
|
||||
}
|
||||
|
||||
if (!empty($group)) {
|
||||
$groups[$group]->getSubtable()->addRow($site);
|
||||
} else {
|
||||
$sitesByGroup->addRow($site);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($groups as $group) {
|
||||
// we need to recalculate as long as all rows are there, as soon as some rows are removed
|
||||
// we can no longer recalculate the correct value. We might even calculate values for groups
|
||||
// that are not returned. If this becomes a problem we need to keep a copy of this to recalculate
|
||||
// only actual returned groups.
|
||||
$group->recalculate();
|
||||
}
|
||||
|
||||
return $sitesByGroup;
|
||||
}
|
||||
|
||||
private function createGroupSubtable(DataTable $sites)
|
||||
{
|
||||
$table = new DataTable();
|
||||
$processedMetrics = $sites->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME);
|
||||
$table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $processedMetrics);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function makeCloneOfDataTableSites(DataTable $sites)
|
||||
{
|
||||
$sitesByGroup = $sites->getEmptyClone(true);
|
||||
// we handle them ourselves for faster performance etc. This way we also avoid to apply them twice.
|
||||
$sitesByGroup->disableFilter('ColumnCallbackReplace');
|
||||
$sitesByGroup->disableFilter('MetadataCallbackAddMetadata');
|
||||
|
||||
return $sitesByGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure to not have any subtables anymore.
|
||||
*
|
||||
* So if $table is
|
||||
* array(
|
||||
* site1
|
||||
* site2
|
||||
* subtable => site3
|
||||
* site4
|
||||
* site5
|
||||
* site6
|
||||
* site7
|
||||
* )
|
||||
*
|
||||
* it will return
|
||||
*
|
||||
* array(
|
||||
* site1
|
||||
* site2
|
||||
* site3
|
||||
* site4
|
||||
* site5
|
||||
* site6
|
||||
* site7
|
||||
* )
|
||||
*
|
||||
* in a sorted order
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @param array $request
|
||||
*/
|
||||
private function makeSitesFlatAndApplyGenericFilters(DataTable $table, $request)
|
||||
{
|
||||
// we handle limit here as we have to apply sort filter, then make sites flat, then apply limit filter.
|
||||
$filterOffset = $request['filter_offset'];
|
||||
$filterLimit = $request['filter_limit'];
|
||||
unset($request['filter_offset']);
|
||||
unset($request['filter_limit']);
|
||||
|
||||
// filter_sort_column does not work correctly is a bug in MultiSites.getAll
|
||||
if (!empty($request['filter_sort_column']) && $request['filter_sort_column'] === 'nb_pageviews') {
|
||||
$request['filter_sort_column'] = 'Actions_nb_pageviews';
|
||||
} elseif (!empty($request['filter_sort_column']) && $request['filter_sort_column'] === 'revenue') {
|
||||
$request['filter_sort_column'] = 'Goal_revenue';
|
||||
}
|
||||
|
||||
// make sure no limit filter is applied, we will do this manually
|
||||
$table->disableFilter('Limit');
|
||||
|
||||
// this will apply the sort filter
|
||||
/** @var DataTable $table */
|
||||
$genericFilter = new DataTablePostProcessor('MultiSites', 'getAll', $request);
|
||||
$table = $genericFilter->applyGenericFilters($table);
|
||||
|
||||
// make sure from now on the sites will be no longer sorted, they were already sorted
|
||||
$table->disableFilter('Sort');
|
||||
|
||||
// make sites flat and limit
|
||||
$table->filter('Piwik\Plugins\MultiSites\DataTable\Filter\NestedSitesLimiter', array($filterOffset, $filterLimit));
|
||||
}
|
||||
|
||||
private function enrichValues($sites)
|
||||
{
|
||||
foreach ($sites as &$site) {
|
||||
if (!isset($site['idsite'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$site['main_url'] = Site::getMainUrlFor($site['idsite']);
|
||||
|
||||
$this->formatMetrics($site);
|
||||
}
|
||||
|
||||
return $sites;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user