/** * 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); } }
/** 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); }
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; }
/** 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); }
/** * 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); }
/** * 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; }