HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/matomo.vdk/plugins/MarketingCampaignsReporting/API.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
 *
 * Based on code from AdvancedCampaignReporting plugin by Piwik PRO released under GPL v3 or later:
 * https://github.com/PiwikPRO/plugin-AdvancedCampaignReporting
 */

namespace Piwik\Plugins\MarketingCampaignsReporting;

use Piwik\Archive;
use Piwik\DataTable;
use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Plugins\Referrers\API as ReferrersAPI;

/**
 * The MarketingCampaignsReporting API provides campaign reports grouped by campaign dimensions
 * such as name, keyword, source, medium, content, group, placement, and source/medium hierarchy.
 *
 * @package MarketingCampaignsReporting
 * @method static \Piwik\Plugins\MarketingCampaignsReporting\API getInstance()
 */
class API extends \Piwik\Plugin\API
{
    protected function getDataTable($name, $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable = null)
    {
        Piwik::checkUserHasViewAccess($idSite);
        $dataTable = Archive::createDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
        $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS));
        return $dataTable;
    }

    /**
     * Returns campaign IDs with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign IDs report.
     */
    public function getId($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_ID_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns campaign names with standard campaign metrics.
     *
     * Falls back to the Referrers campaigns report when no archived data is available.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @param bool $expanded Whether to return subtables as nested data.
     * @param bool $flat Whether to flatten subtables into a single table.
     * @return DataTable|DataTable\Map Campaign names report.
     */
    public function getName($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_NAME_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat);
        $dataTable->filter('AddSegmentValue');

        if ($this->isTableEmpty($dataTable)) {
            $referrersDataTable = ReferrersAPI::getInstance()->getCampaigns($idSite, $period, $date, $segment, $expanded);
            $dataTable          = $this->mergeDataTableMaps($dataTable, $referrersDataTable);
        }

        return $dataTable;
    }

    /**
     * Returns campaign keyword/content rows for a campaign name subtable ID.
     *
     * Falls back to Referrers campaign subtables and then campaign label lookup when needed.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param int $idSubtable Subtable ID to load.
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign keyword/content rows for the selected campaign name.
     */
    public function getKeywordContentFromNameId($idSite, $period, $date, $idSubtable, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_NAME_RECORD_NAME, $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable);

        if (!$this->isTableEmpty($dataTable)) {
            return $dataTable;
        }

        // try to load sub table from referrers api. That might work, if the report leading to this subtable was loaded using the referrers api fallback
        $referrersDataTable = ReferrersAPI::getInstance()->getKeywordsFromCampaignId($idSite, $period, $date, $idSubtable, $segment);

        if (!$this->isTableEmpty($referrersDataTable)) {
            return $this->mergeDataTableMaps($dataTable, $referrersDataTable);
        }

        // if we can't find a subtable report using the id, try fetching the label to search for a subtable
        $campaignNames = $this->getDataTable(Archiver::CAMPAIGN_NAME_RECORD_NAME, $idSite, $period, $date, $segment, $expanded = false);
        $row           = $campaignNames->getRowFromIdSubDataTable($idSubtable);

        if (!$row) {
            return $dataTable;
        }

        $campaignName = $row->getColumn('label');

        $campaignsDataTable = ReferrersAPI::getInstance()->getCampaigns($idSite, $period, $date, $segment, false);
        $campaignRow        = $campaignsDataTable->getRowFromLabel($campaignName);

        if ($campaignRow && $idSubtable = $campaignRow->getIdSubDataTable()) {
            $referrersDataTable = ReferrersAPI::getInstance()->getKeywordsFromCampaignId($idSite, $period, $date, $idSubtable, $segment);
            return $this->mergeDataTableMaps($dataTable, $referrersDataTable);
        }

        return $dataTable;
    }

    /**
     * Returns campaign keywords with standard campaign metrics.
     *
     * Falls back to merged Referrers campaign subtables when no archived keyword data is available.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign keywords report.
     */
    public function getKeyword($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_KEYWORD_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');

        if ($this->isTableEmpty($dataTable)) {
            $referrersDataTable = ReferrersAPI::getInstance()->getCampaigns($idSite, $period, $date, $segment, $expanded = true);
            $referrersDataTable->applyQueuedFilters();
            $referrersDataTable = $referrersDataTable->mergeSubtables();

            $dataTable = $this->mergeDataTableMaps($dataTable, $referrersDataTable);
        }

        return $dataTable;
    }

    /**
     * Returns campaign sources with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign sources report.
     */
    public function getSource($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_SOURCE_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns campaign media with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign media report.
     */
    public function getMedium($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_MEDIUM_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns campaign contents with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign contents report.
     */
    public function getContent($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_CONTENT_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns campaign groups with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign groups report.
     */
    public function getGroup($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_GROUP_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns campaign placements with standard campaign metrics.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign placements report.
     */
    public function getPlacement($idSite, $period, $date, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::CAMPAIGN_PLACEMENT_RECORD_NAME, $idSite, $period, $date, $segment);
        $dataTable->filter('AddSegmentValue');
        return $dataTable;
    }

    /**
     * Returns hierarchical source/medium report rows.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @param bool $expanded Whether to return subtables as nested data.
     * @param bool $flat Whether to flatten subtables into a single table.
     * @return DataTable|DataTable\Map Hierarchical source/medium report.
     */
    public function getSourceMedium($idSite, $period, $date, $segment = false, $expanded = false, $flat = false)
    {
        $dataTable = $this->getDataTable(Archiver::HIERARCHICAL_SOURCE_MEDIUM_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat);
        return $dataTable;
    }

    /**
     * Returns campaign names for a hierarchical source/medium subtable ID.
     *
     * @param int|string|int[] $idSite Website ID(s) to query.
     *                         - Single site ID (e.g. 1)
     *                         - Multiple site IDs (e.g. [1, 4, 5])
     *                         - Comma-separated list ("1,4,5") or "all"
     * @param string $period The period to process, processes data for the period containing the
     *                       specified date. Allowed values: "day", "week", "month", "year",
     *                       "range".
     * @param string $date The date or date range to process.
     *                     'YYYY-MM-DD', magic keywords (today, yesterday, lastWeek, lastMonth,
     *                     lastYear), or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD', lastX,
     *                     previousX).
     * @param int $idSubtable Subtable ID to load.
     * @param string|false $segment (Optional) Custom segment to filter the report.
     *                              Example: "referrerName==twitter.com"
     *                              Supports AND (;) and OR (,) operators.
     *                              [See documentation:](https://developer.matomo.org/api-reference/reporting-api-segmentation)
     * @return DataTable|DataTable\Map Campaign names for the selected source/medium row.
     */
    public function getNameFromSourceMediumId($idSite, $period, $date, $idSubtable, $segment = false)
    {
        $dataTable = $this->getDataTable(Archiver::HIERARCHICAL_SOURCE_MEDIUM_RECORD_NAME, $idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable);
        return $dataTable;
    }

    private function isTableEmpty(DataTable\DataTableInterface $dataTable)
    {
        if ($dataTable instanceof DataTable) {
            return $dataTable->getRowsCount() == 0;
        } elseif ($dataTable instanceof DataTable\Map) {
            foreach ($dataTable->getDataTables() as $label => $childTable) {
                if ($this->isTableEmpty($childTable)) {
                    return true;
                }
            }
            return false;
        } else {
            throw new \Exception("Sanity check: unknown datatable type '" . get_class($dataTable) . "'.");
        }
    }

    private function mergeDataTableMaps(
        DataTable\DataTableInterface $dataTable,
        DataTable\DataTableInterface $referrersDataTable
    ) {
        if ($dataTable instanceof DataTable) {
            if ($this->isTableEmpty($dataTable)) {
                $referrersDataTable->setAllTableMetadata($dataTable->getAllTableMetadata());
                return $referrersDataTable;
            } else {
                return $dataTable;
            }
        } elseif ($dataTable instanceof DataTable\Map) {
            foreach ($dataTable->getDataTables() as $label => $childTable) {
                $newTable = $this->mergeDataTableMaps($childTable, $referrersDataTable->getTable($label));
                $dataTable->addTable($newTable, $label);
            }
            return $dataTable;
        } else {
            throw new \Exception("Sanity check: unknown datatable type '" . get_class($dataTable) . "'.");
        }
    }
}