Download core/DataTable/Renderer.php from Leon4gr45/matomo: direct link, hf CLI and curl.
- Browser
- Download file 18.2 kB
-
https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/core/DataTable/Renderer.php
- Command line
-
hf download hf://spaces/Leon4gr45/matomo/core/DataTable/Renderer.php
-
curl -L -o Renderer.php https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/core/DataTable/Renderer.php
18.2 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\DataTable; | |
| use Exception; | |
| use Piwik\Columns\Dimension; | |
| use Piwik\Common; | |
| use Piwik\DataTable; | |
| use Piwik\Metrics; | |
| use Piwik\Piwik; | |
| use Piwik\BaseFactory; | |
| /** | |
| * A DataTable Renderer can produce an output given a DataTable object. | |
| * All new Renderers must be copied in DataTable/Renderer and added to the factory() method. | |
| * To use a renderer, simply do: | |
| * $render = new Xml(); | |
| * $render->setTable($dataTable); | |
| * echo $render; | |
| */ | |
| abstract class Renderer extends BaseFactory | |
| { | |
| protected $table; | |
| /** | |
| * @var Exception | |
| */ | |
| protected $exception; | |
| protected $renderSubTables = false; | |
| /** @var bool */ | |
| protected $hideIdSubDatatable = false; | |
| /** @var bool */ | |
| protected $hideMetadata = false; | |
| /** | |
| * Whether to translate column names (i.e. metric names) or not | |
| * @var bool | |
| */ | |
| public $translateColumnNames = false; | |
| /** | |
| * Column translations | |
| * @var null|array | |
| */ | |
| private $columnTranslations = null; | |
| /** | |
| * The API method that has returned the data that should be rendered | |
| * @var null|string | |
| */ | |
| public $apiMethod = null; | |
| /** | |
| * API metadata for the current report | |
| * @var array|false|null | |
| */ | |
| private $apiMetaData = null; | |
| /** | |
| * The current idSite | |
| * @var int|string | |
| */ | |
| public $idSite = 'all'; | |
| public function __construct() | |
| { | |
| } | |
| /** | |
| * Sets whether to render subtables or not | |
| */ | |
| public function setRenderSubTables(bool $enableRenderSubTable): void | |
| { | |
| $this->renderSubTables = $enableRenderSubTable; | |
| } | |
| public function setHideIdSubDatableFromResponse(bool $hideIdSubDataTable): void | |
| { | |
| $this->hideIdSubDatatable = $hideIdSubDataTable; | |
| } | |
| public function setHideMetadataFromResponse(bool $hideMetadata): void | |
| { | |
| $this->hideMetadata = $hideMetadata; | |
| } | |
| /** | |
| * Returns whether to render subtables or not | |
| */ | |
| protected function isRenderSubtables(): bool | |
| { | |
| return $this->renderSubTables; | |
| } | |
| /** | |
| * Output HTTP Content-Type header | |
| */ | |
| protected function renderHeader() | |
| { | |
| Common::sendHeader('Content-Type: text/plain; charset=utf-8'); | |
| } | |
| /** | |
| * Computes the dataTable output and returns the string/binary | |
| * | |
| * @return string | |
| */ | |
| abstract public function render(); | |
| /** | |
| * @see render() | |
| */ | |
| public function __toString(): string | |
| { | |
| return $this->render(); | |
| } | |
| /** | |
| * Set the DataTable to be rendered | |
| * | |
| * @param DataTableInterface|array $table table to be rendered | |
| */ | |
| public function setTable($table) | |
| { | |
| if ( | |
| !is_array($table) | |
| && !($table instanceof DataTableInterface) | |
| ) { | |
| throw new Exception("DataTable renderers renderer accepts only DataTable, Simple and Map instances, and arrays."); | |
| } | |
| $this->table = $table; | |
| } | |
| /** | |
| * @var array | |
| */ | |
| protected static $availableRenderers = array('xml', | |
| 'json', | |
| 'csv', | |
| 'tsv', | |
| 'html', | |
| ); | |
| /** | |
| * Returns available renderers | |
| * | |
| * @return array | |
| */ | |
| public static function getRenderers() | |
| { | |
| return self::$availableRenderers; | |
| } | |
| protected static function getClassNameFromClassId($id) | |
| { | |
| $className = ucfirst(strtolower($id)); | |
| $className = 'Piwik\DataTable\Renderer\\' . $className; | |
| return $className; | |
| } | |
| protected static function getInvalidClassIdExceptionMessage($id) | |
| { | |
| $availableRenderers = implode(', ', self::getRenderers()); | |
| $klassName = self::getClassNameFromClassId($id); | |
| return Piwik::translate('General_ExceptionInvalidRendererFormat', array($klassName, $availableRenderers)); | |
| } | |
| /** | |
| * Format a value to xml | |
| * | |
| * @param string|number|bool $value value to format | |
| * @return int|string | |
| */ | |
| public static function formatValueXml($value) | |
| { | |
| if ( | |
| is_string($value) | |
| && !is_numeric($value) | |
| ) { | |
| $value = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); | |
| // make sure non-UTF-8 chars don't cause htmlspecialchars to choke | |
| if (function_exists('mb_convert_encoding')) { | |
| $value = @mb_convert_encoding($value, 'UTF-8', 'UTF-8'); | |
| } | |
| $value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); | |
| $htmlentities = array( | |
| " ", "¡", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", | |
| "ª", "«", "¬", "­", "®", "¯", "°", "±", "²", "³", | |
| "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", | |
| "½", "¾", "¿", "À", "Á", "Â", "Ã", "Ä", "Å", | |
| "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", | |
| "Ï", "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", | |
| "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", "à", | |
| "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", | |
| "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", | |
| "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", | |
| "ü", "ý", "þ", "ÿ", "€", | |
| ); | |
| $xmlentities = array( | |
| "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", | |
| "¬", "­", "®", "¯", "°", "±", "²", "³", "´", "µ", | |
| "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿", | |
| "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", | |
| "Ê", "Ë", "Ì", "Í", "Î", "Ï", "Ð", "Ñ", "Ò", "Ó", | |
| "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", | |
| "Þ", "ß", "à", "á", "â", "ã", "ä", "å", "æ", "ç", | |
| "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", | |
| "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", | |
| "ü", "ý", "þ", "ÿ", "€", | |
| ); | |
| $value = str_replace($htmlentities, $xmlentities, $value); | |
| } elseif ($value === false) { | |
| $value = 0; | |
| } | |
| return $value; | |
| } | |
| /** | |
| * Translate column names to the current language. | |
| * Used in subclasses. | |
| * | |
| * @param array $names | |
| * @return array | |
| */ | |
| protected function translateColumnNames($names) | |
| { | |
| if (!$this->apiMethod) { | |
| return $names; | |
| } | |
| // load the translations only once | |
| // when multiple dates are requested (date=...,...&period=day), the meta data would | |
| // be loaded lots of times otherwise | |
| if ($this->columnTranslations === null) { | |
| $meta = $this->getApiMetaData(); | |
| if ($meta === false) { | |
| return $names; | |
| } | |
| $t = Metrics::getDefaultMetricTranslations(); | |
| foreach (array('metrics', 'processedMetrics', 'metricsGoal', 'processedMetricsGoal') as $index) { | |
| if (isset($meta[$index]) && is_array($meta[$index])) { | |
| $t = array_merge($t, $meta[$index]); | |
| } | |
| } | |
| foreach (Dimension::getAllDimensions() as $dimension) { | |
| $dimensionId = str_replace('.', '_', $dimension->getId()); | |
| $dimensionName = $dimension->getName(); | |
| if (!empty($dimensionId) && !empty($dimensionName)) { | |
| $t[$dimensionId] = $dimensionName; | |
| } | |
| } | |
| $this->columnTranslations = & $t; | |
| } | |
| foreach ($names as &$name) { | |
| if (isset($this->columnTranslations[$name])) { | |
| $name = $this->columnTranslations[$name]; | |
| } | |
| } | |
| return $names; | |
| } | |
| /** | |
| * @return array|false | |
| */ | |
| protected function getApiMetaData() | |
| { | |
| if ($this->apiMetaData === null) { | |
| [$apiModule, $apiAction] = explode('.', $this->apiMethod); | |
| if (!$apiModule || !$apiAction) { | |
| $this->apiMetaData = false; | |
| } | |
| $api = \Piwik\Plugins\API\API::getInstance(); | |
| $meta = $api->getMetadata($this->idSite, $apiModule, $apiAction); | |
| if (isset($meta[0]) && is_array($meta[0])) { | |
| $meta = $meta[0]; | |
| } | |
| $this->apiMetaData = & $meta; | |
| } | |
| return $this->apiMetaData; | |
| } | |
| /** | |
| * Translates the given column name | |
| * | |
| * @param string $column | |
| * @return mixed | |
| */ | |
| protected function translateColumnName($column) | |
| { | |
| $columns = array($column); | |
| $columns = $this->translateColumnNames($columns); | |
| return $columns[0]; | |
| } | |
| /** | |
| * Enables column translating | |
| * | |
| * @param bool $bool | |
| */ | |
| public function setTranslateColumnNames($bool) | |
| { | |
| $this->translateColumnNames = $bool; | |
| } | |
| /** | |
| * Sets the api method | |
| * | |
| * @param $method | |
| */ | |
| public function setApiMethod($method) | |
| { | |
| $this->apiMethod = $method; | |
| } | |
| /** | |
| * Sets the site id | |
| * | |
| * @param int $idSite | |
| */ | |
| public function setIdSite($idSite) | |
| { | |
| $this->idSite = $idSite; | |
| } | |
| /** | |
| * Returns true if an array should be wrapped before rendering. This is used to | |
| * mimic quirks in the old rendering logic (for backwards compatibility). The | |
| * specific meaning of 'wrap' is left up to the Renderer. For XML, this means a | |
| * new <row> node. For JSON, this means wrapping in an array. | |
| * | |
| * In the old code, arrays were added to new DataTable instances, and then rendered. | |
| * This transformation wrapped associative arrays except under certain circumstances, | |
| * including: | |
| * - single element (ie, array('nb_visits' => 0)) (not wrapped for some renderers) | |
| * - empty array (ie, array()) | |
| * - array w/ arrays/DataTable instances as values (ie, | |
| * array('name' => 'myreport', | |
| * 'reportData' => new DataTable()) | |
| * OR array('name' => 'myreport', | |
| * 'reportData' => array(...)) ) | |
| * | |
| * @param array $array | |
| * @param bool $wrapSingleValues Whether to wrap array('key' => 'value') arrays. Some | |
| * renderers wrap them and some don't. | |
| * @param bool|null $isAssociativeArray Whether the array is associative or not. | |
| * If null, it is determined. | |
| * @return bool | |
| */ | |
| protected static function shouldWrapArrayBeforeRendering( | |
| $array, | |
| $wrapSingleValues = true, | |
| $isAssociativeArray = null | |
| ) { | |
| if (empty($array)) { | |
| return false; | |
| } | |
| if ($isAssociativeArray === null) { | |
| $isAssociativeArray = Piwik::isAssociativeArray($array); | |
| } | |
| $wrap = true; | |
| if ($isAssociativeArray) { | |
| // we don't wrap if the array has one element that is a value | |
| $firstValue = reset($array); | |
| if ( | |
| !$wrapSingleValues | |
| && count($array) === 1 | |
| && (!is_array($firstValue) | |
| && !is_object($firstValue)) | |
| ) { | |
| $wrap = false; | |
| } else { | |
| foreach ($array as $value) { | |
| if ( | |
| is_array($value) | |
| || is_object($value) | |
| ) { | |
| $wrap = false; | |
| break; | |
| } | |
| } | |
| } | |
| } else { | |
| $wrap = false; | |
| } | |
| return $wrap; | |
| } | |
| /** | |
| * Produces a flat php array from the DataTable, putting "columns" and "metadata" on the same level. | |
| * | |
| * For example, when a originalRender() would be | |
| * array( 'columns' => array( 'col1_name' => value1, 'col2_name' => value2 ), | |
| * 'metadata' => array( 'metadata1_name' => value_metadata) ) | |
| * | |
| * a flatRender() is | |
| * array( 'col1_name' => value1, | |
| * 'col2_name' => value2, | |
| * 'metadata1_name' => value_metadata ) | |
| * | |
| * @param null|array|DataTable\DataTableInterface $dataTable | |
| * @return mixed Php array representing the 'flat' version of the datatable, or a scalar value | |
| * when the table is a Simple table with a single column. | |
| */ | |
| protected function convertDataTableToArray($dataTable = null) | |
| { | |
| if (is_null($dataTable)) { | |
| $dataTable = $this->table; | |
| } | |
| if (is_array($dataTable)) { | |
| $flatArray = $dataTable; | |
| if (self::shouldWrapArrayBeforeRendering($flatArray)) { | |
| $flatArray = array($flatArray); | |
| } | |
| } elseif ($dataTable instanceof DataTable\Map) { | |
| $flatArray = array(); | |
| foreach ($dataTable->getDataTables() as $keyName => $table) { | |
| $flatArray[$keyName] = $this->convertDataTableToArray($table); | |
| } | |
| } elseif ($dataTable instanceof Simple) { | |
| $flatArray = $this->convertSimpleTable($dataTable); | |
| reset($flatArray); | |
| $firstKey = key($flatArray); | |
| // if we return only one numeric value then we print out the result in a simple <result> tag | |
| // keep it simple! | |
| if ( | |
| count($flatArray) == 1 | |
| && $firstKey !== DataTable\Row::COMPARISONS_METADATA_NAME | |
| ) { | |
| $flatArray = current($flatArray); | |
| } | |
| } else { | |
| // A normal DataTable needs to be handled specifically | |
| $array = $this->convertTable($dataTable); | |
| $flatArray = $this->flattenArray($array); | |
| } | |
| return $flatArray; | |
| } | |
| /** | |
| * Converts the given data table to an array | |
| * | |
| * @param DataTable $table | |
| * @return array | |
| */ | |
| protected function convertTable($table) | |
| { | |
| $array = []; | |
| foreach ($table->getRows() as $id => $row) { | |
| $newRow = [ | |
| 'columns' => $row->getColumns(), | |
| 'metadata' => $row->getMetadata(), | |
| 'idsubdatatable' => $row->getIdSubDataTable(), | |
| ]; | |
| if ($id == DataTable::ID_SUMMARY_ROW) { | |
| $newRow['issummaryrow'] = true; | |
| } | |
| if (isset($newRow['metadata'][DataTable\Row::COMPARISONS_METADATA_NAME])) { | |
| $newRow['metadata'][DataTable\Row::COMPARISONS_METADATA_NAME] = $row->getComparisons(); | |
| } | |
| $subTable = $row->getSubtable(); | |
| if ( | |
| $this->isRenderSubtables() | |
| && $subTable | |
| ) { | |
| $subTable = $this->convertTable($subTable); | |
| $newRow['subtable'] = $subTable; | |
| if ( | |
| $this->hideIdSubDatatable === false | |
| && $this->hideMetadata === false | |
| && isset($newRow['metadata']['idsubdatatable_in_db']) | |
| ) { | |
| $newRow['columns']['idsubdatatable'] = $newRow['metadata']['idsubdatatable_in_db']; | |
| } | |
| unset($newRow['metadata']['idsubdatatable_in_db']); | |
| } | |
| if ($this->hideIdSubDatatable || $this->hideMetadata) { | |
| unset($newRow['idsubdatatable']); | |
| } | |
| $array[] = $newRow; | |
| } | |
| return $array; | |
| } | |
| /** | |
| * Converts the simple data table to an array | |
| * | |
| * @param Simple $table | |
| * @return array | |
| */ | |
| protected function convertSimpleTable($table) | |
| { | |
| $array = []; | |
| $row = $table->getFirstRow(); | |
| if ($row === false) { | |
| return $array; | |
| } | |
| foreach ($row->getColumns() as $columnName => $columnValue) { | |
| $array[$columnName] = $columnValue; | |
| } | |
| $comparisons = $row->getComparisons(); | |
| if (!empty($comparisons)) { | |
| $array[DataTable\Row::COMPARISONS_METADATA_NAME] = $comparisons; | |
| } | |
| return $array; | |
| } | |
| /** | |
| * @param array $array | |
| * @return array | |
| */ | |
| protected function flattenArray($array) | |
| { | |
| $flatArray = []; | |
| foreach ($array as $row) { | |
| if ($this->hideMetadata) { | |
| $newRow = $row['columns']; | |
| } else { | |
| $newRow = $row['columns'] + $row['metadata']; | |
| } | |
| if ( | |
| isset($row['idsubdatatable']) | |
| && $this->hideIdSubDatatable === false | |
| ) { | |
| $newRow += ['idsubdatatable' => $row['idsubdatatable']]; | |
| } | |
| if (isset($row['subtable'])) { | |
| $newRow += ['subtable' => $this->flattenArray($row['subtable'])]; | |
| } | |
| $flatArray[] = $newRow; | |
| } | |
| return $flatArray; | |
| } | |
| } | |