Download core/API/DataTableManipulator.php from Leon4gr45/matomo: direct link, hf CLI and curl.
- Browser
- Download file 7.55 kB
-
https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/core/API/DataTableManipulator.php
- Command line
-
hf download hf://spaces/Leon4gr45/matomo/core/API/DataTableManipulator.php
-
curl -L -o DataTableManipulator.php https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/core/API/DataTableManipulator.php
7.55 kB
| /** | |
| * 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\API; | |
| use Exception; | |
| use Piwik\Archive\DataTableFactory; | |
| use Piwik\Container\StaticContainer; | |
| use Piwik\DataTable\Row; | |
| use Piwik\DataTable; | |
| use Piwik\Period\Range; | |
| use Piwik\Plugins\API\API; | |
| use Piwik\Url; | |
| /** | |
| * Base class for manipulating data tables. | |
| * It provides generic mechanisms like iteration and loading subtables. | |
| * | |
| * The manipulators are used in ResponseBuilder and are triggered by | |
| * API parameters. They are not filters because they don't work on the pre- | |
| * fetched nested data tables. Instead, they load subtables using this base | |
| * class. This way, they can only load the tables they really need instead | |
| * of using expanded=1. Another difference between manipulators and filters | |
| * is that filters keep the overall structure of the table intact while | |
| * manipulators can change the entire thing. | |
| */ | |
| abstract class DataTableManipulator | |
| { | |
| protected $apiModule; | |
| protected $apiMethod; | |
| protected $request; | |
| protected $apiMethodForSubtable; | |
| /** | |
| * @param string|bool $apiModule | |
| * @param string|bool $apiMethod | |
| * @param array $request | |
| */ | |
| public function __construct($apiModule = false, $apiMethod = false, $request = array()) | |
| { | |
| $this->apiModule = $apiModule; | |
| $this->apiMethod = $apiMethod; | |
| $this->request = $request; | |
| } | |
| /** | |
| * This method can be used by subclasses to iterate over data tables that might be | |
| * data table maps. It calls back the template method self::doManipulate for each table. | |
| * This way, data table arrays can be handled in a transparent fashion. | |
| * | |
| * @param DataTable\Map|DataTable $dataTable | |
| * @throws Exception | |
| * @return DataTable\Map|DataTable | |
| */ | |
| protected function manipulate($dataTable) | |
| { | |
| if ($dataTable instanceof DataTable\Map) { | |
| return $this->manipulateDataTableMap($dataTable); | |
| } elseif ($dataTable instanceof DataTable) { | |
| return $this->manipulateDataTable($dataTable); | |
| } else { | |
| return $dataTable; | |
| } | |
| } | |
| /** | |
| * Manipulates child DataTables of a DataTable\Map. See @manipulate for more info. | |
| * | |
| * @param DataTable\Map $dataTable | |
| * @return DataTable\Map | |
| */ | |
| protected function manipulateDataTableMap($dataTable) | |
| { | |
| $result = $dataTable->getEmptyClone(); | |
| foreach ($dataTable->getDataTables() as $tableLabel => $childTable) { | |
| $newTable = $this->manipulate($childTable); | |
| $result->addTable($newTable, $tableLabel); | |
| } | |
| return $result; | |
| } | |
| /** | |
| * Manipulates a single DataTable instance. Derived classes must define | |
| * this function. | |
| */ | |
| abstract protected function manipulateDataTable($dataTable); | |
| /** | |
| * Load the subtable for a row. | |
| * Returns null if none is found. | |
| * | |
| * @param DataTable $dataTable | |
| * @param Row $row | |
| * | |
| * @return DataTable|null | |
| */ | |
| protected function loadSubtable($dataTable, $row) | |
| { | |
| if (!($this->apiModule && $this->apiMethod && count($this->request))) { | |
| return null; | |
| } | |
| $request = $this->request; | |
| $idSubTable = $row->getIdSubDataTable(); | |
| if ($idSubTable === null) { | |
| return null; | |
| } | |
| $request['idSubtable'] = $idSubTable; | |
| if ($dataTable) { | |
| $period = $dataTable->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX); | |
| if ($period instanceof Range) { | |
| $request['date'] = $period->getDateStart() . ',' . $period->getDateEnd(); | |
| } else { | |
| $request['date'] = $period->getDateStart()->toString(); | |
| } | |
| } | |
| $method = $this->getApiMethodForSubtable($request); | |
| return $this->callApiAndReturnDataTable($this->apiModule, $method, $request); | |
| } | |
| /** | |
| * In this method, subclasses can clean up the request array for loading subtables | |
| * in order to make ResponseBuilder behave correctly (e.g. not trigger the | |
| * manipulator again). | |
| * | |
| * @param array $request | |
| * @return array | |
| */ | |
| abstract protected function manipulateSubtableRequest($request); | |
| /** | |
| * Extract the API method for loading subtables from the meta data | |
| * | |
| * @throws Exception | |
| * @return string | |
| */ | |
| protected function getApiMethodForSubtable($request) | |
| { | |
| if (!$this->apiMethodForSubtable) { | |
| if (!empty($request['idSite'])) { | |
| $idSite = $request['idSite']; | |
| } else { | |
| $idSite = 'all'; | |
| } | |
| $apiParameters = array(); | |
| $entityNames = StaticContainer::get('entities.idNames'); | |
| foreach ($entityNames as $idName) { | |
| if (!empty($request[$idName])) { | |
| $apiParameters[$idName] = $request[$idName]; | |
| } | |
| } | |
| $meta = API::getInstance()->getMetadata($idSite, $this->apiModule, $this->apiMethod, $apiParameters); | |
| if (empty($meta) && array_key_exists('idGoal', $apiParameters)) { | |
| unset($apiParameters['idGoal']); | |
| $meta = API::getInstance()->getMetadata($idSite, $this->apiModule, $this->apiMethod, $apiParameters); | |
| } | |
| if (empty($meta)) { | |
| throw new Exception(sprintf( | |
| "The DataTable cannot be manipulated: Metadata for report %s.%s could not be found. You can define the metadata in a hook, see example at: %s", | |
| $this->apiModule, | |
| $this->apiMethod, | |
| Url::addCampaignParametersToMatomoLink('https://developer.matomo.org/api-reference/events#apigetreportmetadata') | |
| )); | |
| } | |
| if (isset($meta[0]['actionToLoadSubTables'])) { | |
| $this->apiMethodForSubtable = $meta[0]['actionToLoadSubTables']; | |
| } else { | |
| $this->apiMethodForSubtable = $this->apiMethod; | |
| } | |
| } | |
| return $this->apiMethodForSubtable; | |
| } | |
| protected function callApiAndReturnDataTable($apiModule, $method, $request) | |
| { | |
| $class = Request::getClassNameAPI($apiModule); | |
| $request = $this->manipulateSubtableRequest($request); | |
| $request['serialize'] = 0; | |
| $request['expanded'] = 0; | |
| $request['format'] = 'original'; | |
| $request['format_metrics'] = 0; | |
| $request['compare'] = 0; | |
| // don't want to run recursive filters on the subtables as they are loaded, | |
| // otherwise the result will be empty in places (or everywhere). instead we | |
| // run it on the flattened table. | |
| unset($request['filter_pattern_recursive']); | |
| $dataTable = Proxy::getInstance()->call($class, $method, $request); | |
| $response = new ResponseBuilder($format = 'original', $request); | |
| $response->disableSendHeader(); | |
| $dataTable = $response->getResponse($dataTable, $apiModule, $method); | |
| // save API method name so it can be used by filters | |
| if ($dataTable instanceof DataTable\DataTableInterface) { | |
| $dataTable->filter(function (DataTable $table) use ($apiModule, $method) { | |
| $table->setMetadata('apiModule', $apiModule); | |
| $table->setMetadata('apiMethod', $method); | |
| }); | |
| } | |
| return $dataTable; | |
| } | |
| } | |