/** * @param Piwik_DataTable_Row $row * @param Piwik_DataTable $dataTable * @param string $date * @param string $labelPrefix * @param bool $parentLogo */ private function flattenRow(Piwik_DataTable_Row $row, Piwik_DataTable $dataTable, $date, $labelPrefix = '', $parentLogo = false) { $label = $row->getColumn('label'); if ($label !== false) { $label = trim($label); if (substr($label, 0, 1) == '/' && $this->recursiveLabelSeparator == '/') { $label = substr($label, 1); } $label = $labelPrefix . $label; $row->setColumn('label', $label); } $logo = $row->getMetadata('logo'); if ($logo === false && $parentLogo !== false) { $logo = $parentLogo; $row->setMetadata('logo', $logo); } $subTable = $this->loadSubtable($row, $date); $row->removeSubtable(); if ($subTable === null) { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 0); } $dataTable->addRow($row); } else { if ($this->includeAggregateRows) { $row->setMetadata('is_aggregate', 1); $dataTable->addRow($row); } $prefix = $label . $this->recursiveLabelSeparator; foreach ($subTable->getRows() as $row) { $this->flattenRow($row, $dataTable, $date, $prefix, $logo); } } }
/** * Loads in the DataTable the array information * @param array Array containing the rows information * array( * 'Label row 1' => Value row 1, * 'Label row 2' => Value row 2, * ) * @return void */ function loadFromArray($array) { foreach ($array as $label => $value) { $row = new Piwik_DataTable_Row(); $row->addColumn('label', $label); $row->addColumn('value', $value); $this->addRow($row); } }
public function getCompetitionDatatable() { $dataTable = new Piwik_DataTable(); $row1 = new Piwik_DataTable_Row(); $row1->setColumns(array('name' => 'piwik', 'license' => 'GPL')); $dataTable->addRow($row1); $dataTable->addRowFromSimpleArray(array('name' => 'google analytics', 'license' => 'commercial')); return $dataTable; }
/** * Filters a subtable * * @param Piwik_DataTable_Row $row * @return mixed */ public function filterSubTable(Piwik_DataTable_Row $row) { if (!$this->enableRecursive) { return; } if ($row->isSubtableLoaded()) { $subTable = Piwik_DataTable_Manager::getInstance()->getTable($row->getIdSubDataTable()); $this->filter($subTable); } }
public function filterSubTable(Piwik_DataTable_Row $row) { if (!$this->enableRecursive) { return; } try { $subTable = Piwik_DataTable_Manager::getInstance()->getTable($row->getIdSubDataTable()); $this->filter($subTable); } catch (Exception $e) { // case idSubTable == null, or if the table is not loaded in memory } }
/** * @param Piwik_DataTable $subTable */ function __construct($subTable = null) { parent::__construct(); if ($subTable !== null) { $this->sumTable($subTable); } }
function __construct($subTable) { parent::__construct(); foreach ($subTable->getRows() as $row) { $this->sumRow($row); } }
public function filter($table) { if($table->getRowsCount() <= $this->startRowToSummarize + 1) { return; } $table->filter('Sort', array( $this->columnToSortByBeforeTruncating, 'desc')); $rows = $table->getRows(); $count = $table->getRowsCount(); $newRow = new Piwik_DataTable_Row(); for($i = $this->startRowToSummarize; $i < $count; $i++) { if(!isset($rows[$i])) { // case when the last row is a summary row, it is not indexed by $cout but by Piwik_DataTable::ID_SUMMARY_ROW $summaryRow = $table->getRowFromId(Piwik_DataTable::ID_SUMMARY_ROW); $newRow->sumRow($summaryRow); } else { $newRow->sumRow($rows[$i]); } } $newRow->setColumns(array('label' => $this->labelSummaryRow) + $newRow->getColumns()); $table->filter('Limit', array(0, $this->startRowToSummarize)); $table->addSummaryRow($newRow); unset($rows); }
/** * Adds a summary row to the given data table * * @param Piwik_DataTable $table */ public function filter($table) { if ($table->getRowsCount() <= $this->startRowToSummarize + 1) { return; } $table->filter('Sort', array($this->columnToSortByBeforeTruncating, 'desc')); $rows = $table->getRows(); $count = $table->getRowsCount(); $newRow = new Piwik_DataTable_Row(); for ($i = $this->startRowToSummarize; $i < $count; $i++) { if (!isset($rows[$i])) { // case when the last row is a summary row, it is not indexed by $cout but by Piwik_DataTable::ID_SUMMARY_ROW $summaryRow = $table->getRowFromId(Piwik_DataTable::ID_SUMMARY_ROW); //FIXME: I'm not sure why it could return false, but it was reported in: http://forum.piwik.org/read.php?2,89324,page=1#msg-89442 if ($summaryRow) { $newRow->sumRow($summaryRow, $enableCopyMetadata = false); } } else { $newRow->sumRow($rows[$i], $enableCopyMetadata = false); } } $newRow->setColumns(array('label' => $this->labelSummaryRow) + $newRow->getColumns()); if ($this->deleteRows) { $table->filter('Limit', array(0, $this->startRowToSummarize)); } $table->addSummaryRow($newRow); unset($rows); }
/** * Returns column from a given row. * Will work with 2 types of datatable * - raw datatables coming from the archive DB, which columns are int indexed * - datatables processed resulting of API calls, which columns have human readable english names * * @param Piwik_DataTable_Row $row * @param int $columnIdRaw see consts in Piwik_Archive:: * @return mixed Value of column, false if not found */ protected function getColumn($row, $columnIdRaw, $mappingIdToName = false) { if (empty($mappingIdToName)) { $mappingIdToName = Piwik_Archive::$mappingFromIdToName; } $columnIdReadable = $mappingIdToName[$columnIdRaw]; if ($row instanceof Piwik_DataTable_Row) { $raw = $row->getColumn($columnIdRaw); if ($raw !== false) { return $raw; } return $row->getColumn($columnIdReadable); } if (isset($row[$columnIdRaw])) { return $row[$columnIdRaw]; } if (isset($row[$columnIdReadable])) { return $row[$columnIdReadable]; } return false; }
/** Get row evolution for a multiple labels */ private function getMultiRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $column, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true) { $actualLabels = $logos = array(); $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal); if (!isset($metadata['metrics'][$column])) { // invalid column => use the first one that's available $metrics = array_keys($metadata['metrics']); $column = reset($metrics); } // load the tables for each label $dataTablesPerLabel = array(); $dataTableMetadata = false; foreach ($labels as $labelIndex => $label) { $dataTable = $this->loadRowEvolutionDataFromAPI($idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $idGoal); $dataTablesPerLabel[$labelIndex] = $dataTable->getArray(); if (!$dataTableMetadata) { $dataTableMetadata = $dataTable->metadata; } $urlFound = false; foreach ($dataTablesPerLabel[$labelIndex] as $table) { if ($table->getRowsCount() > 0) { $firstRow = $table->getFirstRow(); // in case labels were replaced in the data table (e.g. for browsers report), // display the label from the table, not the one passed as filter $columnLabel = $firstRow->getColumn('label'); if (!empty($columnLabel)) { $actualLabels[$labelIndex] = $columnLabel; } list($actualLabel, $urlFound) = $this->cleanUrlForLabel($firstRow, $apiModule, $apiAction, $labelUseAbsoluteUrl); if ($actualLabel) { $actualLabels[$labelIndex] = $actualLabel; } // Forward the logo path to display logos in multi rows comparison $logos[$labelIndex] = $firstRow->getMetadata('logo'); break; } } if (!$urlFound) { $actualLabels[$labelIndex] = str_replace(Piwik_API_DataTableManipulator_LabelFilter::SEPARATOR_RECURSIVE_LABEL, ' - ', $label); } } // combine the tables $dataTableMulti = new Piwik_DataTable_Array(); $dataTableMulti->setKeyName($dataTable->getKeyName()); $dataTableMulti->metadata = $dataTableMetadata; foreach (array_keys(reset($dataTablesPerLabel)) as $dateLabel) { $newRow = new Piwik_DataTable_Row(); foreach ($dataTablesPerLabel as $labelIndex => $tableArray) { $table = $tableArray[$dateLabel]; if ($table->getRowsCount() == 0) { $value = 0; } else { $value = $table->getFirstRow()->getColumn($column); $value = floatVal(str_replace(',', '.', $value)); if ($value == '') { $value = 0; } } // keep metric in the label so that unit (%, s, ...) can be guessed correctly $label = $column . '_' . $labelIndex; $newRow->addColumn($label, $value); } $newTable = new Piwik_DataTable(); $newTable->addRow($newRow); $dataTableMulti->addTable($newTable, $dateLabel); } // the available metrics for the report are returned as metadata / columns $metadata['columns'] = $metadata['metrics']; // metadata / metrics should document the rows that are compared // this way, UI code can be reused $metadata['metrics'] = array(); foreach ($actualLabels as $labelIndex => $label) { if ($legendAppendMetric) { $label .= ' (' . $metadata['columns'][$column] . ')'; } $metricName = $column . '_' . $labelIndex; $metadata['metrics'][$metricName] = Piwik_DataTable_Filter_SafeDecodeLabel::safeDecodeLabel($label); if (!empty($logos[$labelIndex])) { $metadata['logos'][$metricName] = $logos[$labelIndex]; } } $this->enhanceRowEvolutionMetaData($metadata, $dataTableMulti); return array('column' => $column, 'reportData' => $dataTableMulti, 'metadata' => $metadata); }
/** * Utility function. Returns the current row in the past DataTable. * * @param Piwik_DataTable_Row $row The row in the 'current' DataTable. */ private function getPastRowFromCurrent($row) { return $this->pastDataTable->getRowFromLabel($row->getColumn('label')); }
/** * Helper function to test if two rows are equal. * * Two rows are equal * - if they have exactly the same columns / metadata * - if they have a subDataTable associated, then we check that both of them are the same. * * @param Piwik_DataTable_Row row1 to compare * @param Piwik_DataTable_Row row2 to compare * * @return bool */ public static function isEqual(Piwik_DataTable_Row $row1, Piwik_DataTable_Row $row2) { //same columns $cols1 = $row1->getColumns(); $cols2 = $row2->getColumns(); $diff1 = array_udiff($cols1, $cols2, array(__CLASS__, 'compareElements')); $diff2 = array_udiff($cols2, $cols1, array(__CLASS__, 'compareElements')); if ($diff1 != $diff2) { return false; } $dets1 = $row1->getMetadata(); $dets2 = $row2->getMetadata(); ksort($dets1); ksort($dets2); if ($dets1 != $dets2) { return false; } // either both are null // or both have a value if (!(is_null($row1->getIdSubDataTable()) && is_null($row2->getIdSubDataTable()))) { $subtable1 = Piwik_DataTable_Manager::getInstance()->getTable($row1->getIdSubDataTable()); $subtable2 = Piwik_DataTable_Manager::getInstance()->getTable($row2->getIdSubDataTable()); if (!Piwik_DataTable::isEqual($subtable1, $subtable2)) { return false; } } return true; }
/** * Helper function to test if two rows are equal. * * Two rows are equal * - if they have exactly the same columns / details * - if they have a subDataTable associated, then we check that both of them are the same. * * @param Piwik_DataTable_Row row1 to compare * @param Piwik_DataTable_Row row2 to compare * * @return bool */ public static function isEqual(Piwik_DataTable_Row $row1, Piwik_DataTable_Row $row2) { //same columns $cols1 = $row1->getColumns(); $cols2 = $row2->getColumns(); uksort($cols1, 'strnatcasecmp'); uksort($cols2, 'strnatcasecmp'); if ($cols1 != $cols2) { return false; } $dets1 = $row1->getDetails(); $dets2 = $row2->getDetails(); ksort($dets1); ksort($dets2); // same details if ($dets1 != $dets2) { return false; } // either both are null // or both have a value if (!(is_null($row1->getIdSubDataTable()) && is_null($row2->getIdSubDataTable()))) { $subtable1 = Piwik_DataTable_Manager::getInstance()->getTable($row1->getIdSubDataTable()); $subtable2 = Piwik_DataTable_Manager::getInstance()->getTable($row2->getIdSubDataTable()); if (!Piwik_DataTable::isEqual($subtable1, $subtable2)) { return false; } } return true; }
/** * Sets the column to be used for sorting * * @param Piwik_DataTable_Row $row * @return int */ protected function selectColumnToSort($row) { $value = $row->getColumn($this->columnToSort); if ($value !== false) { return $this->columnToSort; } // sorting by "nb_visits" but the index is Piwik_Archive::INDEX_NB_VISITS in the table if (isset(Piwik_Archive::$mappingFromNameToId[$this->columnToSort])) { $column = Piwik_Archive::$mappingFromNameToId[$this->columnToSort]; $value = $row->getColumn($column); if ($value !== false) { return $column; } } // eg. was previously sorted by revenue_per_visit, but this table // doesn't have this column; defaults with nb_visits $column = Piwik_Archive::INDEX_NB_VISITS; $value = $row->getColumn($column); if ($value !== false) { return $column; } // even though this column is not set properly in the table, // we select it for the sort, so that the table's internal state is set properly return $this->columnToSort; }
/** * Returns a custom data table. * This data table will be converted to all available formats * when requested in the API request. * * @return Piwik_DataTable */ public function getCompetitionDatatable() { $dataTable = new Piwik_DataTable(); $row1 = new Piwik_DataTable_Row(); $row1->setColumns(array('name' => 'piwik', 'license' => 'GPL')); // Rows Metadata is useful to store non stats data for example (logos, urls, etc.) // When printed out, they are simply merged with columns $row1->setMetadata('logo', 'logo.png'); $dataTable->addRow($row1); $dataTable->addRowFromSimpleArray(array('name' => 'google analytics', 'license' => 'commercial')); return $dataTable; }
protected function updateActionsTableWithRowQuery($query) { $rowsProcessed = 0; while ($row = $query->fetch()) { // in some unknown case, the type field is NULL, as reported in #1082 - we ignore this page view if (empty($row['type'])) { continue; } $actionExplodedNames = $this->getActionExplodedNames($row['name'], $row['type']); // we work on the root table of the given TYPE (either ACTION_URL or DOWNLOAD or OUTLINK etc.) $currentTable =& $this->actionsTablesByType[$row['type']]; // go to the level of the subcategory $end = count($actionExplodedNames) - 1; for ($level = 0; $level < $end; $level++) { $actionCategory = $actionExplodedNames[$level]; $currentTable =& $currentTable[$actionCategory]; } $actionName = $actionExplodedNames[$end]; // we are careful to prefix the page URL / name with some value // so that if a page has the same name as a category // we don't merge both entries if ($row['type'] == Piwik_Tracker_Action::TYPE_ACTION_URL) { $actionName = '/' . $actionName; } else { $actionName = ' ' . $actionName; } // currentTable is now the array element corresponding the the action // at this point we may be for example at the 4th level of depth in the hierarchy $currentTable =& $currentTable[$actionName]; // add the row to the matching sub category subtable if (!$currentTable instanceof Piwik_DataTable_Row) { if ($row['type'] == Piwik_Tracker_Action::TYPE_ACTION_NAME) { $currentTable = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => (string) $actionName))); } else { $currentTable = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => (string) $actionName), Piwik_DataTable_Row::METADATA => array('url' => (string) $row['name']))); } } foreach ($row as $name => $value) { // we don't add this information as itnot pertinent // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate. if ($name != 'name' && $name != 'type') { // in some edge cases, we have twice the same action name with 2 different idaction // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page, // and in between the two the other visitor comes. // here we handle the case where there is already a row for this action name, if this is the case we add the value if (($alreadyValue = $currentTable->getColumn($name)) !== false) { $currentTable->setColumn($name, $alreadyValue + $value); } else { $currentTable->addColumn($name, $value); } } } // if the exit_action was not recorded properly in the log_link_visit_action // there would be an error message when getting the nb_hits column // we must fake the record and add the columns if ($currentTable->getColumn('nb_hits') === false) { // to test this code: delete the entries in log_link_action_visit for // a given exit_idaction_url foreach ($this->defaultRow->getColumns() as $name => $value) { $currentTable->addColumn($name, $value); } } // simple count $rowsProcessed++; } // just to make sure php copies the last $currentTable in the $parentTable array $currentTable =& $this->actionsTablesByType; return $rowsProcessed; }
/** * Simple test of the DataTable_Row */ function test_sumRow() { $columns = array('test_int' => 145, 'test_float' => 145.5, 'test_float3' => 1.5, 'test_stringint' => "145", "test" => 'string fake', 'super' => array('this column has an array string that will be 0 when algorithm sums the value'), 'integerArrayToSum' => array(1 => 1, 2 => 10.0, 3 => array(1 => 2, 2 => 3))); $metadata = array('logo' => 'piwik.png', 'super' => array('this column has an array value, amazing')); $arrayRow = array(Piwik_DataTable_Row::COLUMNS => $columns, Piwik_DataTable_Row::METADATA => $metadata, 'fake useless key' => 38959, 43905724897 => 'value'); $row1 = new Piwik_DataTable_Row($arrayRow); $columns2 = array('test_int' => 5, 'test_float' => 4.5, 'test_float2' => 14.5, 'test_stringint' => "5", 00 => 'toto', 'super' => array('this column has geagaean array value, amazing'), 'integerArrayToSum' => array(1 => 5, 2 => 5.5, 3 => array(2 => 4))); $finalRow = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => $columns2)); $finalRow->sumRow($row1); $columnsWanted = array('test_int' => 150, 'test_float' => 150.0, 'test_float2' => 14.5, 'test_float3' => 1.5, 'test_stringint' => 150, 'super' => array(0), 'test' => 0, 'integerArrayToSum' => array(1 => 6, 2 => 15.5, 3 => array(1 => 2, 2 => 7)), 00 => 'toto'); $rowWanted = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => $columnsWanted)); $this->assertTrue(Piwik_DataTable_Row::isEqual($rowWanted, $finalRow)); }
public function test_whenRowsInRandomOrderButSortSpecified_shouldComputeSummaryRowAfterSort() { $table = new Piwik_DataTable(); $table->addRow($this->getRow3()); $table->addRow($this->getRow2()); $table->addRow($this->getRow4()); $table->addRow($this->getRow1()); $table->addRow($this->getRow0()); $filter = new Piwik_DataTable_Filter_AddSummaryRow($table, 2, Piwik_DataTable::LABEL_SUMMARY_ROW, $columnToSortBy = 'nb'); $this->assertEqual($table->getRowsCount(), 3); $expectedRow = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => Piwik_DataTable::LABEL_SUMMARY_ROW, 'nb' => 111))); $this->assertTrue(Piwik_DataTable_Row::isEqual($table->getLastRow(), $expectedRow)); }
/** * Returns the divisor to use when calculating the new column value. Can * be overridden by descendent classes to customize behavior. * * @param Piwik_DataTable_Row $row The row being modified. * @return int|float */ protected function getDivisor($row) { if (!is_null($this->totalValueUsedAsDivisor)) { return $this->totalValueUsedAsDivisor; } else { return $row->getColumn($this->columnNameUsedAsDivisor); } }
/** * @param Piwik_DataTable_Row $row * @param string $metadataToFilter * @return array|false|mixed */ protected function getElementToReplace($row, $metadataToFilter) { return $row->getMetadata($metadataToFilter); }
/** * Returns the divisor to use when calculating the new column value. Can * be overridden by descendent classes to customize behavior. * * @param Piwik_DataTable_Row $row The row being modified. * @return int|float */ protected function getDivisor($row) { if (!is_null($this->totalValueUsedAsDivisor)) { return $this->totalValueUsedAsDivisor; } else { if ($this->getDivisorFromSummaryRow) { $summaryRow = $this->table->getRowFromId(Piwik_DataTable::ID_SUMMARY_ROW); return $summaryRow->getColumn($this->columnNameUsedAsDivisor); } else { return $row->getColumn($this->columnNameUsedAsDivisor); } } }
/** * Returns the element that should be replaced * * @param Piwik_DataTable_Row $row * @param string $columnToFilter * @return mixed */ protected function getElementToReplace($row, $columnToFilter) { return $row->getColumn($columnToFilter); }
function test_generateDataTable_1row4level() { $table = new Piwik_DataTable(); $rowpagecat3 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => '123123', 'visits' => 3, 'actions' => 5))); $rowcat3 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => '789.654', 'visits' => 3, 'actions' => 5))); $rowcat2 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => 'cat2', 'visits' => 3, 'actions' => 5))); $rowcat1 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => array('label' => '&*()', 'visits' => 3, 'actions' => 5))); $subtablerowpagecat3 = new Piwik_DataTable(); $subtablerowpagecat3->addRow($rowpagecat3); $rowcat3->addSubtable($subtablerowpagecat3); $subtablecat2 = new Piwik_DataTable(); $subtablecat2->addRow($rowcat3); $rowcat2->addSubtable($subtablecat2); $subtablecat1 = new Piwik_DataTable(); $subtablecat1->addRow($rowcat2); $rowcat1->addSubtable($subtablecat1); //-- add $table->addRow($rowcat1); // WHAT WE TEST $input = array('&*()' => array('cat2' => array('789.654' => array('123123' => $rowpagecat3)))); $tableGenerated = Piwik_ArchiveProcessing_Day::generateDataTable($input); $r1 = new Piwik_DataTable_Renderer_Console(); $r1->setTable($table); $r2 = new Piwik_DataTable_Renderer_Console(); $r2->setTable($tableGenerated); $this->assertTrue(Piwik_DataTable::isEqual($table, $tableGenerated)); }
/** * @group Core * @group DataTable */ public function testSubDataTableIsDestructed() { $mockedDataTable = $this->getMock('Piwik_DataTable', array('__destruct')); $mockedDataTable->expects($this->once())->method('__destruct'); $rowBeingDestructed = new Piwik_DataTable_Row(); $rowBeingDestructed->setSubtable($mockedDataTable); destroy($rowBeingDestructed); }
/** * 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); }
/** Get row evolution for a multiple labels */ private function getMultiRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $column, $language = false) { $actualLabels = array(); $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $segment, $language); if (!isset($metadata['metrics'][$column])) { // invalid column => use the first one that's available $column = reset(array_keys($metadata['metrics'])); } // load the tables for each label $dataTablesPerLabel = array(); $dataTableMetadata = false; foreach ($labels as $labelIndex => $label) { $dataTable = $this->loadRowEvolutionData($idSite, $period, $date, $apiModule, $apiAction, $label, $segment); $dataTablesPerLabel[$labelIndex] = $dataTable->getArray(); if (!$dataTableMetadata) { $dataTableMetadata = $dataTable->metadata; } $urlFound = false; foreach ($dataTablesPerLabel[$labelIndex] as $table) { if ($table->getRowsCount() > 0) { $firstRow = $table->getFirstRow(); // in case labels were replaced in the data table (e.g. for browsers report), // display the label from the table, not the one passed as filter $columnLabel = $firstRow->getColumn('label'); if (!empty($columnLabel)) { $actualLabels[$labelIndex] = $columnLabel; // TODO: confirm we need this // special case: websites report //if ($apiAction == 'getWebsites') //{ // $actualLabels[$labelIndex] = html_entity_decode($actualLabels[$labelIndex]); //} } // if url is available as metadata, use it (only for actions reports) if ($url = $firstRow->getMetadata('url')) { $actualLabels[$labelIndex] = $url; $urlFound = true; } break; } } if (!$urlFound) { // if we have a recursive label and no url, use the path $actualLabels[$labelIndex] = str_replace(Piwik_API_DataTableLabelFilter::SEPARATOR_RECURSIVE_LABEL, ' - ', $label); } } // combine the tables $dataTable = new Piwik_DataTable_Array(); $dataTable->setKeyName($dataTable->getKeyName()); $dataTable->metadata = $dataTableMetadata; foreach (array_keys(reset($dataTablesPerLabel)) as $dateLabel) { $newRow = new Piwik_DataTable_Row(); foreach ($dataTablesPerLabel as $labelIndex => $tableArray) { $table = $tableArray[$dateLabel]; if ($table->getRowsCount() == 0) { $value = 0; } else { $value = $table->getFirstRow()->getColumn($column); $value = floatVal(str_replace(',', '.', $value)); if ($value == '') { $value = 0; } } // keep metric in the label so that unit (%, s, ...) can be guessed correctly $label = $column . '_' . $labelIndex; $newRow->addColumn($label, $value); } $newTable = new Piwik_DataTable(); $newTable->addRow($newRow); $dataTable->addTable($newTable, $dateLabel); } // the available metrics for the report are returned as metadata / availableColumns $metadata['availableColumns'] = $metadata['metrics']; // metadata / metrics should document the rows that are compared // this way, UI code can be reused $metadata['metrics'] = array(); foreach ($actualLabels as $labelIndex => $label) { $label .= ' (' . $metadata['availableColumns'][$column] . ')'; $metadata['metrics'][$column . '_' . $labelIndex] = $label; } $this->enhanceRowEvolutionMetaData($metadata, $dataTable); return array('column' => $column, 'data' => $dataTable, 'metadata' => $metadata); }
/** * Test that adding two string column values results in an exception. */ public function testSumRow_stringException() { $columns = array('super' => array('this column has an array string that will be 0 when algorithm sums the value')); $row1 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => $columns)); $columns2 = array('super' => array('this column has geagaean array value, amazing')); $row2 = new Piwik_DataTable_Row(array(Piwik_DataTable_Row::COLUMNS => $columns2)); try { $row2->sumRow($row1); $this->fail("sumRow did not throw when adding two string columns."); } catch (Exception $ex) { // pass } }
/** * Returns true if both DataTable are exactly the same. * Used in unit tests. * * @param Piwik_DataTable $table1 * @param Piwik_DataTable $table2 * @return bool */ public static function isEqual(Piwik_DataTable $table1, Piwik_DataTable $table2) { $rows1 = $table1->getRows(); $rows2 = $table2->getRows(); $table1->rebuildIndex(); $table2->rebuildIndex(); if ($table1->getRowsCount() != $table2->getRowsCount()) { return false; } foreach ($rows1 as $row1) { $row2 = $table2->getRowFromLabel($row1->getColumn('label')); if ($row2 === false || !Piwik_DataTable_Row::isEqual($row1, $row2)) { return false; } } return true; }
/** * Load the data tables from the API and combine them into a data table * that can be plotted */ protected function loadDataTable() { $metadata = false; $dataTableArrays = array(); // load the tables for each label foreach ($this->labels as $rowLabelIndex => $rowLabel) { // TODO this used to be: $_GET['label'] = $this->label = $rowLabel; // is the $_GET assignment obsolete after label filter refactorings? $this->label = $rowLabel; $table = $this->doLoadDataTable(); $dataTableArrays[$rowLabelIndex] = $table->getArray(); if (!$metadata) { $metadata = $table->metadata; } $urlFound = false; foreach ($dataTableArrays[$rowLabelIndex] as $table) { if ($table->getRowsCount() > 0) { $firstRow = $table->getFirstRow(); // in case labels were replaced in the data table (e.g. for browsers report), // display the label from the table, not the one passed as filter $label = $firstRow->getColumn('label'); if (!empty($label)) { $this->labels[$rowLabelIndex] = $label; // special case: websites report if ($this->apiMethod == 'Referers.getWebsites') { $this->labels[$rowLabelIndex] = html_entity_decode($this->labels[$rowLabelIndex]); $urlFound = true; } } // if url is available as metadata, use it (only for actions reports) if (substr($this->apiMethod, 0, 7) == 'Actions' && ($url = $firstRow->getMetadata('url'))) { $this->labels[$rowLabelIndex] = $url; $urlFound = true; } break; } } if (!$urlFound && strpos($rowLabel, Piwik_API_DataTableLabelFilter::RECURSIVE_LABEL_SEPARATOR) !== false) { // if we have a recursive label and no url, use the path $this->labels[$rowLabelIndex] = str_replace(Piwik_API_DataTableLabelFilter::RECURSIVE_LABEL_SEPARATOR, ' - ', $rowLabel); } } // combine the tables $dataTable = new Piwik_DataTable_Array(); $dataTable->metadata = $metadata; foreach (array_keys(reset($dataTableArrays)) as $dateLabel) { $newRow = new Piwik_DataTable_Row(); foreach ($dataTableArrays as $rowLabelIndex => $tableArray) { $table = $tableArray[$dateLabel]; if ($table->getRowsCount() == 0) { $value = 0; } else { $value = $table->getFirstRow()->getColumn($this->metric); $value = floatVal(str_replace(',', '.', $value)); if ($value == '') { $value = 0; } } // keep metric in the label so that unit (%, s, ...) can be guessed correctly $label = $this->metric . '_' . $rowLabelIndex; $newRow->addColumn($label, $value); } $newTable = new Piwik_DataTable(); $newTable->addRow($newRow); $dataTable->addTable($newTable, $dateLabel); } // available metrics for metrics picker $this->metricsForSelect = $this->availableMetrics; $this->availableMetrics = array(); foreach ($this->labels as $rowLabelIndex => $label) { // add metric name $label .= ' (' . $this->metricsForSelect[$this->metric] . ')'; $this->availableMetrics[$this->metric . '_' . $rowLabelIndex] = $label; } return $dataTable; }