add piwik installation
This commit is contained in:
parent
90aa4ef157
commit
8c5d4f0c31
3197 changed files with 563902 additions and 0 deletions
167
www/analytics/core/DataTable/Renderer/Console.php
Normal file
167
www/analytics/core/DataTable/Renderer/Console.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Piwik\DataTable\Manager;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Renderer;
|
||||
|
||||
/**
|
||||
* Simple output
|
||||
*/
|
||||
class Console extends Renderer
|
||||
{
|
||||
/**
|
||||
* Prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefixRows = '#';
|
||||
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$this->renderHeader();
|
||||
return $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renderException()
|
||||
{
|
||||
$this->renderHeader();
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
return 'Error: ' . $exceptionMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix to be used
|
||||
*
|
||||
* @param string $str new prefix
|
||||
*/
|
||||
public function setPrefixRow($str)
|
||||
{
|
||||
$this->prefixRows = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output of the given array of data tables
|
||||
*
|
||||
* @param DataTable\Map $map data tables to render
|
||||
* @param string $prefix prefix to output before table data
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTableMap(DataTable\Map $map, $prefix)
|
||||
{
|
||||
$output = "Set<hr />";
|
||||
$prefix = $prefix . ' ';
|
||||
foreach ($map->getDataTables() as $descTable => $table) {
|
||||
$output .= $prefix . "<b>" . $descTable . "</b><br />";
|
||||
$output .= $prefix . $this->renderTable($table, $prefix . ' ');
|
||||
$output .= "<hr />";
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the given dataTable output and returns the string/binary
|
||||
*
|
||||
* @param DataTable $table data table to render
|
||||
* @param string $prefix prefix to output before table data
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTable($table, $prefix = "")
|
||||
{
|
||||
if (is_array($table)) // convert array to DataTable
|
||||
{
|
||||
$table = DataTable::makeFromSimpleArray($table);
|
||||
}
|
||||
|
||||
if ($table instanceof DataTable\Map) {
|
||||
return $this->renderDataTableMap($table, $prefix);
|
||||
}
|
||||
|
||||
if ($table->getRowsCount() == 0) {
|
||||
return "Empty table<br />\n";
|
||||
}
|
||||
|
||||
static $depth = 0;
|
||||
$output = '';
|
||||
$i = 1;
|
||||
foreach ($table->getRows() as $row) {
|
||||
$dataTableMapBreak = false;
|
||||
$columns = array();
|
||||
foreach ($row->getColumns() as $column => $value) {
|
||||
if ($value instanceof DataTable\Map) {
|
||||
$output .= $this->renderDataTableMap($value, $prefix);
|
||||
$dataTableMapBreak = true;
|
||||
break;
|
||||
}
|
||||
if (is_string($value)) $value = "'$value'";
|
||||
elseif (is_array($value)) $value = var_export($value, true);
|
||||
|
||||
$columns[] = "'$column' => $value";
|
||||
}
|
||||
if ($dataTableMapBreak === true) {
|
||||
continue;
|
||||
}
|
||||
$columns = implode(", ", $columns);
|
||||
|
||||
$metadata = array();
|
||||
foreach ($row->getMetadata() as $name => $value) {
|
||||
if (is_string($value)) $value = "'$value'";
|
||||
elseif (is_array($value)) $value = var_export($value, true);
|
||||
$metadata[] = "'$name' => $value";
|
||||
}
|
||||
$metadata = implode(", ", $metadata);
|
||||
|
||||
$output .= str_repeat($this->prefixRows, $depth)
|
||||
. "- $i [" . $columns . "] [" . $metadata . "] [idsubtable = "
|
||||
. $row->getIdSubDataTable() . "]<br />\n";
|
||||
|
||||
if (!is_null($row->getIdSubDataTable())) {
|
||||
if ($row->isSubtableLoaded()) {
|
||||
$depth++;
|
||||
$output .= $this->renderTable(
|
||||
Manager::getInstance()->getTable(
|
||||
$row->getIdSubDataTable()
|
||||
),
|
||||
$prefix . ' '
|
||||
);
|
||||
$depth--;
|
||||
} else {
|
||||
$output .= "-- Sub DataTable not loaded<br />\n";
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
$metadata = $table->getAllTableMetadata();
|
||||
if (!empty($metadata)) {
|
||||
$output .= "<hr />Metadata<br />";
|
||||
foreach ($metadata as $id => $metadataIn) {
|
||||
$output .= "<br />";
|
||||
$output .= $prefix . " <b>$id</b><br />";
|
||||
if(is_array($metadataIn)) {
|
||||
foreach ($metadataIn as $name => $value) {
|
||||
$output .= $prefix . $prefix . "$name => $value";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
403
www/analytics/core/DataTable/Renderer/Csv.php
Normal file
403
www/analytics/core/DataTable/Renderer/Csv.php
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\DataTable\Renderer;
|
||||
use Piwik\DataTable\Simple;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Date;
|
||||
use Piwik\Period;
|
||||
use Piwik\Period\Range;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\ProxyHttp;
|
||||
|
||||
/**
|
||||
* CSV export
|
||||
*
|
||||
* When rendered using the default settings, a CSV report has the following characteristics:
|
||||
* The first record contains headers for all the columns in the report.
|
||||
* All rows have the same number of columns.
|
||||
* The default field delimiter string is a comma (,).
|
||||
* Formatting and layout are ignored.
|
||||
*
|
||||
*/
|
||||
class Csv extends Renderer
|
||||
{
|
||||
/**
|
||||
* Column separator
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $separator = ",";
|
||||
|
||||
/**
|
||||
* Line end
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $lineEnd = "\n";
|
||||
|
||||
/**
|
||||
* 'metadata' columns will be exported, prefixed by 'metadata_'
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $exportMetadata = true;
|
||||
|
||||
/**
|
||||
* Converts the content to unicode so that UTF8 characters (eg. chinese) can be imported in Excel
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $convertToUnicode = true;
|
||||
|
||||
/**
|
||||
* idSubtable will be exported in a column called 'idsubdatatable'
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $exportIdSubtable = true;
|
||||
|
||||
/**
|
||||
* This string is also hardcoded in archive,sh
|
||||
*/
|
||||
const NO_DATA_AVAILABLE = 'No data available';
|
||||
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$str = $this->renderTable($this->table);
|
||||
if (empty($str)) {
|
||||
return self::NO_DATA_AVAILABLE;
|
||||
}
|
||||
|
||||
$this->renderHeader();
|
||||
|
||||
if ($this->convertToUnicode
|
||||
&& function_exists('mb_convert_encoding')
|
||||
) {
|
||||
$str = chr(255) . chr(254) . mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function renderException()
|
||||
{
|
||||
@header('Content-Type: text/html; charset=utf-8');
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
return 'Error: ' . $exceptionMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables / Disables unicode converting
|
||||
*
|
||||
* @param $bool
|
||||
*/
|
||||
public function setConvertToUnicode($bool)
|
||||
{
|
||||
$this->convertToUnicode = $bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column separator
|
||||
*
|
||||
* @param $separator
|
||||
*/
|
||||
public function setSeparator($separator)
|
||||
{
|
||||
$this->separator = $separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output of the given data table
|
||||
*
|
||||
* @param DataTable|array $table
|
||||
* @param array $allColumns
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTable($table, &$allColumns = array())
|
||||
{
|
||||
if (is_array($table)) // convert array to DataTable
|
||||
{
|
||||
$table = DataTable::makeFromSimpleArray($table);
|
||||
}
|
||||
|
||||
if ($table instanceof DataTable\Map) {
|
||||
$str = $this->renderDataTableMap($table, $allColumns);
|
||||
} else {
|
||||
$str = $this->renderDataTable($table, $allColumns);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output of the given data table array
|
||||
*
|
||||
* @param DataTable\Map $table
|
||||
* @param array $allColumns
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTableMap($table, &$allColumns = array())
|
||||
{
|
||||
$str = '';
|
||||
foreach ($table->getDataTables() as $currentLinePrefix => $dataTable) {
|
||||
$returned = explode("\n", $this->renderTable($dataTable, $allColumns));
|
||||
|
||||
// get rid of the columns names
|
||||
$returned = array_slice($returned, 1);
|
||||
|
||||
// case empty datatable we dont print anything in the CSV export
|
||||
// when in xml we would output <result date="2008-01-15" />
|
||||
if (!empty($returned)) {
|
||||
foreach ($returned as &$row) {
|
||||
$row = $currentLinePrefix . $this->separator . $row;
|
||||
}
|
||||
$str .= "\n" . implode("\n", $returned);
|
||||
}
|
||||
}
|
||||
|
||||
// prepend table key to column list
|
||||
$allColumns = array_merge(array($table->getKeyName() => true), $allColumns);
|
||||
|
||||
// add header to output string
|
||||
$str = $this->getHeaderLine(array_keys($allColumns)) . $str;
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the output of the given simple data table
|
||||
*
|
||||
* @param DataTable|Simple $table
|
||||
* @param array $allColumns
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTable($table, &$allColumns = array())
|
||||
{
|
||||
if ($table instanceof Simple) {
|
||||
$row = $table->getFirstRow();
|
||||
if ($row !== false) {
|
||||
$columnNameToValue = $row->getColumns();
|
||||
if (count($columnNameToValue) == 1) {
|
||||
// simple tables should only have one column, the value
|
||||
$allColumns['value'] = true;
|
||||
|
||||
$value = array_values($columnNameToValue);
|
||||
$str = 'value' . $this->lineEnd . $this->formatValue($value[0]);
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$csv = array();
|
||||
foreach ($table->getRows() as $row) {
|
||||
$csvRow = $this->flattenColumnArray($row->getColumns());
|
||||
|
||||
if ($this->exportMetadata) {
|
||||
$metadata = $row->getMetadata();
|
||||
foreach ($metadata as $name => $value) {
|
||||
if ($name == 'idsubdatatable_in_db') {
|
||||
continue;
|
||||
}
|
||||
//if a metadata and a column have the same name make sure they dont overwrite
|
||||
if ($this->translateColumnNames) {
|
||||
$name = Piwik::translate('General_Metadata') . ': ' . $name;
|
||||
} else {
|
||||
$name = 'metadata_' . $name;
|
||||
}
|
||||
|
||||
$csvRow[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($csvRow as $name => $value) {
|
||||
$allColumns[$name] = true;
|
||||
}
|
||||
|
||||
if ($this->exportIdSubtable) {
|
||||
$idsubdatatable = $row->getIdSubDataTable();
|
||||
if ($idsubdatatable !== false
|
||||
&& $this->hideIdSubDatatable === false
|
||||
) {
|
||||
$csvRow['idsubdatatable'] = $idsubdatatable;
|
||||
}
|
||||
}
|
||||
|
||||
$csv[] = $csvRow;
|
||||
}
|
||||
|
||||
// now we make sure that all the rows in the CSV array have all the columns
|
||||
foreach ($csv as &$row) {
|
||||
foreach ($allColumns as $columnName => $true) {
|
||||
if (!isset($row[$columnName])) {
|
||||
$row[$columnName] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$str = '';
|
||||
|
||||
// specific case, we have only one column and this column wasn't named properly (indexed by a number)
|
||||
// we don't print anything in the CSV file => an empty line
|
||||
if (sizeof($allColumns) == 1
|
||||
&& reset($allColumns)
|
||||
&& !is_string(key($allColumns))
|
||||
) {
|
||||
$str .= '';
|
||||
} else {
|
||||
// render row names
|
||||
$str .= $this->getHeaderLine(array_keys($allColumns)) . $this->lineEnd;
|
||||
}
|
||||
|
||||
// we render the CSV
|
||||
foreach ($csv as $theRow) {
|
||||
$rowStr = '';
|
||||
foreach ($allColumns as $columnName => $true) {
|
||||
$rowStr .= $this->formatValue($theRow[$columnName]) . $this->separator;
|
||||
}
|
||||
// remove the last separator
|
||||
$rowStr = substr_replace($rowStr, "", -strlen($this->separator));
|
||||
$str .= $rowStr . $this->lineEnd;
|
||||
}
|
||||
$str = substr($str, 0, -strlen($this->lineEnd));
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSV header line for a set of metrics. Will translate columns if desired.
|
||||
*
|
||||
* @param array $columnMetrics
|
||||
* @return array
|
||||
*/
|
||||
private function getHeaderLine($columnMetrics)
|
||||
{
|
||||
if ($this->translateColumnNames) {
|
||||
$columnMetrics = $this->translateColumnNames($columnMetrics);
|
||||
}
|
||||
return implode($this->separator, $columnMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats/Escapes the given value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
protected function formatValue($value)
|
||||
{
|
||||
if (is_string($value)
|
||||
&& !is_numeric($value)
|
||||
) {
|
||||
$value = html_entity_decode($value, ENT_COMPAT, 'UTF-8');
|
||||
} elseif ($value === false) {
|
||||
$value = 0;
|
||||
}
|
||||
if (is_string($value)
|
||||
&& (strpos($value, '"') !== false
|
||||
|| strpos($value, $this->separator) !== false)
|
||||
) {
|
||||
$value = '"' . str_replace('"', '""', $value) . '"';
|
||||
}
|
||||
|
||||
// in some number formats (e.g. German), the decimal separator is a comma
|
||||
// we need to catch and replace this
|
||||
if (is_numeric($value)) {
|
||||
$value = (string)$value;
|
||||
$value = str_replace(',', '.', $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the http headers for csv file
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
$fileName = 'Piwik ' . Piwik::translate('General_Export');
|
||||
|
||||
$period = Common::getRequestVar('period', false);
|
||||
$date = Common::getRequestVar('date', false);
|
||||
if ($period || $date) // in test cases, there are no request params set
|
||||
{
|
||||
if ($period == 'range') {
|
||||
$period = new Range($period, $date);
|
||||
} else if (strpos($date, ',') !== false) {
|
||||
$period = new Range('range', $date);
|
||||
} else {
|
||||
$period = Period::factory($period, Date::factory($date));
|
||||
}
|
||||
|
||||
$prettyDate = $period->getLocalizedLongString();
|
||||
|
||||
$meta = $this->getApiMetaData();
|
||||
|
||||
$fileName .= ' _ ' . $meta['name']
|
||||
. ' _ ' . $prettyDate . '.csv';
|
||||
}
|
||||
|
||||
// silent fail otherwise unit tests fail
|
||||
@header('Content-Type: application/vnd.ms-excel');
|
||||
@header('Content-Disposition: attachment; filename="' . $fileName . '"');
|
||||
ProxyHttp::overrideCacheControlHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array of column values so they can be outputted as CSV (which does not support
|
||||
* nested structures).
|
||||
*/
|
||||
private function flattenColumnArray($columns, &$csvRow = array(), $csvColumnNameTemplate = '%s')
|
||||
{
|
||||
foreach ($columns as $name => $value) {
|
||||
$csvName = sprintf($csvColumnNameTemplate, $this->getCsvColumnName($name));
|
||||
|
||||
if (is_array($value)) {
|
||||
// if we're translating column names and this is an array of arrays, the column name
|
||||
// format becomes a bit more complicated. also in this case, we assume $value is not
|
||||
// nested beyond 2 levels (ie, array(0 => array(0 => 1, 1 => 2)), but not array(
|
||||
// 0 => array(0 => array(), 1 => array())) )
|
||||
if ($this->translateColumnNames
|
||||
&& is_array(reset($value))
|
||||
) {
|
||||
foreach ($value as $level1Key => $level1Value) {
|
||||
$inner = $name == 'goals' ? Piwik::translate('Goals_GoalX', $level1Key) : $name . ' ' . $level1Key;
|
||||
$columnNameTemplate = '%s (' . $inner . ')';
|
||||
|
||||
$this->flattenColumnArray($level1Value, $csvRow, $columnNameTemplate);
|
||||
}
|
||||
} else {
|
||||
$this->flattenColumnArray($value, $csvRow, $csvName . '_%s');
|
||||
}
|
||||
} else {
|
||||
$csvRow[$csvName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $csvRow;
|
||||
}
|
||||
|
||||
private function getCsvColumnName($name)
|
||||
{
|
||||
if ($this->translateColumnNames) {
|
||||
return $this->translateColumnName($name);
|
||||
} else {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
207
www/analytics/core/DataTable/Renderer/Html.php
Normal file
207
www/analytics/core/DataTable/Renderer/Html.php
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Exception;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Renderer;
|
||||
|
||||
/**
|
||||
* Simple HTML output
|
||||
* Does not work with recursive DataTable (i.e., when a row can be associated with a subDataTable).
|
||||
*
|
||||
*/
|
||||
class Html extends Renderer
|
||||
{
|
||||
protected $tableId;
|
||||
protected $allColumns;
|
||||
protected $tableStructure;
|
||||
protected $i;
|
||||
|
||||
/**
|
||||
* Sets the table id
|
||||
*
|
||||
* @param string $id
|
||||
*/
|
||||
function setTableId($id)
|
||||
{
|
||||
$this->tableId = str_replace('.', '_', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output HTTP Content-Type header
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
@header('Content-Type: text/html; charset=utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function render()
|
||||
{
|
||||
$this->renderHeader();
|
||||
$this->tableStructure = array();
|
||||
$this->allColumns = array();
|
||||
$this->i = 0;
|
||||
|
||||
return $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function renderException()
|
||||
{
|
||||
$this->renderHeader();
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
return nl2br($exceptionMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data table
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTable($table)
|
||||
{
|
||||
if (is_array($table)) // convert array to DataTable
|
||||
{
|
||||
$table = DataTable::makeFromSimpleArray($table);
|
||||
}
|
||||
|
||||
if ($table instanceof DataTable\Map) {
|
||||
foreach ($table->getDataTables() as $date => $subtable) {
|
||||
if ($subtable->getRowsCount()) {
|
||||
$this->buildTableStructure($subtable, '_' . $table->getKeyName(), $date);
|
||||
}
|
||||
}
|
||||
} else // Simple
|
||||
{
|
||||
if ($table->getRowsCount()) {
|
||||
$this->buildTableStructure($table);
|
||||
}
|
||||
}
|
||||
|
||||
$out = $this->renderDataTable();
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given data table to the table structure array
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @param null|string $columnToAdd
|
||||
* @param null|string $valueToAdd
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function buildTableStructure($table, $columnToAdd = null, $valueToAdd = null)
|
||||
{
|
||||
$i = $this->i;
|
||||
$someMetadata = false;
|
||||
$someIdSubTable = false;
|
||||
|
||||
/*
|
||||
* table = array
|
||||
* ROW1 = col1 | col2 | col3 | metadata | idSubTable
|
||||
* ROW2 = col1 | col2 (no value but appears) | col3 | metadata | idSubTable
|
||||
*/
|
||||
if (!($table instanceof DataTable)) {
|
||||
throw new Exception("HTML Renderer does not work with this combination of parameters");
|
||||
}
|
||||
foreach ($table->getRows() as $row) {
|
||||
if (isset($columnToAdd) && isset($valueToAdd)) {
|
||||
$this->allColumns[$columnToAdd] = true;
|
||||
$this->tableStructure[$i][$columnToAdd] = $valueToAdd;
|
||||
}
|
||||
|
||||
foreach ($row->getColumns() as $column => $value) {
|
||||
$this->allColumns[$column] = true;
|
||||
$this->tableStructure[$i][$column] = $value;
|
||||
}
|
||||
|
||||
$metadata = array();
|
||||
foreach ($row->getMetadata() as $name => $value) {
|
||||
if (is_string($value)) $value = "'$value'";
|
||||
$metadata[] = "'$name' => $value";
|
||||
}
|
||||
|
||||
if (count($metadata) != 0) {
|
||||
$someMetadata = true;
|
||||
$metadata = implode("<br />", $metadata);
|
||||
$this->tableStructure[$i]['_metadata'] = $metadata;
|
||||
}
|
||||
|
||||
$idSubtable = $row->getIdSubDataTable();
|
||||
if (!is_null($idSubtable)) {
|
||||
$someIdSubTable = true;
|
||||
$this->tableStructure[$i]['_idSubtable'] = $idSubtable;
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
$this->i = $i;
|
||||
|
||||
$this->allColumns['_metadata'] = $someMetadata;
|
||||
$this->allColumns['_idSubtable'] = $someIdSubTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the table structure array
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTable()
|
||||
{
|
||||
$html = "<table " . ($this->tableId ? "id=\"{$this->tableId}\" " : "") . "border=\"1\">\n<thead>\n\t<tr>\n";
|
||||
|
||||
foreach ($this->allColumns as $name => $toDisplay) {
|
||||
if ($toDisplay !== false) {
|
||||
if ($name === 0) {
|
||||
$name = 'value';
|
||||
}
|
||||
if ($this->translateColumnNames) {
|
||||
$name = $this->translateColumnName($name);
|
||||
}
|
||||
$html .= "\t\t<th>$name</th>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$html .= "\t</tr>\n</thead>\n<tbody>\n";
|
||||
|
||||
foreach ($this->tableStructure as $row) {
|
||||
$html .= "\t<tr>\n";
|
||||
foreach ($this->allColumns as $name => $toDisplay) {
|
||||
if ($toDisplay !== false) {
|
||||
$value = "-";
|
||||
if (isset($row[$name])) {
|
||||
if (is_array($row[$name])) {
|
||||
$value = "<pre>" . self::formatValueXml(var_export($row[$name], true)) . "</pre>";
|
||||
} else {
|
||||
$value = self::formatValueXml($row[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
$html .= "\t\t<td>$value</td>\n";
|
||||
}
|
||||
}
|
||||
$html .= "\t</tr>\n";
|
||||
}
|
||||
|
||||
$html .= "</tbody>\n</table>\n";
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
140
www/analytics/core/DataTable/Renderer/Json.php
Normal file
140
www/analytics/core/DataTable/Renderer/Json.php
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\DataTable\Renderer;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\ProxyHttp;
|
||||
|
||||
/**
|
||||
* JSON export.
|
||||
* Works with recursive DataTable (when a row can be associated with a subDataTable).
|
||||
*
|
||||
*/
|
||||
class Json extends Renderer
|
||||
{
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$this->renderHeader();
|
||||
return $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function renderException()
|
||||
{
|
||||
$this->renderHeader();
|
||||
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
$exceptionMessage = str_replace(array("\r\n", "\n"), "", $exceptionMessage);
|
||||
|
||||
$result = json_encode(array('result' => 'error', 'message' => $exceptionMessage));
|
||||
|
||||
return $this->jsonpWrap($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data table
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @return string
|
||||
*/
|
||||
protected function renderTable($table)
|
||||
{
|
||||
if (is_array($table)) {
|
||||
$array = $table;
|
||||
if (self::shouldWrapArrayBeforeRendering($array, $wrapSingleValues = true)) {
|
||||
$array = array($array);
|
||||
}
|
||||
|
||||
foreach ($array as $key => $tab) {
|
||||
if ($tab instanceof DataTable\Map
|
||||
|| $tab instanceof DataTable
|
||||
|| $tab instanceof DataTable\Simple) {
|
||||
$array[$key] = $this->convertDataTableToArray($tab);
|
||||
|
||||
if (!is_array($array[$key])) {
|
||||
$array[$key] = array('value' => $array[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$array = $this->convertDataTableToArray($table);
|
||||
}
|
||||
|
||||
if (!is_array($array)) {
|
||||
$array = array('value' => $array);
|
||||
}
|
||||
|
||||
// decode all entities
|
||||
$callback = function (&$value, $key) {
|
||||
if (is_string($value)) {
|
||||
$value = html_entity_decode($value, ENT_QUOTES, "UTF-8");
|
||||
};
|
||||
};
|
||||
array_walk_recursive($array, $callback);
|
||||
|
||||
$str = json_encode($array);
|
||||
|
||||
return $this->jsonpWrap($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @return string
|
||||
*/
|
||||
protected function jsonpWrap($str)
|
||||
{
|
||||
if (($jsonCallback = Common::getRequestVar('callback', false)) === false)
|
||||
$jsonCallback = Common::getRequestVar('jsoncallback', false);
|
||||
if ($jsonCallback !== false) {
|
||||
if (preg_match('/^[0-9a-zA-Z_.]*$/D', $jsonCallback) > 0) {
|
||||
$str = $jsonCallback . "(" . $str . ")";
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the http header for json file
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
self::sendHeaderJSON();
|
||||
ProxyHttp::overrideCacheControlHeaders();
|
||||
}
|
||||
|
||||
public static function sendHeaderJSON()
|
||||
{
|
||||
@header('Content-Type: application/json; charset=utf-8');
|
||||
}
|
||||
|
||||
private function convertDataTableToArray($table)
|
||||
{
|
||||
$renderer = new Php();
|
||||
$renderer->setTable($table);
|
||||
$renderer->setRenderSubTables($this->isRenderSubtables());
|
||||
$renderer->setSerialize(false);
|
||||
$renderer->setHideIdSubDatableFromResponse($this->hideIdSubDatatable);
|
||||
$array = $renderer->flatRender();
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
271
www/analytics/core/DataTable/Renderer/Php.php
Normal file
271
www/analytics/core/DataTable/Renderer/Php.php
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Exception;
|
||||
use Piwik\DataTable\Manager;
|
||||
use Piwik\DataTable\Renderer;
|
||||
use Piwik\DataTable\Simple;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Piwik;
|
||||
|
||||
/**
|
||||
* Returns the equivalent PHP array for a given DataTable.
|
||||
* You can specify in the constructor if you want the serialized version.
|
||||
* Please note that by default it will produce a flat version of the array.
|
||||
* See the method flatRender() for details. @see flatRender();
|
||||
*
|
||||
* Works with recursive DataTable (when a row can be associated with a subDataTable).
|
||||
*
|
||||
*/
|
||||
class Php extends Renderer
|
||||
{
|
||||
protected $prettyDisplay = false;
|
||||
protected $serialize = true;
|
||||
|
||||
/**
|
||||
* Enables/Disables serialize
|
||||
*
|
||||
* @param bool $bool
|
||||
*/
|
||||
public function setSerialize($bool)
|
||||
{
|
||||
$this->serialize = (bool)$bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/Disables pretty display
|
||||
*
|
||||
* @param bool $bool
|
||||
*/
|
||||
public function setPrettyDisplay($bool)
|
||||
{
|
||||
$this->prettyDisplay = (bool)$bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts current data table to string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$data = $this->render();
|
||||
if (!is_string($data)) {
|
||||
$data = serialize($data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @param null|DataTable|DataTable\Map|Simple $dataTable
|
||||
* @return string
|
||||
*/
|
||||
public function render($dataTable = null)
|
||||
{
|
||||
$this->renderHeader();
|
||||
|
||||
if (is_null($dataTable)) {
|
||||
$dataTable = $this->table;
|
||||
}
|
||||
$toReturn = $this->flatRender($dataTable);
|
||||
|
||||
if ($this->prettyDisplay) {
|
||||
if (!is_array($toReturn)) {
|
||||
$toReturn = unserialize($toReturn);
|
||||
}
|
||||
$toReturn = "<pre>" . var_export($toReturn, true) . "</pre>";
|
||||
}
|
||||
return $toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renderException()
|
||||
{
|
||||
$this->renderHeader();
|
||||
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
|
||||
$return = array('result' => 'error', 'message' => $exceptionMessage);
|
||||
|
||||
if ($this->serialize) {
|
||||
$return = serialize($return);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|DataTable|DataTable\Map|Simple $dataTable
|
||||
* @return array Php array representing the 'flat' version of the datatable
|
||||
*/
|
||||
public function flatRender($dataTable = null)
|
||||
{
|
||||
if (is_null($dataTable)) {
|
||||
$dataTable = $this->table;
|
||||
}
|
||||
|
||||
if (is_array($dataTable)) {
|
||||
$flatArray = $dataTable;
|
||||
if (self::shouldWrapArrayBeforeRendering($flatArray)) {
|
||||
$flatArray = array($flatArray);
|
||||
}
|
||||
} else if ($dataTable instanceof DataTable\Map) {
|
||||
$flatArray = array();
|
||||
foreach ($dataTable->getDataTables() as $keyName => $table) {
|
||||
$serializeSave = $this->serialize;
|
||||
$this->serialize = false;
|
||||
$flatArray[$keyName] = $this->flatRender($table);
|
||||
$this->serialize = $serializeSave;
|
||||
}
|
||||
} else if ($dataTable instanceof Simple) {
|
||||
$flatArray = $this->renderSimpleTable($dataTable);
|
||||
|
||||
// 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) {
|
||||
$flatArray = current($flatArray);
|
||||
}
|
||||
} // A normal DataTable needs to be handled specifically
|
||||
else {
|
||||
$array = $this->renderTable($dataTable);
|
||||
$flatArray = $this->flattenArray($array);
|
||||
}
|
||||
|
||||
if ($this->serialize) {
|
||||
$flatArray = serialize($flatArray);
|
||||
}
|
||||
|
||||
return $flatArray;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
protected function flattenArray($array)
|
||||
{
|
||||
$flatArray = array();
|
||||
foreach ($array as $row) {
|
||||
$newRow = $row['columns'] + $row['metadata'];
|
||||
if (isset($row['idsubdatatable'])
|
||||
&& $this->hideIdSubDatatable === false
|
||||
) {
|
||||
$newRow += array('idsubdatatable' => $row['idsubdatatable']);
|
||||
}
|
||||
if (isset($row['subtable'])) {
|
||||
$newRow += array('subtable' => $this->flattenArray($row['subtable']));
|
||||
}
|
||||
$flatArray[] = $newRow;
|
||||
}
|
||||
return $flatArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current data table to an array
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function originalRender()
|
||||
{
|
||||
Piwik::checkObjectTypeIs($this->table, array('Simple', 'DataTable'));
|
||||
|
||||
if ($this->table instanceof Simple) {
|
||||
$array = $this->renderSimpleTable($this->table);
|
||||
} elseif ($this->table instanceof DataTable) {
|
||||
$array = $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
if ($this->serialize) {
|
||||
$array = serialize($array);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given data table to an array
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @return array
|
||||
*/
|
||||
protected function renderTable($table)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
foreach ($table->getRows() as $id => $row) {
|
||||
$newRow = array(
|
||||
'columns' => $row->getColumns(),
|
||||
'metadata' => $row->getMetadata(),
|
||||
'idsubdatatable' => $row->getIdSubDataTable(),
|
||||
);
|
||||
|
||||
if ($id == DataTable::ID_SUMMARY_ROW) {
|
||||
$newRow['issummaryrow'] = true;
|
||||
}
|
||||
|
||||
if ($this->isRenderSubtables()
|
||||
&& $row->isSubtableLoaded()
|
||||
) {
|
||||
$subTable = $this->renderTable(Manager::getInstance()->getTable($row->getIdSubDataTable()));
|
||||
$newRow['subtable'] = $subTable;
|
||||
if ($this->hideIdSubDatatable === false
|
||||
&& isset($newRow['metadata']['idsubdatatable_in_db'])
|
||||
) {
|
||||
$newRow['columns']['idsubdatatable'] = $newRow['metadata']['idsubdatatable_in_db'];
|
||||
}
|
||||
unset($newRow['metadata']['idsubdatatable_in_db']);
|
||||
}
|
||||
if ($this->hideIdSubDatatable !== false) {
|
||||
unset($newRow['idsubdatatable']);
|
||||
}
|
||||
|
||||
$array[] = $newRow;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the simple data table to an array
|
||||
*
|
||||
* @param Simple $table
|
||||
* @return array
|
||||
*/
|
||||
protected function renderSimpleTable($table)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
$row = $table->getFirstRow();
|
||||
if ($row === false) {
|
||||
return $array;
|
||||
}
|
||||
foreach ($row->getColumns() as $columnName => $columnValue) {
|
||||
$array[$columnName] = $columnValue;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
207
www/analytics/core/DataTable/Renderer/Rss.php
Normal file
207
www/analytics/core/DataTable/Renderer/Rss.php
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Archive;
|
||||
use Piwik\Common;
|
||||
use Piwik\DataTable\Renderer;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\Date;
|
||||
use Piwik\SettingsPiwik;
|
||||
use Piwik\Url;
|
||||
|
||||
/**
|
||||
* RSS Feed.
|
||||
* The RSS renderer can be used only on Set that are arrays of DataTable.
|
||||
* A RSS feed contains one dataTable per element in the Set.
|
||||
*
|
||||
*/
|
||||
class Rss extends Renderer
|
||||
{
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function render()
|
||||
{
|
||||
$this->renderHeader();
|
||||
return $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function renderException()
|
||||
{
|
||||
header('Content-type: text/plain');
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
return 'Error: ' . $exceptionMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data table
|
||||
*
|
||||
* @param DataTable $table
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function renderTable($table)
|
||||
{
|
||||
if (!($table instanceof DataTable\Map)
|
||||
|| $table->getKeyName() != 'date'
|
||||
) {
|
||||
throw new Exception("RSS feeds can be generated for one specific website &idSite=X." .
|
||||
"\nPlease specify only one idSite or consider using &format=XML instead.");
|
||||
}
|
||||
|
||||
$idSite = Common::getRequestVar('idSite', 1, 'int');
|
||||
$period = Common::getRequestVar('period');
|
||||
|
||||
$piwikUrl = SettingsPiwik::getPiwikUrl()
|
||||
. "?module=CoreHome&action=index&idSite=" . $idSite . "&period=" . $period;
|
||||
$out = "";
|
||||
$moreRecentFirst = array_reverse($table->getDataTables(), true);
|
||||
foreach ($moreRecentFirst as $date => $subtable) {
|
||||
/** @var DataTable $subtable */
|
||||
$timestamp = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->getTimestamp();
|
||||
$site = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_SITE_INDEX);
|
||||
|
||||
$pudDate = date('r', $timestamp);
|
||||
|
||||
$dateInSiteTimezone = Date::factory($timestamp)->setTimezone($site->getTimezone())->toString('Y-m-d');
|
||||
$thisPiwikUrl = Common::sanitizeInputValue($piwikUrl . "&date=$dateInSiteTimezone");
|
||||
$siteName = $site->getName();
|
||||
$title = $siteName . " on " . $date;
|
||||
|
||||
$out .= "\t<item>
|
||||
<pubDate>$pudDate</pubDate>
|
||||
<guid>$thisPiwikUrl</guid>
|
||||
<link>$thisPiwikUrl</link>
|
||||
<title>$title</title>
|
||||
<author>http://piwik.org</author>
|
||||
<description>";
|
||||
|
||||
$out .= Common::sanitizeInputValue($this->renderDataTable($subtable));
|
||||
$out .= "</description>\n\t</item>\n";
|
||||
}
|
||||
|
||||
$header = $this->getRssHeader();
|
||||
$footer = $this->getRssFooter();
|
||||
|
||||
return $header . $out . $footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the xml file http header
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
@header('Content-Type: text/xml; charset=utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RSS file footer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRssFooter()
|
||||
{
|
||||
return "\t</channel>\n</rss>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RSS file header
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRssHeader()
|
||||
{
|
||||
$generationDate = date('r');
|
||||
$header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<rss version=\"2.0\">
|
||||
<channel>
|
||||
<title>piwik statistics - RSS</title>
|
||||
<link>http://piwik.org</link>
|
||||
<description>Piwik RSS feed</description>
|
||||
<pubDate>$generationDate</pubDate>
|
||||
<generator>piwik</generator>
|
||||
<language>en</language>
|
||||
<lastBuildDate>$generationDate</lastBuildDate>";
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DataTable $table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTable($table)
|
||||
{
|
||||
if ($table->getRowsCount() == 0) {
|
||||
return "<strong><em>Empty table</em></strong><br />\n";
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
$tableStructure = array();
|
||||
|
||||
/*
|
||||
* table = array
|
||||
* ROW1 = col1 | col2 | col3 | metadata | idSubTable
|
||||
* ROW2 = col1 | col2 (no value but appears) | col3 | metadata | idSubTable
|
||||
* subtable here
|
||||
*/
|
||||
$allColumns = array();
|
||||
foreach ($table->getRows() as $row) {
|
||||
foreach ($row->getColumns() as $column => $value) {
|
||||
// for example, goals data is array: not supported in export RSS
|
||||
// in the future we shall reuse ViewDataTable for html exports in RSS anyway
|
||||
if (is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
$allColumns[$column] = true;
|
||||
$tableStructure[$i][$column] = $value;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$html = "\n";
|
||||
$html .= "<table border=1 width=70%>";
|
||||
$html .= "\n<tr>";
|
||||
foreach ($allColumns as $name => $toDisplay) {
|
||||
if ($toDisplay !== false) {
|
||||
if ($this->translateColumnNames) {
|
||||
$name = $this->translateColumnName($name);
|
||||
}
|
||||
$html .= "\n\t<td><strong>$name</strong></td>";
|
||||
}
|
||||
}
|
||||
$html .= "\n</tr>";
|
||||
$colspan = count($allColumns);
|
||||
|
||||
foreach ($tableStructure as $row) {
|
||||
$html .= "\n\n<tr>";
|
||||
foreach ($allColumns as $columnName => $toDisplay) {
|
||||
if ($toDisplay !== false) {
|
||||
$value = "-";
|
||||
if (isset($row[$columnName])) {
|
||||
$value = urldecode($row[$columnName]);
|
||||
}
|
||||
|
||||
$html .= "\n\t<td>$value</td>";
|
||||
}
|
||||
}
|
||||
$html .= "</tr>";
|
||||
}
|
||||
$html .= "\n\n</table>";
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
39
www/analytics/core/DataTable/Renderer/Tsv.php
Normal file
39
www/analytics/core/DataTable/Renderer/Tsv.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
|
||||
/**
|
||||
* TSV export
|
||||
*
|
||||
* Excel doesn't import CSV properly, it expects TAB separated values by default.
|
||||
* TSV is therefore the 'CSV' that is Excel compatible
|
||||
*
|
||||
*/
|
||||
class Tsv extends Csv
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setSeparator("\t");
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function render()
|
||||
{
|
||||
return parent::render();
|
||||
}
|
||||
}
|
||||
443
www/analytics/core/DataTable/Renderer/Xml.php
Normal file
443
www/analytics/core/DataTable/Renderer/Xml.php
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\DataTable\Renderer;
|
||||
|
||||
use Exception;
|
||||
use Piwik\DataTable\Map;
|
||||
use Piwik\DataTable\Renderer;
|
||||
use Piwik\DataTable;
|
||||
use Piwik\DataTable\Simple;
|
||||
use Piwik\Piwik;
|
||||
|
||||
/**
|
||||
* XML export of a given DataTable.
|
||||
* See the tests cases for more information about the XML format (/tests/core/DataTable/Renderer.test.php)
|
||||
* Or have a look at the API calls examples.
|
||||
*
|
||||
* Works with recursive DataTable (when a row can be associated with a subDataTable).
|
||||
*
|
||||
*/
|
||||
class Xml extends Renderer
|
||||
{
|
||||
/**
|
||||
* Computes the dataTable output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function render()
|
||||
{
|
||||
$this->renderHeader();
|
||||
return '<?xml version="1.0" encoding="utf-8" ?>' . "\n" . $this->renderTable($this->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the exception output and returns the string/binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function renderException()
|
||||
{
|
||||
$this->renderHeader();
|
||||
|
||||
$exceptionMessage = $this->getExceptionMessage();
|
||||
|
||||
$return = '<?xml version="1.0" encoding="utf-8" ?>' . "\n" .
|
||||
"<result>\n" .
|
||||
"\t<error message=\"" . $exceptionMessage . "\" />\n" .
|
||||
"</result>";
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given data table to an array
|
||||
*
|
||||
* @param DataTable|DataTable/Map $table data table to convert
|
||||
* @return array
|
||||
*/
|
||||
protected function getArrayFromDataTable($table)
|
||||
{
|
||||
if (is_array($table)) {
|
||||
return $table;
|
||||
}
|
||||
|
||||
$renderer = new Php();
|
||||
$renderer->setRenderSubTables($this->isRenderSubtables());
|
||||
$renderer->setSerialize(false);
|
||||
$renderer->setTable($table);
|
||||
$renderer->setHideIdSubDatableFromResponse($this->hideIdSubDatatable);
|
||||
return $renderer->flatRender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data table
|
||||
*
|
||||
* @param DataTable|DataTable/Map $table
|
||||
* @param bool $returnOnlyDataTableXml
|
||||
* @param string $prefixLines
|
||||
* @return array|string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function renderTable($table, $returnOnlyDataTableXml = false, $prefixLines = '')
|
||||
{
|
||||
$array = $this->getArrayFromDataTable($table);
|
||||
if ($table instanceof Map) {
|
||||
$out = $this->renderDataTableMap($table, $array, $prefixLines);
|
||||
|
||||
if ($returnOnlyDataTableXml) {
|
||||
return $out;
|
||||
}
|
||||
$out = "<results>\n$out</results>";
|
||||
return $out;
|
||||
}
|
||||
|
||||
// integer value of ZERO is a value we want to display
|
||||
if ($array != 0 && empty($array)) {
|
||||
if ($returnOnlyDataTableXml) {
|
||||
throw new Exception("Illegal state, what xml shall we return?");
|
||||
}
|
||||
$out = "<result />";
|
||||
return $out;
|
||||
}
|
||||
if ($table instanceof Simple) {
|
||||
if (is_array($array)) {
|
||||
$out = $this->renderDataTableSimple($array);
|
||||
} else {
|
||||
$out = $array;
|
||||
}
|
||||
if ($returnOnlyDataTableXml) {
|
||||
return $out;
|
||||
}
|
||||
|
||||
if (is_array($array)) {
|
||||
$out = "<result>\n" . $out . "</result>";
|
||||
} else {
|
||||
$value = self::formatValueXml($out);
|
||||
if ($value === '') {
|
||||
$out = "<result />";
|
||||
} else {
|
||||
$out = "<result>" . $value . "</result>";
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
if ($table instanceof DataTable) {
|
||||
$out = $this->renderDataTable($array);
|
||||
if ($returnOnlyDataTableXml) {
|
||||
return $out;
|
||||
}
|
||||
$out = "<result>\n$out</result>";
|
||||
return $out;
|
||||
}
|
||||
|
||||
if (is_array($array)) {
|
||||
$out = $this->renderArray($array, $prefixLines . "\t");
|
||||
if ($returnOnlyDataTableXml) {
|
||||
return $out;
|
||||
}
|
||||
return "<result>\n$out</result>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an array as XML.
|
||||
*
|
||||
* @param array $array The array to render.
|
||||
* @param string $prefixLines The string to prefix each line in the output.
|
||||
* @return string
|
||||
*/
|
||||
private function renderArray($array, $prefixLines)
|
||||
{
|
||||
$isAssociativeArray = Piwik::isAssociativeArray($array);
|
||||
|
||||
// check if array contains arrays, and if not wrap the result in an extra <row> element
|
||||
// (only check if this is the root renderArray call)
|
||||
// NOTE: this is for backwards compatibility. before, array's were added to a new DataTable.
|
||||
// if the array had arrays, they were added as multiple rows, otherwise it was treated as
|
||||
// one row. removing will change API output.
|
||||
$wrapInRow = $prefixLines === "\t"
|
||||
&& self::shouldWrapArrayBeforeRendering($array, $wrapSingleValues = false, $isAssociativeArray);
|
||||
|
||||
// render the array
|
||||
$result = "";
|
||||
if ($wrapInRow) {
|
||||
$result .= "$prefixLines<row>\n";
|
||||
$prefixLines .= "\t";
|
||||
}
|
||||
foreach ($array as $key => $value) {
|
||||
// based on the type of array & the key, determine how this node will look
|
||||
if ($isAssociativeArray) {
|
||||
$keyIsInvalidXmlElement = is_numeric($key) || is_numeric($key[0]);
|
||||
if ($keyIsInvalidXmlElement) {
|
||||
$prefix = "<row key=\"$key\">";
|
||||
$suffix = "</row>";
|
||||
$emptyNode = "<row key=\"$key\"/>";
|
||||
} else if (strpos($key, '=') !== false) {
|
||||
list($keyAttributeName, $key) = explode('=', $key, 2);
|
||||
|
||||
$prefix = "<row $keyAttributeName=\"$key\">";
|
||||
$suffix = "</row>";
|
||||
$emptyNode = "<row $keyAttributeName=\"$key\">";
|
||||
} else {
|
||||
$prefix = "<$key>";
|
||||
$suffix = "</$key>";
|
||||
$emptyNode = "<$key />";
|
||||
}
|
||||
} else {
|
||||
$prefix = "<row>";
|
||||
$suffix = "</row>";
|
||||
$emptyNode = "<row/>";
|
||||
}
|
||||
|
||||
// render the array item
|
||||
if (is_array($value)) {
|
||||
$result .= $prefixLines . $prefix . "\n";
|
||||
$result .= $this->renderArray($value, $prefixLines . "\t");
|
||||
$result .= $prefixLines . $suffix . "\n";
|
||||
} else if ($value instanceof DataTable
|
||||
|| $value instanceof Map
|
||||
) {
|
||||
if ($value->getRowsCount() == 0) {
|
||||
$result .= $prefixLines . $emptyNode . "\n";
|
||||
} else {
|
||||
$result .= $prefixLines . $prefix . "\n";
|
||||
if ($value instanceof Map) {
|
||||
$result .= $this->renderDataTableMap($value, $this->getArrayFromDataTable($value), $prefixLines);
|
||||
} else if ($value instanceof Simple) {
|
||||
$result .= $this->renderDataTableSimple($this->getArrayFromDataTable($value), $prefixLines);
|
||||
} else {
|
||||
$result .= $this->renderDataTable($this->getArrayFromDataTable($value), $prefixLines);
|
||||
}
|
||||
$result .= $prefixLines . $suffix . "\n";
|
||||
}
|
||||
} else {
|
||||
$xmlValue = self::formatValueXml($value);
|
||||
if (strlen($xmlValue) != 0) {
|
||||
$result .= $prefixLines . $prefix . $xmlValue . $suffix . "\n";
|
||||
} else {
|
||||
$result .= $prefixLines . $emptyNode . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($wrapInRow) {
|
||||
$result .= substr($prefixLines, 0, strlen($prefixLines) - 1) . "</row>\n";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data table array
|
||||
*
|
||||
* @param Map $table
|
||||
* @param array $array
|
||||
* @param string $prefixLines
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTableMap($table, $array, $prefixLines = "")
|
||||
{
|
||||
// CASE 1
|
||||
//array
|
||||
// 'day1' => string '14' (length=2)
|
||||
// 'day2' => string '6' (length=1)
|
||||
$firstTable = current($array);
|
||||
if (!is_array($firstTable)) {
|
||||
$xml = '';
|
||||
$nameDescriptionAttribute = $table->getKeyName();
|
||||
foreach ($array as $valueAttribute => $value) {
|
||||
if (empty($value)) {
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";
|
||||
} elseif ($value instanceof Map) {
|
||||
$out = $this->renderTable($value, true);
|
||||
//TODO somehow this code is not tested, cover this case
|
||||
$xml .= "\t<result $nameDescriptionAttribute=\"$valueAttribute\">\n$out</result>\n";
|
||||
} else {
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">" . self::formatValueXml($value) . "</result>\n";
|
||||
}
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
$subTables = $table->getDataTables();
|
||||
$firstTable = current($subTables);
|
||||
|
||||
// CASE 2
|
||||
//array
|
||||
// 'day1' =>
|
||||
// array
|
||||
// 'nb_uniq_visitors' => string '18'
|
||||
// 'nb_visits' => string '101'
|
||||
// 'day2' =>
|
||||
// array
|
||||
// 'nb_uniq_visitors' => string '28'
|
||||
// 'nb_visits' => string '11'
|
||||
if ($firstTable instanceof Simple) {
|
||||
$xml = '';
|
||||
$nameDescriptionAttribute = $table->getKeyName();
|
||||
foreach ($array as $valueAttribute => $dataTableSimple) {
|
||||
if (count($dataTableSimple) == 0) {
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\" />\n";
|
||||
} else {
|
||||
if (is_array($dataTableSimple)) {
|
||||
$dataTableSimple = "\n" . $this->renderDataTableSimple($dataTableSimple, $prefixLines . "\t") . $prefixLines . "\t";
|
||||
}
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">" . $dataTableSimple . "</result>\n";
|
||||
}
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
// CASE 3
|
||||
//array
|
||||
// 'day1' =>
|
||||
// array
|
||||
// 0 =>
|
||||
// array
|
||||
// 'label' => string 'phpmyvisites'
|
||||
// 'nb_uniq_visitors' => int 11
|
||||
// 'nb_visits' => int 13
|
||||
// 1 =>
|
||||
// array
|
||||
// 'label' => string 'phpmyvisits'
|
||||
// 'nb_uniq_visitors' => int 2
|
||||
// 'nb_visits' => int 2
|
||||
// 'day2' =>
|
||||
// array
|
||||
// 0 =>
|
||||
// array
|
||||
// 'label' => string 'piwik'
|
||||
// 'nb_uniq_visitors' => int 121
|
||||
// 'nb_visits' => int 130
|
||||
// 1 =>
|
||||
// array
|
||||
// 'label' => string 'piwik bis'
|
||||
// 'nb_uniq_visitors' => int 20
|
||||
// 'nb_visits' => int 120
|
||||
if ($firstTable instanceof DataTable) {
|
||||
$xml = '';
|
||||
$nameDescriptionAttribute = $table->getKeyName();
|
||||
foreach ($array as $keyName => $arrayForSingleDate) {
|
||||
$dataTableOut = $this->renderDataTable($arrayForSingleDate, $prefixLines . "\t");
|
||||
if (empty($dataTableOut)) {
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$keyName\" />\n";
|
||||
} else {
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$keyName\">\n";
|
||||
$xml .= $dataTableOut;
|
||||
$xml .= $prefixLines . "\t</result>\n";
|
||||
}
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
if ($firstTable instanceof Map) {
|
||||
$xml = '';
|
||||
$tables = $table->getDataTables();
|
||||
$nameDescriptionAttribute = $table->getKeyName();
|
||||
foreach ($tables as $valueAttribute => $tableInArray) {
|
||||
$out = $this->renderTable($tableInArray, true, $prefixLines . "\t");
|
||||
$xml .= $prefixLines . "\t<result $nameDescriptionAttribute=\"$valueAttribute\">\n" . $out . $prefixLines . "\t</result>\n";
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data array
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $prefixLine
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTable($array, $prefixLine = "")
|
||||
{
|
||||
$out = '';
|
||||
foreach ($array as $rowId => $row) {
|
||||
if (!is_array($row)) {
|
||||
$value = self::formatValueXml($row);
|
||||
if (strlen($value) == 0) {
|
||||
$out .= $prefixLine . "\t\t<$rowId />\n";
|
||||
} else {
|
||||
$out .= $prefixLine . "\t\t<$rowId>" . $value . "</$rowId>\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Handing case idgoal=7, creating a new array for that one
|
||||
$rowAttribute = '';
|
||||
if (($equalFound = strstr($rowId, '=')) !== false) {
|
||||
$rowAttribute = explode('=', $rowId);
|
||||
$rowAttribute = " " . $rowAttribute[0] . "='" . $rowAttribute[1] . "'";
|
||||
}
|
||||
$out .= $prefixLine . "\t<row$rowAttribute>";
|
||||
|
||||
if (count($row) === 1
|
||||
&& key($row) === 0
|
||||
) {
|
||||
$value = self::formatValueXml(current($row));
|
||||
$out .= $prefixLine . $value;
|
||||
} else {
|
||||
$out .= "\n";
|
||||
foreach ($row as $name => $value) {
|
||||
// handle the recursive dataTable case by XML outputting the recursive table
|
||||
if (is_array($value)) {
|
||||
$value = "\n" . $this->renderDataTable($value, $prefixLine . "\t\t");
|
||||
$value .= $prefixLine . "\t\t";
|
||||
} else {
|
||||
$value = self::formatValueXml($value);
|
||||
}
|
||||
if (strlen($value) == 0) {
|
||||
$out .= $prefixLine . "\t\t<$name />\n";
|
||||
} else {
|
||||
$out .= $prefixLine . "\t\t<$name>" . $value . "</$name>\n";
|
||||
}
|
||||
}
|
||||
$out .= "\t";
|
||||
}
|
||||
$out .= $prefixLine . "</row>\n";
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the output for the given data array (representing a simple data table)
|
||||
*
|
||||
* @param $array
|
||||
* @param string $prefixLine
|
||||
* @return string
|
||||
*/
|
||||
protected function renderDataTableSimple($array, $prefixLine = "")
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array('value' => $array);
|
||||
}
|
||||
|
||||
$out = '';
|
||||
foreach ($array as $keyName => $value) {
|
||||
$xmlValue = self::formatValueXml($value);
|
||||
if (strlen($xmlValue) == 0) {
|
||||
$out .= $prefixLine . "\t<$keyName />\n";
|
||||
} else {
|
||||
$out .= $prefixLine . "\t<$keyName>" . $xmlValue . "</$keyName>\n";
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the XML headers
|
||||
*/
|
||||
protected function renderHeader()
|
||||
{
|
||||
// silent fail because otherwise it throws an exception in the unit tests
|
||||
@header('Content-Type: text/xml; charset=utf-8');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue