قرینه از
https://github.com/matomo-org/matomo.git
synced 2025-08-22 06:57:53 +00:00

* [Coding Style] Enable rule PSR12.Files.FileHeader * Apply CS * Replace Piwik with Matomo in file headers * Unify file headers (position, no. of lines, https links) * Rebuild dist files * Apply CS * Fix system test that relies on line numbers in a file that had the file header updated --------- Co-authored-by: Stefan Giehl <stefan@matomo.org>
196 خطوط
7.2 KiB
PHP
196 خطوط
7.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
namespace Piwik\Plugins\UserCountry\RecordBuilders;
|
|
|
|
use Piwik\ArchiveProcessor;
|
|
use Piwik\ArchiveProcessor\Record;
|
|
use Piwik\ArchiveProcessor\RecordBuilder;
|
|
use Piwik\Config as PiwikConfig;
|
|
use Piwik\DataTable;
|
|
use Piwik\DataAccess\LogAggregator;
|
|
use Piwik\Metrics;
|
|
use Piwik\Plugins\UserCountry\Archiver;
|
|
use Piwik\Plugins\UserCountry\LocationProvider;
|
|
|
|
class Locations extends RecordBuilder
|
|
{
|
|
protected $dimensions = [
|
|
Archiver::COUNTRY_RECORD_NAME => Archiver::COUNTRY_FIELD,
|
|
Archiver::REGION_RECORD_NAME => Archiver::REGION_FIELD,
|
|
Archiver::CITY_RECORD_NAME => Archiver::CITY_FIELD,
|
|
];
|
|
|
|
private $latLongForCities = [];
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->columnToSortByBeforeTruncation = Metrics::INDEX_NB_VISITS;
|
|
}
|
|
|
|
public function getRecordMetadata(ArchiveProcessor $archiveProcessor): array
|
|
{
|
|
$maxRowsInTable = PiwikConfig::getInstance()->General['datatable_archiving_maximum_rows_standard'];
|
|
|
|
return [
|
|
Record::make(Record::TYPE_BLOB, Archiver::COUNTRY_RECORD_NAME),
|
|
Record::make(Record::TYPE_BLOB, Archiver::REGION_RECORD_NAME)
|
|
->setMaxRowsInTable($maxRowsInTable),
|
|
Record::make(Record::TYPE_BLOB, Archiver::CITY_RECORD_NAME)
|
|
->setMaxRowsInTable($maxRowsInTable),
|
|
|
|
Record::make(Record::TYPE_NUMERIC, Archiver::DISTINCT_COUNTRIES_METRIC)
|
|
->setIsCountOfBlobRecordRows(Archiver::COUNTRY_RECORD_NAME),
|
|
];
|
|
}
|
|
|
|
protected function aggregate(ArchiveProcessor $archiveProcessor): array
|
|
{
|
|
try {
|
|
/** @var DataTable[] $records */
|
|
$records = [];
|
|
foreach ($this->dimensions as $recordName => $dimension) {
|
|
$records[$recordName] = new DataTable();
|
|
}
|
|
|
|
$logAggregator = $archiveProcessor->getLogAggregator();
|
|
|
|
$this->aggregateFromVisits($records, $logAggregator);
|
|
$this->aggregateFromConversions($records, $logAggregator);
|
|
|
|
$this->setLatitudeLongitude($records[Archiver::CITY_RECORD_NAME]);
|
|
|
|
$records[Archiver::DISTINCT_COUNTRIES_METRIC] = $records[Archiver::COUNTRY_RECORD_NAME]->getRowsCount();
|
|
|
|
return $records;
|
|
} finally {
|
|
unset($this->latLongForCities);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param DataTable[] $records
|
|
*/
|
|
protected function aggregateFromVisits(array $records, LogAggregator $logAggregator): void
|
|
{
|
|
$additionalSelects = array('MAX(log_visit.location_latitude) as location_latitude',
|
|
'MAX(log_visit.location_longitude) as location_longitude');
|
|
$query = $logAggregator->queryVisitsByDimension(array_values($this->dimensions), $where = false, $additionalSelects);
|
|
if ($query === false) {
|
|
return;
|
|
}
|
|
|
|
while ($row = $query->fetch()) {
|
|
$this->makeRegionCityLabelsUnique($row);
|
|
$this->rememberCityLatLong($row);
|
|
|
|
$columns = [
|
|
Metrics::INDEX_NB_UNIQ_VISITORS => $row[Metrics::INDEX_NB_UNIQ_VISITORS],
|
|
Metrics::INDEX_NB_VISITS => $row[Metrics::INDEX_NB_VISITS],
|
|
Metrics::INDEX_NB_ACTIONS => $row[Metrics::INDEX_NB_ACTIONS],
|
|
Metrics::INDEX_NB_USERS => $row[Metrics::INDEX_NB_USERS],
|
|
Metrics::INDEX_MAX_ACTIONS => $row[Metrics::INDEX_MAX_ACTIONS],
|
|
Metrics::INDEX_SUM_VISIT_LENGTH => $row[Metrics::INDEX_SUM_VISIT_LENGTH],
|
|
Metrics::INDEX_BOUNCE_COUNT => $row[Metrics::INDEX_BOUNCE_COUNT],
|
|
Metrics::INDEX_NB_VISITS_CONVERTED => $row[Metrics::INDEX_NB_VISITS_CONVERTED],
|
|
];
|
|
|
|
foreach ($records as $recordName => $dataTable) {
|
|
$dimension = $this->dimensions[$recordName];
|
|
$dataTable->sumRowWithLabel($row[$dimension], $columns);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes sure the region and city of a query row are unique.
|
|
*
|
|
* @param array $row
|
|
*/
|
|
private function makeRegionCityLabelsUnique(array &$row): void
|
|
{
|
|
// remove the location separator from the region/city/country we get from the query
|
|
foreach ($this->dimensions as $column) {
|
|
$row[$column] = str_replace(Archiver::LOCATION_SEPARATOR, '', $row[$column] ?? '');
|
|
}
|
|
|
|
// set city first, as containing region might be manipulated afterwards if not empty
|
|
if (!empty($row[Archiver::CITY_FIELD])) {
|
|
$row[Archiver::CITY_FIELD] = $row[Archiver::CITY_FIELD] . Archiver::LOCATION_SEPARATOR . $row[Archiver::REGION_FIELD] . Archiver::LOCATION_SEPARATOR . $row[Archiver::COUNTRY_FIELD];
|
|
}
|
|
|
|
if (!empty($row[Archiver::REGION_FIELD])) {
|
|
$row[Archiver::REGION_FIELD] = $row[Archiver::REGION_FIELD] . Archiver::LOCATION_SEPARATOR . $row[Archiver::COUNTRY_FIELD];
|
|
}
|
|
}
|
|
|
|
protected function rememberCityLatLong(array $row): void
|
|
{
|
|
if (
|
|
!empty($row[Archiver::CITY_FIELD])
|
|
&& !empty($row[Archiver::LATITUDE_FIELD])
|
|
&& !empty($row[Archiver::LONGITUDE_FIELD])
|
|
&& empty($this->latLongForCities[$row[Archiver::CITY_FIELD]])
|
|
) {
|
|
$this->latLongForCities[$row[Archiver::CITY_FIELD]] = array($row[Archiver::LATITUDE_FIELD], $row[Archiver::LONGITUDE_FIELD]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param DataTable[] $records
|
|
*/
|
|
protected function aggregateFromConversions(array $records, LogAggregator $logAggregator): void
|
|
{
|
|
$query = $logAggregator->queryConversionsByDimension(array_values($this->dimensions));
|
|
|
|
while ($row = $query->fetch()) {
|
|
$this->makeRegionCityLabelsUnique($row);
|
|
|
|
foreach ($records as $recordName => $table) {
|
|
$idGoal = (int) $row['idgoal'];
|
|
$columns = [
|
|
Metrics::INDEX_GOALS => [
|
|
$idGoal => Metrics::makeGoalColumnsRow($idGoal, $row),
|
|
],
|
|
];
|
|
|
|
$dimension = $this->dimensions[$recordName];
|
|
$table->sumRowWithLabel($row[$dimension], $columns);
|
|
}
|
|
}
|
|
|
|
foreach ($records as $table) {
|
|
$table->filter(DataTable\Filter\EnrichRecordWithGoalMetricSums::class);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility method, appends latitude/longitude pairs to city table labels, if that data
|
|
* exists for the city.
|
|
*/
|
|
private function setLatitudeLongitude(DataTable $tableCity): void
|
|
{
|
|
foreach ($tableCity->getRows() as $row) {
|
|
$label = $row->getColumn('label');
|
|
if (isset($this->latLongForCities[$label])) {
|
|
// get lat/long for city
|
|
list($lat, $long) = $this->latLongForCities[$label];
|
|
$lat = round($lat, LocationProvider::GEOGRAPHIC_COORD_PRECISION);
|
|
$long = round($long, LocationProvider::GEOGRAPHIC_COORD_PRECISION);
|
|
|
|
// set latitude + longitude metadata
|
|
$row->setMetadata('lat', $lat);
|
|
$row->setMetadata('long', $long);
|
|
}
|
|
}
|
|
}
|
|
}
|