site-accueil-insa/matomo/plugins/Events/Archiver.php

266 lines
9.5 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\Events;
use Piwik\Config;
use Piwik\DataArray;
use Piwik\Metrics;
use Piwik\Plugins\Actions\ArchivingHelper;
use Piwik\RankingQuery;
use Piwik\Tracker\Action;
/**
* Processing reports for Events
EVENT
- Category
- Action
- Name
- Value
METRICS (Events Overview report)
- Total number of events
- Unique events
- Visits with events
- Events/visit
- Event value
- Average event value AVG(custom_float)
MAIN REPORTS:
- Top Event Category (total events, unique events, event value, avg+min+max value)
- Top Event Action (total events, unique events, event value, avg+min+max value)
- Top Event Name (total events, unique events, event value, avg+min+max value)
COMPOSED REPORTS
- Top Category > Actions X
- Top Category > Names X
- Top Actions > Categories X
- Top Actions > Names X
- Top Names > Actions X
- Top Names > Categories X
UI
- Overview at the top (graph + Sparklines)
- Below show the left menu, defaults to Top Event Category
Not MVP:
- On hover on any row: Show % of total events
- Add min value metric, max value metric in tooltip
- List event scope Custom Variables Names > Custom variables values > Event Names > Event Actions
- List event scope Custom Variables Value > Event Category > Event Names > Event Actions
NOTES:
- For a given Name, Category is often constant
*/
class Archiver extends \Piwik\Plugin\Archiver
{
const EVENTS_CATEGORY_ACTION_RECORD_NAME = 'Events_category_action';
const EVENTS_CATEGORY_NAME_RECORD_NAME = 'Events_category_name';
const EVENTS_ACTION_CATEGORY_RECORD_NAME = 'Events_action_category';
const EVENTS_ACTION_NAME_RECORD_NAME = 'Events_action_name';
const EVENTS_NAME_ACTION_RECORD_NAME = 'Events_name_action';
const EVENTS_NAME_CATEGORY_RECORD_NAME = 'Events_name_category';
const EVENT_NAME_NOT_SET = 'Piwik_EventNameNotSet';
/**
* @var DataArray[]
*/
protected $arrays = array();
function __construct($processor)
{
parent::__construct($processor);
$this->columnToSortByBeforeTruncation = Metrics::INDEX_NB_VISITS;
$this->maximumRowsInDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_events'];
$this->maximumRowsInSubDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_events'];
}
protected function getRecordToDimensions()
{
return array(
self::EVENTS_CATEGORY_ACTION_RECORD_NAME => array("eventCategory", "eventAction"),
self::EVENTS_CATEGORY_NAME_RECORD_NAME => array("eventCategory", "eventName"),
self::EVENTS_ACTION_NAME_RECORD_NAME => array("eventAction", "eventName"),
self::EVENTS_ACTION_CATEGORY_RECORD_NAME => array("eventAction", "eventCategory"),
self::EVENTS_NAME_ACTION_RECORD_NAME => array("eventName", "eventAction"),
self::EVENTS_NAME_CATEGORY_RECORD_NAME => array("eventName", "eventCategory"),
);
}
public function aggregateMultipleReports()
{
$dataTableToSum = $this->getRecordNames();
$columnsAggregationOperation = array(
Metrics::INDEX_EVENT_MIN_EVENT_VALUE => 'min',
Metrics::INDEX_EVENT_MAX_EVENT_VALUE => 'max',
);
$this->getProcessor()->aggregateDataTableRecords(
$dataTableToSum,
$this->maximumRowsInDataTable,
$this->maximumRowsInSubDataTable,
$this->columnToSortByBeforeTruncation,
$columnsAggregationOperation,
$columnsToRenameAfterAggregation = null,
$countRowsRecursive = array());
}
protected function getRecordNames()
{
$mapping = $this->getRecordToDimensions();
return array_keys($mapping);
}
public function aggregateDayReport()
{
$this->aggregateDayEvents();
$this->insertDayReports();
}
protected function aggregateDayEvents()
{
$select = "
log_action_event_category.name as eventCategory,
log_action_event_action.name as eventAction,
log_action_event_name.name as eventName,
count(distinct log_link_visit_action.idvisit) as `" . Metrics::INDEX_NB_VISITS . "`,
count(distinct log_link_visit_action.idvisitor) as `" . Metrics::INDEX_NB_UNIQ_VISITORS . "`,
count(*) as `" . Metrics::INDEX_EVENT_NB_HITS . "`,
sum(
case when " . Action::DB_COLUMN_CUSTOM_FLOAT . " is null
then 0
else " . Action::DB_COLUMN_CUSTOM_FLOAT . "
end
) as `" . Metrics::INDEX_EVENT_SUM_EVENT_VALUE . "`,
sum( case when " . Action::DB_COLUMN_CUSTOM_FLOAT . " is null then 0 else 1 end )
as `" . Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE . "`,
min(" . Action::DB_COLUMN_CUSTOM_FLOAT . ") as `" . Metrics::INDEX_EVENT_MIN_EVENT_VALUE . "`,
max(" . Action::DB_COLUMN_CUSTOM_FLOAT . ") as `" . Metrics::INDEX_EVENT_MAX_EVENT_VALUE . "`
";
$from = array(
"log_link_visit_action",
array(
"table" => "log_action",
"tableAlias" => "log_action_event_category",
"joinOn" => "log_link_visit_action.idaction_event_category = log_action_event_category.idaction"
),
array(
"table" => "log_action",
"tableAlias" => "log_action_event_action",
"joinOn" => "log_link_visit_action.idaction_event_action = log_action_event_action.idaction"
),
array(
"table" => "log_action",
"tableAlias" => "log_action_event_name",
"joinOn" => "log_link_visit_action.idaction_name = log_action_event_name.idaction"
)
);
$where = $this->getLogAggregator()->getWhereStatement('log_link_visit_action', 'server_time');
$where .= " AND log_link_visit_action.idaction_event_category IS NOT NULL";
$groupBy = "log_link_visit_action.idaction_event_category,
log_link_visit_action.idaction_event_action,
log_link_visit_action.idaction_name";
$orderBy = "`" . Metrics::INDEX_NB_VISITS . "` DESC, `eventName`";
$rankingQueryLimit = ArchivingHelper::getRankingQueryLimit();
$rankingQuery = null;
if ($rankingQueryLimit > 0) {
$rankingQuery = new RankingQuery($rankingQueryLimit);
$rankingQuery->addLabelColumn(array('eventCategory', 'eventAction', 'eventName'));
$rankingQuery->addColumn(array(Metrics::INDEX_NB_UNIQ_VISITORS));
$rankingQuery->addColumn(array(Metrics::INDEX_EVENT_NB_HITS, Metrics::INDEX_NB_VISITS, Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE), 'sum');
$rankingQuery->addColumn(Metrics::INDEX_EVENT_SUM_EVENT_VALUE, 'sum');
$rankingQuery->addColumn(Metrics::INDEX_EVENT_MIN_EVENT_VALUE, 'min');
$rankingQuery->addColumn(Metrics::INDEX_EVENT_MAX_EVENT_VALUE, 'max');
}
$this->archiveDayQueryProcess($select, $from, $where, $groupBy, $orderBy, $rankingQuery);
}
protected function archiveDayQueryProcess($select, $from, $where, $groupBy, $orderBy, RankingQuery $rankingQuery)
{
// get query with segmentation
$query = $this->getLogAggregator()->generateQuery($select, $from, $where, $groupBy, $orderBy);
// apply ranking query
if ($rankingQuery) {
$query['sql'] = $rankingQuery->generateRankingQuery($query['sql']);
}
// get result
$resultSet = $this->getLogAggregator()->getDb()->query($query['sql'], $query['bind']);
if ($resultSet === false) {
return;
}
while ($row = $resultSet->fetch()) {
$this->aggregateEventRow($row);
}
}
/**
* Records the daily datatables
*/
protected function insertDayReports()
{
foreach ($this->arrays as $recordName => $dataArray) {
$dataTable = $dataArray->asDataTable();
$blob = $dataTable->getSerialized(
$this->maximumRowsInDataTable,
$this->maximumRowsInSubDataTable,
$this->columnToSortByBeforeTruncation);
$this->getProcessor()->insertBlobRecord($recordName, $blob);
}
}
/**
* @param string $name
* @return DataArray
*/
protected function getDataArray($name)
{
if (empty($this->arrays[$name])) {
$this->arrays[$name] = new DataArray();
}
return $this->arrays[$name];
}
protected function aggregateEventRow($row)
{
foreach ($this->getRecordToDimensions() as $record => $dimensions) {
$dataArray = $this->getDataArray($record);
$mainDimension = $dimensions[0];
$mainLabel = $row[$mainDimension];
// Event name is optional
if ($mainDimension == 'eventName'
&& empty($mainLabel)) {
$mainLabel = self::EVENT_NAME_NOT_SET;
}
$dataArray->sumMetricsEvents($mainLabel, $row);
$subDimension = $dimensions[1];
$subLabel = $row[$subDimension];
if (empty($subLabel)) {
continue;
}
$dataArray->sumMetricsEventsPivot($mainLabel, $subLabel, $row);
}
}
}