1<?php
2/**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9namespace Piwik\DataTable\Filter;
10
11use Piwik\DataTable\BaseFilter;
12use Piwik\DataTable;
13use Piwik\Plugin\Metric;
14use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit;
15use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite;
16use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate;
17use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate;
18
19/**
20 * Adds processed metrics columns to a {@link DataTable} using metrics that already exist.
21 *
22 * Columns added are:
23 *
24 * - **conversion_rate**: percent value of `nb_visits_converted / nb_visits
25 * - **nb_actions_per_visit**: `nb_actions / nb_visits`
26 * - **avg_time_on_site**: in number of seconds, `round(visit_length / nb_visits)`. Not
27 *                         pretty formatted.
28 * - **bounce_rate**: percent value of `bounce_count / nb_visits`
29 *
30 * Adding the **filter_add_columns_when_show_all_columns** query parameter to
31 * an API request will trigger the execution of this Filter.
32 *
33 * _Note: This filter must be called before {@link ReplaceColumnNames} is called._
34 *
35 * **Basic usage example**
36 *
37 *     $dataTable->filter('AddColumnsProcessedMetrics');
38 *
39 * @api
40 */
41class AddColumnsProcessedMetrics extends BaseFilter
42{
43    protected $invalidDivision = 0;
44    protected $roundPrecision = 2;
45    protected $deleteRowsWithNoVisit = true;
46
47    /**
48     * Constructor.
49     *
50     * @param DataTable $table The table to eventually filter.
51     * @param bool $deleteRowsWithNoVisit Whether to delete rows with no visits or not.
52     */
53    public function __construct($table, $deleteRowsWithNoVisit = true)
54    {
55        $this->deleteRowsWithNoVisit = $deleteRowsWithNoVisit;
56        parent::__construct($table);
57    }
58
59    /**
60     * Adds the processed metrics. See {@link AddColumnsProcessedMetrics} for
61     * more information.
62     *
63     * @param DataTable $table
64     */
65    public function filter($table)
66    {
67        if ($this->deleteRowsWithNoVisit) {
68            $this->deleteRowsWithNoVisit($table);
69        }
70
71        $extraProcessedMetrics = $table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME) ?: [];
72
73        $extraProcessedMetrics[] = new ConversionRate();
74        $extraProcessedMetrics[] = new ActionsPerVisit();
75        $extraProcessedMetrics[] = new AverageTimeOnSite();
76        $extraProcessedMetrics[] = new BounceRate();
77
78        $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics);
79    }
80
81    private function deleteRowsWithNoVisit(DataTable $table)
82    {
83        foreach ($table->getRows() as $key => $row) {
84            $nbVisits  = (int)Metric::getMetric($row, 'nb_visits');
85            $nbActions = (int)Metric::getMetric($row, 'nb_actions');
86
87            if ($nbVisits === 0
88                && $nbActions === 0
89            ) {
90                // case of keyword/website/campaign with a conversion for this day, but no visit, we don't show it
91                $table->deleteRow($key);
92            }
93        }
94    }
95}
96