site-accueil-insa/matomo/plugins/Insights/InsightReport.php

288 lines
11 KiB
PHP

<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\Insights;
use Piwik\DataTable;
use Piwik\Piwik;
/**
* Insight report generator
*/
class InsightReport
{
const ORDER_BY_RELATIVE = 'relative';
const ORDER_BY_ABSOLUTE = 'absolute';
const ORDER_BY_IMPORTANCE = 'importance';
/**
* @param array $reportMetadata
* @param string $period
* @param string $date
* @param string $lastDate
* @param string $metric
* @param DataTable $currentReport
* @param DataTable $lastReport
* @param int $totalValue
* @param int $lastTotalValue
* @param string $orderBy
* @param int $limitIncreaser
* @param int $limitDecreaser
* @return DataTable
*/
public function generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser)
{
$totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
$minMoversPercent = 1;
if ($totalEvolution >= 100) {
// eg change from 50 to 150 = 200%
$factor = (int) ceil($totalEvolution / 500);
$minGrowthPercentPositive = $totalEvolution + ($factor * 40); // min +240%
$minGrowthPercentNegative = -70; // min -70%
$minDisappearedPercent = 8; // min 12
$minNewPercent = min(($totalEvolution / 100) * 3, 10); // min 6% = min 10 of total visits up to max 10%
} elseif ($totalEvolution >= 0) {
// eg change from 50 to 75 = 50%
$minGrowthPercentPositive = $totalEvolution + 20; // min 70%
$minGrowthPercentNegative = -1 * $minGrowthPercentPositive; // min -70%
$minDisappearedPercent = 7;
$minNewPercent = 5;
} else {
// eg change from 50 to 25 = -50%
$minGrowthPercentNegative = $totalEvolution - 20; // min -70%
$minGrowthPercentPositive = abs($minGrowthPercentNegative); // min 70%
$minDisappearedPercent = 7;
$minNewPercent = 5;
}
if ($totalValue < 200 && $totalValue != 0) {
// force at least a change of 2 visits
$minMoversPercent = (int) ceil(2 / ($totalValue / 100));
$minNewPercent = max($minNewPercent, $minMoversPercent);
$minDisappearedPercent = max($minDisappearedPercent, $minMoversPercent);
}
$dataTable = $this->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser);
$this->addMoversAndShakersMetadata($dataTable, $totalValue, $lastTotalValue);
return $dataTable;
}
/**
* Extends an already generated insight report by adding a column "isMoverAndShaker" whether a row is also a
* "Mover and Shaker" or not.
*
* Avoids the need to fetch all reports again when we already have the currentReport/lastReport
*/
public function markMoversAndShakers(DataTable $insight, $currentReport, $lastReport, $totalValue, $lastTotalValue)
{
if (!$insight->getRowsCount()) {
return;
}
$limitIncreaser = max($insight->getRowsCount(), 3);
$limitDecreaser = max($insight->getRowsCount(), 3);
$lastDate = $insight->getMetadata('lastDate');
$date = $insight->getMetadata('date');
$period = $insight->getMetadata('period');
$metric = $insight->getMetadata('metric');
$orderBy = $insight->getMetadata('orderBy');
$reportMetadata = $insight->getMetadata('report');
$shakers = $this->generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser);
foreach ($insight->getRows() as $row) {
$label = $row->getColumn('label');
if ($shakers->getRowFromLabel($label)) {
$row->setColumn('isMoverAndShaker', true);
} else {
$row->setColumn('isMoverAndShaker', false);
}
}
$this->addMoversAndShakersMetadata($insight, $totalValue, $lastTotalValue);
}
/**
* @param array $reportMetadata
* @param string $period
* @param string $date
* @param string $lastDate
* @param string $metric
* @param DataTable $currentReport
* @param DataTable $lastReport
* @param int $totalValue
* @param int $minMoversPercent Exclude rows who moved and the difference is not at least min percent
* visits of totalVisits. -1 excludes movers.
* @param int $minNewPercent Exclude rows who are new and the difference is not at least min percent
* visits of totalVisits. -1 excludes all new.
* @param int $minDisappearedPercent Exclude rows who are disappeared and the difference is not at least min
* percent visits of totalVisits. -1 excludes all disappeared.
* @param int $minGrowthPercentPositive The actual growth of a row must be at least percent compared to the
* previous value (not total value)
* @param int $minGrowthPercentNegative The actual growth of a row must be lower percent compared to the
* previous value (not total value)
* @param string $orderBy Order by absolute, relative, importance
* @param int $limitIncreaser
* @param int $limitDecreaser
*
* @return DataTable
*/
public function generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser)
{
$minChangeMovers = $this->getMinVisits($totalValue, $minMoversPercent);
$minIncreaseNew = $this->getMinVisits($totalValue, $minNewPercent);
$minDecreaseDisappeared = $this->getMinVisits($totalValue, $minDisappearedPercent);
$dataTable = new DataTable();
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\Insight',
array(
$currentReport,
$lastReport,
$metric,
$considerMovers = (-1 !== $minMoversPercent),
$considerNew = (-1 !== $minNewPercent),
$considerDisappeared = (-1 !== $minDisappearedPercent)
)
);
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth',
array(
'growth_percent_numeric',
$minGrowthPercentPositive,
$minGrowthPercentNegative
)
);
if ($minIncreaseNew) {
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
array(
'difference',
$minIncreaseNew,
'isNew'
)
);
}
if ($minChangeMovers) {
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
array(
'difference',
$minChangeMovers,
'isMover'
)
);
}
if ($minDecreaseDisappeared) {
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
array(
'difference',
$minDecreaseDisappeared,
'isDisappeared'
)
);
}
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\OrderBy',
array(
$this->getOrderByColumn($orderBy),
$orderBy === self::ORDER_BY_RELATIVE ? $this->getOrderByColumn(self::ORDER_BY_ABSOLUTE) : $this->getOrderByColumn(self::ORDER_BY_RELATIVE),
$metric
)
);
$dataTable->filter(
'Piwik\Plugins\Insights\DataTable\Filter\Limit',
array(
'growth_percent_numeric',
$limitIncreaser,
$limitDecreaser
)
);
$metricName = $metric;
if (!empty($reportMetadata['metrics'][$metric])) {
$metricName = $reportMetadata['metrics'][$metric];
}
$dataTable->setMetadataValues(array(
'reportName' => $reportMetadata['name'],
'metricName' => $metricName,
'date' => $date,
'lastDate' => $lastDate,
'period' => $period,
'report' => $reportMetadata,
'totalValue' => $totalValue,
'orderBy' => $orderBy,
'metric' => $metric,
'minChangeMovers' => $minChangeMovers,
'minIncreaseNew' => $minIncreaseNew,
'minDecreaseDisappeared' => $minDecreaseDisappeared,
'minGrowthPercentPositive' => $minGrowthPercentPositive,
'minGrowthPercentNegative' => $minGrowthPercentNegative,
'minMoversPercent' => $minMoversPercent,
'minNewPercent' => $minNewPercent,
'minDisappearedPercent' => $minDisappearedPercent
));
return $dataTable;
}
private function getOrderByColumn($orderBy)
{
if (self::ORDER_BY_RELATIVE == $orderBy) {
$orderByColumn = 'growth_percent_numeric';
} elseif (self::ORDER_BY_ABSOLUTE == $orderBy) {
$orderByColumn = 'difference';
} elseif (self::ORDER_BY_IMPORTANCE == $orderBy) {
$orderByColumn = 'importance';
} else {
throw new \Exception('Unsupported orderBy');
}
return $orderByColumn;
}
private function getMinVisits($totalValue, $percent)
{
if ($percent <= 0) {
return 0;
}
$minVisits = ceil(($totalValue / 100) * $percent);
return (int) $minVisits;
}
private function addMoversAndShakersMetadata(DataTable $dataTable, $totalValue, $lastTotalValue)
{
$totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
$dataTable->setMetadata('lastTotalValue', $lastTotalValue);
$dataTable->setMetadata('evolutionTotal', $totalEvolution);
$dataTable->setMetadata('evolutionDifference', $totalValue - $lastTotalValue);
}
private function getTotalEvolution($totalValue, $lastTotalValue)
{
return Piwik::getPercentageSafe($totalValue - $lastTotalValue, $lastTotalValue, 1);
}
}