| Server IP : 213.186.33.4 / Your IP : 216.73.216.193 Web Server : Apache System : Linux webm006.cluster103.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 User : awebpaca ( 35430) PHP Version : 8.5.0 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/awebpaca/piwik/plugins/API/Filter/DataComparisonFilter/ |
Upload File : |
<?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\API\Filter\DataComparisonFilter;
use Piwik\DataTable;
use Piwik\DataTable\DataTableInterface;
use Piwik\DataTable\Simple;
use Piwik\Metrics;
use Piwik\Period;
use Piwik\Segment;
use Piwik\Segment\SegmentExpression;
class ComparisonRowGenerator
{
/**
* @var bool
*/
private $isRequestMultiplePeriod;
/**
* @var string
*/
private $segmentNameForReport;
/**
* @var array
*/
private $columnMappings;
public function __construct($segmentNameForReport, $isRequestMultiplePeriod, $columnMappings)
{
$this->segmentNameForReport = $segmentNameForReport;
$this->isRequestMultiplePeriod = $isRequestMultiplePeriod;
$this->columnMappings = $columnMappings;
}
public function compareTables($compareMetadata, DataTableInterface $tables, DataTableInterface $compareTables = null)
{
if ($tables instanceof DataTable) {
$this->compareTable($compareMetadata, $tables, $compareTables, $compareTables);
} else if ($tables instanceof DataTable\Map) {
$childTablesArray = array_values($tables->getDataTables());
$compareTablesArray = isset($compareTables) ? array_values($compareTables->getDataTables()) : [];
$isDatePeriod = $tables->getKeyName() == 'date';
foreach ($childTablesArray as $index => $childTable) {
$compareChildTable = isset($compareTablesArray[$index]) ? $compareTablesArray[$index] : null;
$this->compareTables($compareMetadata, $childTable, $compareChildTable);
}
// in case one of the compared periods has more periods than the main one, we want to fill the result with empty datatables
// so the comparison data is still present. this allows us to see that data in an evolution report.
if ($isDatePeriod) {
$lastTable = end($childTablesArray);
/** @var Period $lastPeriod */
$lastPeriod = $lastTable->getMetadata('period');
$periodType = $lastPeriod->getLabel();
for ($i = count($childTablesArray); $i < count($compareTablesArray); ++$i) {
$periodChangeCount = $i - count($childTablesArray) + 1;
$newPeriod = Period\Factory::build($periodType, $lastPeriod->getDateStart()->addPeriod($periodChangeCount, $periodType));
// create an empty table for the main request
$newTable = new DataTable();
$newTable->setAllTableMetadata($lastTable->getAllTableMetadata());
$newTable->setMetadata('period', $newPeriod);
if ($newPeriod->getLabel() === 'week' || $newPeriod->getLabel() === 'range') {
$periodLabel = $newPeriod->getRangeString();
} else {
$periodLabel = $newPeriod->getPrettyString();
}
$tables->addTable($newTable, $periodLabel);
// compare with the empty table
$compareTable = $compareTablesArray[$i];
$this->compareTables($compareMetadata, $newTable, $compareTable);
}
}
} else {
throw new \Exception("Unexpected DataTable type: " . get_class($tables));
}
}
private function compareTable($compareMetadata, DataTable $table, DataTable $rootCompareTable = null, DataTable $compareTable = null)
{
// if there are no rows in the table because the metrics are 0, add one so we can still set comparison values
if ($table->getRowsCount() == 0) {
$table->addRow(new DataTable\Row());
}
foreach ($table->getRows() as $row) {
$label = $row->getColumn('label');
$compareRow = null;
if ($compareTable instanceof Simple) {
$compareRow = $compareTable->getFirstRow() ?: null;
} else if ($compareTable instanceof DataTable) {
$compareRow = $compareTable->getRowFromLabel($label) ?: null;
}
$this->compareRow($table, $compareMetadata, $row, $compareRow, $rootCompareTable);
}
$totalsRow = $table->getTotalsRow();
if (!empty($totalsRow)) {
$compareRow = $compareTable ? $compareTable->getTotalsRow() : null;
$this->compareRow($table, $compareMetadata, $totalsRow, $compareRow, $rootCompareTable);
}
if ($compareTable) {
$totals = $compareTable->getMetadata('totals');
if (!empty($totals)) {
$totals = $this->replaceIndexesInTotals($totals);
$comparisonTotalsEntry = array_merge($compareMetadata, [
'totals' => $totals,
]);
$allTotalsTables = $table->getMetadata('comparisonTotals');
$allTotalsTables[] = $comparisonTotalsEntry;
$table->setMetadata('comparisonTotals', $allTotalsTables);
}
}
}
private function compareRow(DataTable $table, $compareMetadata, DataTable\Row $row, DataTable\Row $compareRow = null, DataTable $rootTable = null)
{
$comparisonDataTable = $row->getComparisons();
if (empty($comparisonDataTable)) {
$comparisonDataTable = new DataTable();
$comparisonDataTable->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME,
$table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME));
$row->setComparisons($comparisonDataTable);
}
$this->addIndividualChildPrettifiedMetadata($compareMetadata, $rootTable);
$columns = [];
if ($compareRow) {
foreach ($compareRow as $name => $value) {
if (!is_numeric($value)
|| $name == 'label'
) {
continue;
}
$columns[$name] = $value;
}
} else {
foreach ($row as $name => $value) {
if (!is_numeric($value)
|| $name == 'label'
) {
continue;
}
$columns[$name] = 0;
}
}
$newRow = new DataTable\Row([
DataTable\Row::COLUMNS => $columns,
DataTable\Row::METADATA => $compareMetadata,
]);
// set subtable
$newRow->setMetadata('idsubdatatable', -1);
if ($compareRow) {
$subtableId = $compareRow->getMetadata('idsubdatatable_in_db') ?: $compareRow->getIdSubDataTable();
if ($subtableId) {
$newRow->setMetadata('idsubdatatable', $subtableId);
}
}
// add segment metadatas
if ($row->getMetadata('segment')) {
$newSegment = $row->getMetadata('segment');
if ($newRow->getMetadata('compareSegment')) {
$newSegment = Segment::combine($newRow->getMetadata('compareSegment'), SegmentExpression::AND_DELIMITER, $newSegment);
}
$newRow->setMetadata('segment', $newSegment);
} else if ($this->segmentNameForReport
&& $row->getMetadata('segmentValue') !== false
) {
$segmentValue = $row->getMetadata('segmentValue');
$newRow->setMetadata('segment', sprintf('%s==%s', $this->segmentNameForReport, urlencode($segmentValue)));
}
$comparisonDataTable->addRow($newRow);
// recurse on subtable if there
$subtable = $row->getSubtable();
$compareSubTable = $compareRow ? $compareRow->getSubtable() : null;
if ($subtable && $compareSubTable) {
$this->compareTable($compareMetadata, $subtable, $rootTable, $compareSubTable);
}
}
private function addIndividualChildPrettifiedMetadata(array &$metadata, DataTable $parentTable = null)
{
if ($parentTable
&& $this->isRequestMultiplePeriod
) {
/** @var Period $period */
$period = $parentTable->getMetadata('period');
if (empty($period)) {
return;
}
$prettyPeriod = $period->getLocalizedLongString();
$metadata['comparePeriodPretty'] = ucfirst($prettyPeriod);
$metadata['comparePeriod'] = $period->getLabel();
$metadata['compareDate'] = $period->getDateStart()->toString();
}
}
private function replaceIndexesInTotals($totals)
{
foreach ($totals as $index => $value) {
if (isset($this->columnMappings[$index])) {
$name = $this->columnMappings[$index];
$totals[$name] = $totals[$index];
unset($totals[$index]);
}
}
return $totals;
}
}