If {@link enableRecursiveFilters()} was called, the filter will be applied
to all subtables as well.
public filter ( string | Closur\Closure $className, array $parameters = [] ) | ||
$className | string | Closur\Closure | Class name, eg. `"Sort"` or "Piwik\DataTable\Filters\Sort"`. If no namespace is supplied, `Piwik\DataTable\BaseFilter` is assumed. This parameter can also be a closure that takes a DataTable as its first parameter. |
$parameters | array | Array of extra parameters to pass to the filter. |
public function test_filter_shouldIgnoreSummaryRow() { $row = $this->buildRow(array('label' => 'other')); $this->table->addSummaryRow($row); $this->table->filter($this->filter, array('UTC', 'day', 'today')); $this->assertFalse($row->getMetadata('segmentValue')); }
/** * @param DataTable $table */ public function filter($table) { // make url labels clickable $table->filter('ColumnCallbackAddMetadata', array('label', 'url')); // prettify the DataTable $table->filter('ColumnCallbackReplace', array('label', 'Piwik\\Plugins\\Referrers\\removeUrlProtocol')); $table->queueFilter('ReplaceColumnNames'); }
public function test_filter_shouldUrlEncodeValues() { $mapping = array(1 => 'Core tests', 3 => 'plugins tästs'); $this->table->filter($this->filter, array('segmentName', $mapping)); $metadata = $this->table->getRowsMetadata('segment'); $expected = array('segmentName==Core+tests', false, 'segmentName==plugins+t%C3%A4sts', false, false, false); $this->assertSame($expected, $metadata); }
public function test_filter_shouldOnlyPrependIfAMetadataNameIsSet() { $this->table->filter($this->filter, array('other', 'prependme')); $metadata = $this->table->getRowsMetadata('other'); $this->assertSame(array(false, 'prependmevalue', false, 'prependmevalue', 'prependme'), $metadata); // should still be the same $metadata = $this->table->getRowsMetadata('test'); $this->assertSame(array('1', '2', '3', '1', '4'), $metadata); }
public function test_filter_shouldRemoveAllMetadataEntriesHavingTheGivenName() { $prepend = 'city=test;'; $this->table->filter($this->filter, array($prepend)); $metadata = $this->table->getRowsMetadata('segment'); $this->assertSame(array(false, $prepend . 'country=NZ', false, $prepend . 'country=AU', $prepend), $metadata); // should be still the same $metadata = $this->table->getRowsMetadata('test'); $this->assertSame(array('1', '2', '3', '1', '4'), $metadata); }
public function test_filter_shoulAppendGivenStringToAllColumnsOfAllRows_EvenIfTheyHaveDifferentColumns() { $this->addRow(array('nb_visits' => 49)); $nameToAppend = '_new_visit'; $this->table->filter($this->filter, array($nameToAppend)); $expectedRow1 = array('nb_visits' . $nameToAppend => 1, 'nb_conversions' . $nameToAppend => 5, 'revenue' . $nameToAppend => 10, 'conversion_rate' . $nameToAppend => 20); $expectedRow2 = array('nb_visits' . $nameToAppend => 49); $this->assertColumnsOfRowIdEquals($expectedRow1, $rowId = 0); $this->assertColumnsOfRowIdEquals($expectedRow2, $rowId = 1); }
public function test_filter_shouldNotGenerateASegmentValueIfReturnValueIsFalse() { $this->table->filter($this->filter, array(function ($label) { if ($label === false) { return 'was false'; } return false; })); $segmentValues = $this->table->getRowsMetadata('segmentValue'); $expected = array(false, false, false, false, 'was false', false, 'was false', false); $this->assertSame($expected, $segmentValues); }
public function test_filter_shouldRemoveTheMetadataFromSubtables_IfOneIsSet() { $row = $this->addRowWithMetadata(array('test' => '5', 'other' => 'value2')); $table = new DataTable(); $table->addRow($this->buildRowWithMetadata(array('other' => 'value3'))); $table->addRow($this->buildRowWithMetadata(array('test' => '6'))); $table->addRow($this->buildRowWithMetadata(array('test' => '7', 'other' => 'value4'))); $row->setSubtable($table); $this->table->filter($this->filter, array('other')); $this->assertFalse($row->getMetadata('other')); $metadata = $table->getRowsMetadata('other'); $this->assertSame(array(false, false, false), $metadata); }
private function filterTable($withUser = 5) { $dataTable = new DataTable(); $dataTable->addRowsFromArray(array(array(Row::COLUMNS => array('label' => 'val1', Metrics::INDEX_NB_USERS => 0)), array(Row::COLUMNS => array('label' => 'val2')), array(Row::COLUMNS => array('label' => 'val2 5w ö?', Metrics::INDEX_NB_USERS => $withUser)))); $dataTable->filter($this->filter, array($idSite = 1, $period = 'day', $date = 'today')); return $dataTable->getColumn(Metrics::INDEX_NB_USERS); }
public function test_filter_IfMultipleSegmentsAreGiven_ShouldIgnoreASummaryRow() { $summaryRow = $this->buildRow(array('label' => 'part1 part2')); $this->table->addSummaryRow($summaryRow); $this->table->filter($this->filter, array(array('seg1', 'seg2'), $delimiter = ' ')); $this->assertFalse($summaryRow->getMetadata('segment')); }
/** * Template method called from self::manipulate. * Flatten each data table. * * @param DataTable $dataTable * @return DataTable */ protected function manipulateDataTable($dataTable) { $newDataTable = $dataTable->getEmptyClone($keepFilters = true); // this recursive filter will be applied to subtables $dataTable->filter('ReplaceSummaryRowLabel'); $this->flattenDataTableInto($dataTable, $newDataTable); return $newDataTable; }
/** * See {@link ExcludeLowPopulation}. * * @param DataTable $table */ public function filter($table) { $minimumValue = $this->minimumValue; $isValueLowPopulation = function ($value) use($minimumValue) { return $value < $minimumValue; }; $table->filter('ColumnCallbackDeleteRow', array($this->columnToFilter, $isValueLowPopulation)); }
public function test_filter() { $dataTable = new DataTable(); $dataTable->addRowsFromArray(array(array(Row::COLUMNS => array('label' => 'val1', 'nb_visits' => 120)), array(Row::COLUMNS => array('nb_visits' => 90)), array(Row::COLUMNS => array('label' => 'val2 5w ö?', 'nb_visits' => 99)), array(Row::COLUMNS => array('label' => Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED, 'nb_visits' => 99)))); $dataTable->filter($this->filter, array($idDimension = 5)); $metadata = $dataTable->getRowsMetadata('segment'); $expected = array('dimension5==val1', false, 'dimension5==val2+5w+%C3%B6%3F', 'dimension5=='); $this->assertSame($expected, $metadata); }
/** * @param DataTable $dataTable */ private function filterDataTable($dataTable) { $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS)); $dataTable->queueFilter('ReplaceColumnNames'); $dataTable->queueFilter('ReplaceSummaryRowLabel'); $dataTable->filter(function (DataTable $table) { $row = $table->getRowFromLabel(Archiver::CONTENT_PIECE_NOT_SET); if ($row) { $row->setColumn('label', Piwik::translate('General_NotDefined', Piwik::translate('Contents_ContentPiece'))); } foreach ($table->getRows() as $row) { if ($row->getMetadata('contentTarget') === Archiver::CONTENT_TARGET_NOT_SET) { $row->setMetadata('contentTarget', ''); } } }); // Content interaction rate = interactions / impressions $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('interaction_rate', 'nb_interactions', 'nb_impressions', $precision = 2)); }
/** * See {@link PrependValueToMetadata}. * * @param DataTable $table */ public function filter($table) { if (empty($this->metadataColumn) || empty($this->valueToPrepend)) { return; } $metadataColumn = $this->metadataColumn; $valueToPrepend = $this->valueToPrepend; $table->filter(function (DataTable $dataTable) use($metadataColumn, $valueToPrepend) { foreach ($dataTable->getRows() as $row) { $filter = $row->getMetadata($metadataColumn); if ($filter !== false) { $row->setMetadata($metadataColumn, $valueToPrepend . $filter); } } }); }
/** * @param DataTable $dataTable */ private function filterDataTable($dataTable) { $dataTable->queueFilter('ReplaceColumnNames'); $dataTable->queueFilter('ReplaceSummaryRowLabel'); $dataTable->filter(function (DataTable $table) { $row = $table->getRowFromLabel(Archiver::CONTENT_PIECE_NOT_SET); if ($row) { $row->setColumn('label', Piwik::translate('General_NotDefined', Piwik::translate('Contents_ContentPiece'))); } foreach ($table->getRows() as $row) { if ($row->getMetadata('contentTarget') === Archiver::CONTENT_TARGET_NOT_SET) { $row->setMetadata('contentTarget', ''); } } }); }
/** * @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); } } }
/** * @param DataTable $dataTable */ protected function filterDataTable($dataTable) { $dataTable->filter('Sort', array(Metrics::INDEX_NB_VISITS)); $dataTable->queueFilter('ReplaceColumnNames'); $dataTable->queueFilter('ReplaceSummaryRowLabel'); $dataTable->filter(function (DataTable $table) { $row = $table->getRowFromLabel(Archiver::EVENT_NAME_NOT_SET); if ($row) { $row->setColumn('label', Piwik::translate('General_NotDefined', Piwik::translate('Events_EventName'))); } }); // add processed metric avg_event_value $dataTable->queueFilter('ColumnCallbackAddColumnQuotient', array('avg_event_value', 'sum_event_value', 'nb_events_with_value', $precision = 2, $shouldSkipRows = true)); }
/** * Returns datatable describing the number of visits for each day of the week. * * @param string $idSite The site ID. Cannot refer to multiple sites. * @param string $period The period type: day, week, year, range... * @param string $date The start date of the period. Cannot refer to multiple dates. * @param bool|string $segment The segment. * @throws Exception * @return DataTable */ public function getByDayOfWeek($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess($idSite); // metrics to query $metrics = Metrics::getVisitsMetricNames(); unset($metrics[Metrics::INDEX_MAX_ACTIONS]); // disabled for multiple dates if (Period::isMultiplePeriod($date, $period)) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple dates."); } // get metric data for every day within the supplied period $oPeriod = Period\Factory::makePeriodFromQueryParams(Site::getTimezoneFor($idSite), $period, $date); $dateRange = $oPeriod->getDateStart()->toString() . ',' . $oPeriod->getDateEnd()->toString(); $archive = Archive::build($idSite, 'day', $dateRange, $segment); // disabled for multiple sites if (count($archive->getParams()->getIdSites()) > 1) { throw new Exception("VisitTime.getByDayOfWeek does not support multiple sites."); } $dataTable = $archive->getDataTableFromNumeric($metrics)->mergeChildren(); // if there's no data for this report, don't bother w/ anything else if ($dataTable->getRowsCount() == 0) { return $dataTable; } // group by the day of the week (see below for dayOfWeekFromDate function) $dataTable->filter('GroupBy', array('label', __NAMESPACE__ . '\\dayOfWeekFromDate')); // create new datatable w/ empty rows, then add calculated datatable $rows = array(); foreach (array(1, 2, 3, 4, 5, 6, 7) as $day) { $rows[] = array('label' => $day, 'nb_visits' => 0); } $result = new DataTable(); $result->addRowsFromSimpleArray($rows); $result->addDataTable($dataTable); // set day of week integer as metadata $result->filter('ColumnCallbackAddMetadata', array('label', 'day_of_week')); // translate labels $result->filter('ColumnCallbackReplace', array('label', __NAMESPACE__ . '\\translateDayOfWeek')); // set datatable metadata for period start & finish $result->setMetadata('date_start', $oPeriod->getDateStart()); $result->setMetadata('date_end', $oPeriod->getDateEnd()); return $result; }
/** * Utility function. Gets row count of a set of tables grouped by the 'name' column. * This is the implementation of the getRowCountsAndSizeBy... functions. */ private function getRowCountsByArchiveName($statuses, $getRowSizeMethod, $forceCache = false, $otherSelects = array(), $otherDataTableColumns = array()) { $extraCols = ''; if (!empty($otherSelects)) { $extraCols = ', ' . implode(', ', $otherSelects); } $cols = array_merge(array('row_count'), $otherDataTableColumns); $dataTable = new DataTable(); foreach ($statuses as $status) { $dataTableOptionName = $this->getCachedOptionName($status['Name'], 'byArchiveName'); // if option exists && !$forceCache, use the cached data, otherwise create the $cachedData = Option::get($dataTableOptionName); if ($cachedData !== false && !$forceCache) { $table = DataTable::fromSerializedArray($cachedData); } else { $table = new DataTable(); $table->addRowsFromSimpleArray($this->dataAccess->getRowCountsByArchiveName($status['Name'], $extraCols)); $reduceArchiveRowName = array($this, 'reduceArchiveRowName'); $table->filter('GroupBy', array('label', $reduceArchiveRowName)); $serializedTables = $table->getSerialized(); $serializedTable = reset($serializedTables); Option::set($dataTableOptionName, $serializedTable); } // add estimated_size column $getEstimatedSize = array($this, $getRowSizeMethod); $table->filter('ColumnCallbackAddColumn', array($cols, 'estimated_size', $getEstimatedSize, array($status))); $dataTable->addDataTable($table); } return $dataTable; }
/** * Removes DataTable rows referencing actions that were never the last action of a visit. * * @param DataTable $dataTable */ private function filterNonExitActions($dataTable) { $dataTable->filter('ColumnCallbackDeleteRow', array('exit_nb_visits', function ($visits) { return !strlen($visits); })); }
/** * Apply generic filters to the DataTable object resulting from the API Call. * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request. * * @param DataTable $datatable * @return bool */ protected function applyGenericFilters($datatable) { if ($datatable instanceof DataTable\Map) { $tables = $datatable->getDataTables(); foreach ($tables as $table) { $this->applyGenericFilters($table); } return; } $genericFilters = self::getGenericFiltersInformation(); $filterApplied = false; foreach ($genericFilters as $filterMeta) { $filterName = $filterMeta[0]; $filterParams = $filterMeta[1]; $filterParameters = array(); $exceptionRaised = false; foreach ($filterParams as $name => $info) { // parameter type to cast to $type = $info[0]; // default value if specified, when the parameter doesn't have a value $defaultValue = null; if (isset($info[1])) { $defaultValue = $info[1]; } // third element in the array, if it exists, overrides the name of the request variable $varName = $name; if (isset($info[2])) { $varName = $info[2]; } try { $value = Common::getRequestVar($name, $defaultValue, $type, $this->request); settype($value, $type); $filterParameters[] = $value; } catch (Exception $e) { $exceptionRaised = true; break; } } if (!$exceptionRaised) { $datatable->filter($filterName, $filterParameters); $filterApplied = true; } } return $filterApplied; }
private function assertSegmentForSegmentValueAndReport($report, $segmentValue, $expectedSegment) { $row = $this->addRowWithMetadata(array('segmentValue' => $segmentValue)); $this->table->filter($this->filter, array($report)); $this->assertSegment($expectedSegment, $row); }
/** * @param DataTable|DataTable\Map $dataTable * @param $visualization */ protected function initChartObjectData($dataTable, $visualization) { // We apply a filter to the DataTable, decoding the label column (useful for keywords for example) $dataTable->filter('ColumnCallbackReplace', array('label', 'urldecode')); $xLabels = $dataTable->getColumn('label'); $columnNames = $this->properties['columns_to_display']; if (($labelColumnIndex = array_search('label', $columnNames)) !== false) { unset($columnNames[$labelColumnIndex]); } $columnNameToTranslation = $columnNameToValue = array(); foreach ($columnNames as $columnName) { $columnNameToTranslation[$columnName] = @$this->properties['translations'][$columnName]; $columnNameToValue[$columnName] = $dataTable->getColumn($columnName); } $visualization->dataTable = $dataTable; $visualization->properties = $this->properties; $visualization->setAxisXLabels($xLabels); $visualization->setAxisYValues($columnNameToValue); $visualization->setAxisYLabels($columnNameToTranslation); $units = $this->getUnitsForColumnsToDisplay(); $visualization->setAxisYUnits($units); }
/** * @param DataTable $table */ private function addSummaryRow($table) { if ($table->getRowsCount() <= $this->truncateAfter + 1) { return; } $table->filter('Sort', array($this->columnToSortByBeforeTruncating, 'desc', $naturalSort = true, $recursiveSort = false)); $rows = array_values($table->getRows()); $count = $table->getRowsCount(); $newRow = new Row(array(Row::COLUMNS => array('label' => DataTable::LABEL_SUMMARY_ROW))); $aggregationOps = $table->getMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME); for ($i = $this->truncateAfter; $i < $count; $i++) { if (!isset($rows[$i])) { // case when the last row is a summary row, it is not indexed by $cout but by DataTable::ID_SUMMARY_ROW $summaryRow = $table->getRowFromId(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, $aggregationOps); } } else { $newRow->sumRow($rows[$i], $enableCopyMetadata = false, $aggregationOps); } } $table->filter('Limit', array(0, $this->truncateAfter)); $table->addSummaryRow($newRow); unset($rows); }
/** * Removes DataTable rows referencing actions that were never the last action of a visit. * * @param DataTable $dataTable */ private function filterNonExitActions($dataTable) { $dataTable->filter('ColumnCallbackDeleteRow', array(PiwikMetrics::INDEX_PAGE_EXIT_NB_VISITS, function ($visits) { return !strlen($visits); })); }
/** * @param array $reportMetadata * @param string $period * @param string $date * @param string $lastDate * @param string $metric * @param DataTable $currentReport * @param DataTable $lastReport * @param int $totalValue * @param int $minMoversPercent Exclude rows who moved and the difference is not at least min percent * visits of totalVisits. -1 excludes movers. * @param int $minNewPercent Exclude rows who are new and the difference is not at least min percent * visits of totalVisits. -1 excludes all new. * @param int $minDisappearedPercent Exclude rows who are disappeared and the difference is not at least min * percent visits of totalVisits. -1 excludes all disappeared. * @param int $minGrowthPercentPositive The actual growth of a row must be at least percent compared to the * previous value (not total value) * @param int $minGrowthPercentNegative The actual growth of a row must be lower percent compared to the * previous value (not total value) * @param string $orderBy Order by absolute, relative, importance * @param int $limitIncreaser * @param int $limitDecreaser * * @return DataTable */ public function generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser) { $minChangeMovers = $this->getMinVisits($totalValue, $minMoversPercent); $minIncreaseNew = $this->getMinVisits($totalValue, $minNewPercent); $minDecreaseDisappeared = $this->getMinVisits($totalValue, $minDisappearedPercent); $dataTable = new DataTable(); $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\Insight', array($currentReport, $lastReport, $metric, $considerMovers = -1 !== $minMoversPercent, $considerNew = -1 !== $minNewPercent, $considerDisappeared = -1 !== $minDisappearedPercent)); $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\MinGrowth', array('growth_percent_numeric', $minGrowthPercentPositive, $minGrowthPercentNegative)); if ($minIncreaseNew) { $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\ExcludeLowValue', array('difference', $minIncreaseNew, 'isNew')); } if ($minChangeMovers) { $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\ExcludeLowValue', array('difference', $minChangeMovers, 'isMover')); } if ($minDecreaseDisappeared) { $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\ExcludeLowValue', array('difference', $minDecreaseDisappeared, 'isDisappeared')); } $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\OrderBy', array($this->getOrderByColumn($orderBy), $orderBy === self::ORDER_BY_RELATIVE ? $this->getOrderByColumn(self::ORDER_BY_ABSOLUTE) : $this->getOrderByColumn(self::ORDER_BY_RELATIVE), $metric)); $dataTable->filter('Piwik\\Plugins\\Insights\\DataTable\\Filter\\Limit', array('growth_percent_numeric', $limitIncreaser, $limitDecreaser)); $metricName = $metric; if (!empty($reportMetadata['metrics'][$metric])) { $metricName = $reportMetadata['metrics'][$metric]; } $dataTable->setMetadataValues(array('reportName' => $reportMetadata['name'], 'metricName' => $metricName, 'date' => $date, 'lastDate' => $lastDate, 'period' => $period, 'report' => $reportMetadata, 'totalValue' => $totalValue, 'orderBy' => $orderBy, 'metric' => $metric, 'minChangeMovers' => $minChangeMovers, 'minIncreaseNew' => $minIncreaseNew, 'minDecreaseDisappeared' => $minDecreaseDisappeared, 'minGrowthPercentPositive' => $minGrowthPercentPositive, 'minGrowthPercentNegative' => $minGrowthPercentNegative, 'minMoversPercent' => $minMoversPercent, 'minNewPercent' => $minNewPercent, 'minDisappearedPercent' => $minDisappearedPercent)); return $dataTable; }
/** * Apply generic filters to the DataTable object resulting from the API Call. * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request. * * @param DataTable $datatable * @return bool */ protected function applyGenericFilters($datatable) { if ($datatable instanceof DataTable\Map) { $tables = $datatable->getDataTables(); foreach ($tables as $table) { $this->applyGenericFilters($table); } return; } $genericFilters = $this->getGenericFiltersHavingDefaultValues(); $filterApplied = false; foreach ($genericFilters as $filterMeta) { $filterName = $filterMeta[0]; $filterParams = $filterMeta[1]; $filterParameters = array(); $exceptionRaised = false; if (in_array($filterName, $this->disabledFilters)) { continue; } foreach ($filterParams as $name => $info) { if (!is_array($info)) { // hard coded value that cannot be changed via API, see eg $naturalSort = true in 'Sort' $filterParameters[] = $info; } else { // parameter type to cast to $type = $info[0]; // default value if specified, when the parameter doesn't have a value $defaultValue = null; if (isset($info[1])) { $defaultValue = $info[1]; } try { $value = Common::getRequestVar($name, $defaultValue, $type, $this->request); settype($value, $type); $filterParameters[] = $value; } catch (Exception $e) { $exceptionRaised = true; break; } } } if (!$exceptionRaised) { $datatable->filter($filterName, $filterParameters); $filterApplied = true; } } return $filterApplied; }
protected function aggregateByScreenType(DataTable $resolutions) { $resolutions->filter('GroupBy', array('label', __NAMESPACE__ . '\\getScreenTypeFromResolution')); $this->insertTable(self::SCREEN_TYPE_RECORD_NAME, $resolutions); }