/** * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Array * ordered by idsite * * @param array|string $fields array( fieldName1, fieldName2, ...) Names of the mysql table fields to load * @return Piwik_DataTable_Array */ public function getDataTableFromNumeric( $fields ) { $tableArray = $this->getNewDataTableArray(); if ($this->getFirstArchive() instanceof Piwik_Archive_Single) { $values = $this->getValues($fields); foreach($this->archives as $idSite => $archive) { $table = new Piwik_DataTable_Simple(); if (array_key_exists($idSite, $values)) { $table->addRowsFromArray($values[$idSite]); } $tableArray->addTable($table, $idSite); } } elseif ($this->getFirstArchive() instanceof Piwik_Archive_Array) { foreach($this->archives as $idSite => $archive) { $tableArray->addTable($archive->getDataTableFromNumeric($fields), $idSite); } } return $tableArray; }
/** * Enhance $simpleDataTable using metadata : * * - remove metrics based on $reportMetadata['metrics'] * - add 0 valued metrics if $simpleDataTable doesn't provide all $reportMetadata['metrics'] * - format metric values to a 'human readable' format * - extract row metadata to a separate Piwik_DataTable_Simple $rowsMetadata * * @param int $idSite enables monetary value formatting based on site currency * @param Piwik_DataTable_Simple $simpleDataTable * @param array $metadataColumns * @param boolean $hasDimension * @return array Piwik_DataTable $enhancedDataTable filtered metrics with human readable format & Piwik_DataTable_Simple $rowsMetadata */ private function handleSimpleDataTable($idSite, $simpleDataTable, $metadataColumns, $hasDimension) { // new DataTable to store metadata $rowsMetadata = new Piwik_DataTable(); // new DataTable to store 'human readable' values if ($hasDimension) { $enhancedDataTable = new Piwik_DataTable(); } else { $enhancedDataTable = new Piwik_DataTable_Simple(); } // add missing metrics foreach ($simpleDataTable->getRows() as $row) { $rowMetrics = $row->getColumns(); foreach ($metadataColumns as $id => $name) { if (!isset($rowMetrics[$id])) { $row->addColumn($id, 0); } } } foreach ($simpleDataTable->getRows() as $row) { $enhancedRow = new Piwik_DataTable_Row(); $enhancedDataTable->addRow($enhancedRow); $rowMetrics = $row->getColumns(); foreach ($rowMetrics as $columnName => $columnValue) { // filter metrics according to metadata definition if (isset($metadataColumns[$columnName])) { // generate 'human readable' metric values $prettyValue = Piwik::getPrettyValue($idSite, $columnName, $columnValue, false, false); $enhancedRow->addColumn($columnName, $prettyValue); } } // If report has a dimension, extract metadata into a distinct DataTable if ($hasDimension) { $rowMetadata = $row->getMetadata(); $idSubDataTable = $row->getIdSubDataTable(); // Create a row metadata only if there are metadata to insert if (count($rowMetadata) > 0 || !is_null($idSubDataTable)) { $metadataRow = new Piwik_DataTable_Row(); $rowsMetadata->addRow($metadataRow); foreach ($rowMetadata as $metadataKey => $metadataValue) { $metadataRow->addColumn($metadataKey, $metadataValue); } if (!is_null($idSubDataTable)) { $metadataRow->addColumn('idsubdatatable', $idSubDataTable); } } } } return array($enhancedDataTable, $rowsMetadata); }
/** * Given a list of fields defining numeric values, it will return a Piwik_DataTable_Simple * containing one row per field name. * * For example $fields = array( 'max_actions', * 'nb_uniq_visitors', * 'nb_visits', * 'nb_actions', * 'sum_visit_length', * 'bounce_count', * 'nb_visits_converted' * ); * * @param string|array $fields Name or array of names of Archive fields * * @return Piwik_DataTable_Simple */ public function getDataTableFromNumeric($fields) { if (!is_array($fields)) { $fields = array($fields); } $values = array(); foreach ($fields as $field) { $values[$field] = $this->getNumeric($field); } $table = new Piwik_DataTable_Simple(); $table->addRowsFromArray($values); return $table; }
protected function _getDataTableSimpleOneRowArrayTest() { $array1 = array('nb_visits' => 14.0); $table1 = new Piwik_DataTable_Simple(); $table1->addRowsFromArray($array1); $array2 = array('nb_visits' => 15.0); $table2 = new Piwik_DataTable_Simple(); $table2->addRowsFromArray($array2); $table3 = new Piwik_DataTable_Simple(); $table = new Piwik_DataTable_Array(); $table->setKeyName('testKey'); $table->addTable($table1, 'row1'); $table->addTable($table2, 'row2'); $table->addTable($table3, 'row3'); return $table; }
protected function handleScalar($scalar) { $dataTable = new Piwik_DataTable_Simple(); $dataTable->addRowsFromArray( array($scalar) ); return $this->getRenderedDataTable($dataTable); }
/** * Converts the simple data table to an array * * @param Piwik_DataTable_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; }
/** * Returns a DataTable_Array containing values * of the element $name from the archives in this Archive_Array. * * The value to be returned are blob values (stored in the archive_numeric_* tables in the DB). * * It can return anything from strings, to serialized PHP arrays or PHP objects, etc. * * @param string $name Name of the mysql table field to load eg. Referers_keywordBySearchEngine * @return Piwik_DataTable_Array containing the requested blob values for each Archive */ public function getBlob($name) { $table = $this->getNewDataTableArray(); foreach ($this->archives as $archive) { $blob = $archive->getBlob($name); $subTable = new Piwik_DataTable_Simple(); $subTable->addRowsFromArray(array('blob' => $blob)); $table->addTable($subTable, $this->getDataTableLabelValue($archive)); $this->loadMetadata($table, $archive); } return $table; }
/** * Convert a dimension-less report to a multi-row two-column data table * * @static * @param $reportMetadata array * @param $report Piwik_DataTable * @param $reportColumns array * @return array Piwik_DataTable $report & array $columns */ protected static function processTableFormat($reportMetadata, $report, $reportColumns) { $finalReport = $report; if (empty($reportMetadata['dimension'])) { // var_dump($report); $simpleReportMetrics = $report->getFirstRow(); if ($simpleReportMetrics) { $finalReport = new Piwik_DataTable_Simple(); foreach ($simpleReportMetrics->getColumns() as $metricId => $metric) { $newRow = new Piwik_DataTable_Row(); $newRow->addColumn("label", $reportColumns[$metricId]); $newRow->addColumn("value", $metric); $finalReport->addRow($newRow); } } $reportColumns = array('label' => Piwik_Translate('General_Name'), 'value' => Piwik_Translate('General_Value')); } return array($finalReport, $reportColumns); }
/** * Converts the output of the given simple data table * * @param Piwik_DataTable_Simple $table * @param array $allColumns * @return string */ protected function renderDataTable($table, &$allColumns = array()) { if ($table instanceof Piwik_DataTable_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 = array(); $columns = $row->getColumns(); foreach ($columns as $name => $value) { //goals => array( 'idgoal=1' =>array(..), 'idgoal=2' => array(..)) if (is_array($value)) { foreach ($value as $key => $subValues) { if (is_array($subValues)) { foreach ($subValues as $subKey => $subValue) { if ($this->translateColumnNames) { $subName = $name != 'goals' ? $name . ' ' . $key : Piwik_Translate('Goals_GoalX', $key); $columnName = $this->translateColumnName($subKey) . ' (' . $subName . ')'; } else { // goals_idgoal=1 $columnName = $name . "_" . $key . "_" . $subKey; } $allColumns[$columnName] = true; $csvRow[$columnName] = $subValue; } } } } else { $allColumns[$name] = true; $csvRow[$name] = $value; } } 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; } $allColumns[$name] = true; $csvRow[$name] = $value; } } 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; }
/** * Adds the given data table to the table structure array * * @param Piwik_DataTable_Simple $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 Piwik_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; }
/** * This method post processes the data resulting from the API call. * * - If the data resulted from the API call is a Piwik_DataTable then * - we apply the standard filters if the parameters have been found * in the URL. For example to offset,limit the Table you can add the following parameters to any API * call that returns a DataTable: filter_limit=10&filter_offset=20 * - we apply the filters that have been previously queued on the DataTable * @see Piwik_DataTable::queueFilter() * - we apply the renderer that generate the DataTable in a given format (XML, PHP, HTML, JSON, etc.) * the format can be changed using the 'format' parameter in the request. * Example: format=xml * * - If there is nothing returned (void) we display a standard success message * * - If there is a PHP array returned, we try to convert it to a dataTable * It is then possible to convert this datatable to any requested format (xml/etc) * * - If a bool is returned we convert to a string (true is displayed as 'true' false as 'false') * * - If an integer / float is returned, we simply return it * * @throws Exception If an object/resource is returned, if any of conversion fails, etc. * * @param mixed The initial returned value, before post process * @return mixed Usually a string, but can still be a PHP data structure if the format requested is 'original' */ protected function handleReturnedValue($returnedValue) { $toReturn = $returnedValue; // If the returned value is an object DataTable we // apply the set of generic filters if asked in the URL // and we render the DataTable according to the format specified in the URL if ($returnedValue instanceof Piwik_DataTable || $returnedValue instanceof Piwik_DataTable_Array) { if ($returnedValue instanceof Piwik_DataTable) { $this->applyDataTableGenericFilters($returnedValue); } elseif ($returnedValue instanceof Piwik_DataTable_Array) { $tables = $returnedValue->getArray(); foreach ($tables as $table) { $this->applyDataTableGenericFilters($table); } } // if the flag disable_queued_filters is defined we skip the filters that were queued // useful in some very rare cases but better to use this than a bad hack on the data returned... if (Piwik_Common::getRequestVar('disable_queued_filters', 'false', 'string', $this->requestToUse) == 'false') { $returnedValue->applyQueuedFilters(); } $toReturn = $this->getRenderedDataTable($returnedValue); } elseif (!isset($toReturn)) { $toReturn = $this->getStandardSuccessOutput($this->outputFormatRequested); } elseif (is_array($toReturn)) { if ($this->outputFormatRequested == 'original') { // we handle the serialization. Because some php array have a very special structure that // couldn't be converted with the automatic DataTable->loadFromSimpleArray // the user may want to request the original PHP data structure serialized by the API // in case he has to setup serialize=1 in the URL if ($this->caseRendererPHPSerialize($defaultSerialize = 0)) { $toReturn = serialize($toReturn); } } else { $dataTable = new Piwik_DataTable(); $dataTable->loadFromSimpleArray($toReturn); $toReturn = $this->getRenderedDataTable($dataTable); } } else { // original data structure requested, we return without process if ($this->outputFormatRequested == 'original') { return $toReturn; } if ($toReturn === true) { $toReturn = 'true'; } elseif ($toReturn === false) { $toReturn = 'false'; } elseif (is_object($toReturn) || is_resource($toReturn)) { return $this->getExceptionOutput(' The API cannot handle this data structure. You can get the data internally by directly using the class.', $this->outputFormatRequested); } require_once "DataTable/Simple.php"; $dataTable = new Piwik_DataTable_Simple(); $dataTable->loadFromArray(array($toReturn)); $toReturn = $this->getRenderedDataTable($dataTable); } return $toReturn; }
/** * Returns a DataTable_Simple with one row per field from $fields array names. * * @param string|array $fields Name or array of names of Archive fields * * @return Piwik_DataTable_Simple */ public function getDataTableFromNumeric($fields) { require_once "DataTable/Simple.php"; if (!is_array($fields)) { $fields = array($fields); } $values = array(); foreach ($fields as $field) { $values[$field] = $this->getNumeric($field); } $table = new Piwik_DataTable_Simple(); $table->loadFromArray($values); return $table; }