/** * See {@link ColumnCallbackAddMetadata}. * * @param DataTable $table */ public function filter($table) { if ($this->applyToSummaryRow) { $rows = $table->getRows(); } else { $rows = $table->getRowsWithoutSummaryRow(); } foreach ($rows as $key => $row) { $parameters = array(); foreach ($this->columnsToRead as $columnsToRead) { $parameters[] = $row->getColumn($columnsToRead); } if (!is_null($this->functionParameters)) { $parameters = array_merge($parameters, $this->functionParameters); } if (!is_null($this->functionToApply)) { $newValue = call_user_func_array($this->functionToApply, $parameters); } else { $newValue = $parameters[0]; } if ($newValue !== false) { $row->addMetadata($this->metadataToAdd, $newValue); } } }
/** * See {@link GroupBy}. * * @param DataTable $table */ public function filter($table) { /** @var Row[] $groupByRows */ $groupByRows = array(); $nonGroupByRowIds = array(); foreach ($table->getRowsWithoutSummaryRow() as $rowId => $row) { $groupByColumnValue = $row->getColumn($this->groupByColumn); $groupByValue = $groupByColumnValue; // reduce the group by column of this row if ($this->reduceFunction) { $parameters = array_merge(array($groupByColumnValue), $this->parameters); $groupByValue = call_user_func_array($this->reduceFunction, $parameters); } if (!isset($groupByRows[$groupByValue])) { // if we haven't encountered this group by value before, we mark this row as a // row to keep, and change the group by column to the reduced value. $groupByRows[$groupByValue] = $row; $row->setColumn($this->groupByColumn, $groupByValue); } else { // if we have already encountered this group by value, we add this row to the // row that will be kept, and mark this one for deletion $groupByRows[$groupByValue]->sumRow($row, $copyMeta = true, $table->getMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME)); $nonGroupByRowIds[] = $rowId; } } if ($this->groupByColumn === 'label') { $table->setLabelsHaveChanged(); } // delete the unneeded rows. $table->deleteRows($nonGroupByRowIds); }
/** * See {@link AddSegmentByLabel}. * * @param DataTable $table */ public function filter($table) { if (empty($this->segments)) { $msg = 'AddSegmentByLabel is called without having any segments defined'; Development::error($msg); return; } if (count($this->segments) === 1) { $segment = reset($this->segments); foreach ($table->getRowsWithoutSummaryRow() as $key => $row) { $label = $row->getColumn('label'); if (!empty($label)) { $row->setMetadata('segment', $segment . '==' . urlencode($label)); } } } else { if (!empty($this->delimiter)) { $numSegments = count($this->segments); $conditionAnd = ';'; foreach ($table->getRowsWithoutSummaryRow() as $key => $row) { $label = $row->getColumn('label'); if (!empty($label)) { $parts = explode($this->delimiter, $label); if (count($parts) === $numSegments) { $filter = array(); foreach ($this->segments as $index => $segment) { if (!empty($segment)) { $filter[] = $segment . '==' . urlencode($parts[$index]); } } $row->setMetadata('segment', implode($conditionAnd, $filter)); } } } } else { $names = implode(', ', $this->segments); $msg = 'Multiple segments are given but no delimiter defined. Segments: ' . $names; Development::error($msg); } } }
/** * Sums a tables row with this one. * * @param DataTable $table */ private function sumTable($table) { $metadata = $table->getMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME); $enableCopyMetadata = false; foreach ($table->getRowsWithoutSummaryRow() as $row) { $this->sumRow($row, $enableCopyMetadata, $metadata); } $summaryRow = $table->getRowFromId(DataTable::ID_SUMMARY_ROW); if ($summaryRow) { $this->sumRow($summaryRow, $enableCopyMetadata, $metadata); } }
/** * @param DataTable $table */ public function filter($table) { // the htmlspecialchars_decode call is for BC for before 1.1 // as the Referrer URL was previously encoded in the log tables, but is now recorded raw $table->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', function ($label) { return htmlspecialchars_decode($label); })); $table->queueFilter('ColumnCallbackReplace', array('label', 'Piwik\\Plugins\\Referrers\\getPathFromUrl')); foreach ($table->getRowsWithoutSummaryRow() as $row) { $subtable = $row->getSubtable(); if ($subtable) { $this->filter($subtable); } } }
/** * See {@link MetadataCallbackAddMetadata}. * * @param DataTable $table */ public function filter($table) { if ($this->applyToSummaryRow) { $rows = $table->getRows(); } else { $rows = $table->getRowsWithoutSummaryRow(); } foreach ($rows as $key => $row) { $params = array(); foreach ($this->metadataToRead as $name) { $params[] = $row->getMetadata($name); } $newValue = call_user_func_array($this->functionToApply, $params); if ($newValue !== false) { $row->addMetadata($this->metadataToAdd, $newValue); } } }
/** * See {@link ReplaceSummaryRowLabel}. * * @param DataTable $table */ public function filter($table) { $row = $table->getRowFromId(DataTable::ID_SUMMARY_ROW); if ($row) { $row->setColumn('label', $this->newLabel); } else { $row = $table->getRowFromLabel(DataTable::LABEL_SUMMARY_ROW); if ($row) { $row->setColumn('label', $this->newLabel); } } // recurse foreach ($table->getRowsWithoutSummaryRow() as $row) { $subTable = $row->getSubtable(); if ($subTable) { $this->filter($subTable); } } }
/** * @param DataTable $table */ public function filter($table) { $table->filter(function (DataTable $dataTable) { foreach ($dataTable->getRows() as $row) { $url = $row->getMetadata('url'); if ($url) { $row->setMetadata('segmentValue', urldecode($url)); } } }); // TODO can we remove this one again? $table->queueFilter('GroupBy', array('label', function ($label) { return urldecode($label); })); foreach ($table->getRowsWithoutSummaryRow() as $row) { $subtable = $row->getSubtable(); if ($subtable) { $this->filter($subtable); } } }
/** * Sums a DataTable to this one. * * This method will sum rows that have the same label. If a row is found in `$tableToSum` whose * label is not found in `$this`, the row will be added to `$this`. * * If the subtables for this table are loaded, they will be summed as well. * * Rows are summed together by summing individual columns. By default columns are summed by * adding one column value to another. Some columns cannot be aggregated this way. In these * cases, the {@link COLUMN_AGGREGATION_OPS_METADATA_NAME} * metadata can be used to specify a different type of operation. * * @param \Piwik\DataTable $tableToSum * @throws Exception */ public function addDataTable(DataTable $tableToSum) { if ($tableToSum instanceof Simple) { if ($tableToSum->getRowsCount() > 1) { throw new Exception("Did not expect a Simple table with more than one row in addDataTable()"); } $row = $tableToSum->getFirstRow(); $this->aggregateRowFromSimpleTable($row); } else { $columnAggregationOps = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME); foreach ($tableToSum->getRowsWithoutSummaryRow() as $row) { $this->aggregateRowWithLabel($row, $columnAggregationOps); } // we do not use getRows() as this method might get called 100k times when aggregating many datatables and // this takes a lot of time. $row = $tableToSum->getRowFromId(DataTable::ID_SUMMARY_ROW); if ($row) { $this->aggregateRowWithLabel($row, $columnAggregationOps); } } }
/** * Creates DataTables from $dataTable's subtable blobs (stored in $blobRow) and sets * the subtable IDs of each DataTable row. * * @param DataTable $dataTable * @param array $blobRow An array associating record names (w/ subtable if applicable) * with blob values. This should hold every subtable blob for * the loaded DataTable. * @param int $treeLevel */ private function setSubtables($dataTable, $blobRow, $treeLevel = 0) { if ($this->maxSubtableDepth && $treeLevel >= $this->maxSubtableDepth) { // unset the subtables so DataTableManager doesn't throw foreach ($dataTable->getRowsWithoutSummaryRow() as $row) { $row->removeSubtable(); } return; } $dataName = reset($this->dataNames); foreach ($dataTable->getRowsWithoutSummaryRow() as $row) { $sid = $row->getIdSubDataTable(); if ($sid === null) { continue; } $blobName = $dataName . "_" . $sid; if (isset($blobRow[$blobName])) { $subtable = DataTable::fromSerializedArray($blobRow[$blobName]); $this->setSubtables($subtable, $blobRow, $treeLevel + 1); // we edit the subtable ID so that it matches the newly table created in memory // NB: we dont overwrite the datatableid in the case we are displaying the table expanded. if ($this->addMetadataSubtableId) { // this will be written back to the column 'idsubdatatable' just before rendering, // see Renderer/Php.php $row->addMetadata('idsubdatatable_in_db', $row->getIdSubDataTable()); } $row->setSubtable($subtable); } } }
/** * @param DataTable $table * @param string|int $columnToSort A column name or column id. Make sure that column actually exists in the row. * You might want to get a valid column via {@link getPrimaryColumnToSort()} or * {@link getSecondaryColumnToSort()} * @return int */ public function getBestSortFlags(DataTable $table, $columnToSort) { // when column is label we always to sort by string or natural if (isset($columnToSort) && $columnToSort !== 'label') { foreach ($table->getRowsWithoutSummaryRow() as $row) { $value = $row->getColumn($columnToSort); if ($value !== false && $value !== null && !is_array($value)) { if (is_numeric($value)) { $sortFlags = SORT_NUMERIC; } else { $sortFlags = $this->getStringSortFlags(); } return $sortFlags; } } } return $this->getStringSortFlags(); }
/** * Sorts the DataTable rows using the supplied callback function. * * @param string $functionCallback A comparison callback compatible with {@link usort}. * @param string $columnSortedBy The column name `$functionCallback` sorts by. This is stored * so we can determine how the DataTable was sorted in the future. */ private function sort(DataTable $table, $functionCallback) { $table->setTableSortedBy($this->columnToSort); $rows = $table->getRowsWithoutSummaryRow(); // get column value and label only once for performance tweak $values = array(); if ($functionCallback === 'numberSort') { foreach ($rows as $key => $row) { $values[$key] = array($this->getColumnValue($row), $row->getColumn('label')); } } else { foreach ($rows as $key => $row) { $values[$key] = $this->getColumnValue($row); } } uasort($values, array($this, $functionCallback)); $sortedRows = array(); foreach ($values as $key => $value) { $sortedRows[] = $rows[$key]; } $table->setRows($sortedRows); unset($rows); unset($sortedRows); if ($table->isSortRecursiveEnabled()) { foreach ($table->getRowsWithoutSummaryRow() as $row) { $subTable = $row->getSubtable(); if ($subTable) { $subTable->enableRecursiveSort(); $this->sort($subTable, $functionCallback); } } } }