diff options
author | Thomas Steur <thomas.steur@gmail.com> | 2015-02-26 05:23:28 +0300 |
---|---|---|
committer | Thomas Steur <thomas.steur@gmail.com> | 2015-03-05 05:31:18 +0300 |
commit | 287aad82841f0f0e85406192b2f1f865bc0be67d (patch) | |
tree | d9c035a484c3f2727d7fa1cdf14ccd213c308508 /core/DataTable | |
parent | a1cb3695319b321f92bb0a4fd31892a9bc1bdf38 (diff) |
Faster flattening for many reports
Diffstat (limited to 'core/DataTable')
-rw-r--r-- | core/DataTable/Filter/Sort.php | 101 | ||||
-rw-r--r-- | core/DataTable/Filter/Truncate.php | 2 | ||||
-rw-r--r-- | core/DataTable/Map.php | 33 | ||||
-rw-r--r-- | core/DataTable/Row.php | 44 |
4 files changed, 102 insertions, 78 deletions
diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php index 42441c8e30..632da35dc8 100644 --- a/core/DataTable/Filter/Sort.php +++ b/core/DataTable/Filter/Sort.php @@ -21,7 +21,8 @@ use Piwik\Metrics; * * @api */ -class Sort extends BaseFilter +class +Sort extends BaseFilter { protected $columnToSort; protected $order; @@ -71,34 +72,21 @@ class Sort extends BaseFilter * @param Row $b * @return int */ - public function numberSort($a, $b) + public function numberSort($rowA, $rowB) { - $valA = $this->getColumnValue($a); - $valB = $this->getColumnValue($b); + if (isset($rowA[0]) && isset($rowB[0])) { + if ($rowA[0] != $rowB[0] || !isset($rowA[1])) { + return $this->sign * ($rowA[0] < $rowB[0] ? -1 : 1); + } else { + return -1 * $this->sign * strnatcasecmp($rowA[1], $rowB[1]); + } + } elseif (!isset($rowB[0])) { + return -1; + } elseif (!isset($rowA[0])) { + return 1; + } - return !isset($valA) - && !isset($valB) - ? 0 - : ( - !isset($valA) - ? 1 - : ( - !isset($valB) - ? -1 - : (($valA != $valB - || !isset($a->c[Row::COLUMNS]['label'])) - ? ($this->sign * ( - $valA - < $valB - ? -1 - : 1) - ) - : -1 * $this->sign * strnatcasecmp( - $a->c[Row::COLUMNS]['label'], - $b->c[Row::COLUMNS]['label']) - ) - ) - ); + return 0; } /** @@ -108,10 +96,10 @@ class Sort extends BaseFilter * @param mixed $b * @return int */ - function naturalSort($a, $b) + function naturalSort($rowA, $rowB) { - $valA = $this->getColumnValue($a); - $valB = $this->getColumnValue($b); + $valA = $rowA[0]; + $valB = $rowB[0]; return !isset($valA) && !isset($valB) @@ -135,10 +123,10 @@ class Sort extends BaseFilter * @param mixed $b * @return int */ - function sortString($a, $b) + function sortString($rowA, $rowB) { - $valA = $this->getColumnValue($a); - $valB = $this->getColumnValue($b); + $valA = $rowA[0]; + $valB = $rowB[0]; return !isset($valA) && !isset($valB) @@ -243,6 +231,51 @@ class Sort extends BaseFilter } } - $table->sort(array($this, $methodToUse), $this->columnToSort); + $this->sort($table, $methodToUse); } + + /** + * 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(); + foreach ($rows as $key => $row) { + $values[$key] = array($this->getColumnValue($row), $row->getColumn('label')); + } + + uasort($values, array($this, $functionCallback)); + + $sortedRows = array(); + foreach ($values as $key => $value) { + $sortedRows[$key] = $rows[$key]; + } + + $table->setRows(array_values($sortedRows)); + + unset($rows); + unset($sortedRows); + + if ($table->isSortRecursiveEnabled()) { + foreach ($table->getRows() as $row) { + + $subTable = $row->getSubtable(); + if ($subTable) { + $subTable->enableRecursiveSort(); + $this->sort($subTable, $functionCallback); + } + } + } + + } + } diff --git a/core/DataTable/Filter/Truncate.php b/core/DataTable/Filter/Truncate.php index 632eb2755e..a8fa0bd08f 100644 --- a/core/DataTable/Filter/Truncate.php +++ b/core/DataTable/Filter/Truncate.php @@ -96,7 +96,7 @@ class Truncate extends BaseFilter return; } - $rows = $table->getRows(); + $rows = array_values($table->getRows()); $count = $table->getRowsCount(); $newRow = new Row(array(Row::COLUMNS => array('label' => DataTable::LABEL_SUMMARY_ROW))); diff --git a/core/DataTable/Map.php b/core/DataTable/Map.php index 8795eac134..8787b06404 100644 --- a/core/DataTable/Map.php +++ b/core/DataTable/Map.php @@ -110,6 +110,19 @@ class Map implements DataTableInterface } /** + * Apply a filter to all subtables contained by this instance. + * + * @param string|Closure $className Name of filter class or a Closure. + * @param array $parameters Parameters to pass to the filter. + */ + public function filterSubtables($className, $parameters = array()) + { + foreach ($this->getDataTables() as $table) { + $table->filterSubtables($className, $parameters); + } + } + + /** * Returns the array of DataTables contained by this class. * * @return DataTable[]|Map[] @@ -185,6 +198,26 @@ class Map implements DataTableInterface } /** + * @ignore + */ + public function disableRecursiveFilters() + { + foreach ($this->getDataTables() as $table) { + $table->disableRecursiveFilters(); + } + } + + /** + * @ignore + */ + public function enableRecursiveFilters() + { + foreach ($this->getDataTables() as $table) { + $table->enableRecursiveFilters(); + } + } + + /** * Renames the given column in each contained {@link DataTable}. * * See {@link DataTable::renameColumn()}. diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php index 5f21f3fdec..71dde68031 100644 --- a/core/DataTable/Row.php +++ b/core/DataTable/Row.php @@ -209,37 +209,9 @@ class Row implements \ArrayAccess, \IteratorAggregate return false; } - if ($this->isColumnValueCallable($this->c[self::COLUMNS][$name])) { - $value = $this->resolveCallableColumn($name); - - if (!isset($value)) { - return false; - } - - return $value; - } - return $this->c[self::COLUMNS][$name]; } - private function isColumnValueCallable($name) - { - if (! is_callable($name)) { - return false; - } - - if (is_object($name) && ($name instanceof \Closure)) { - return true; - } - - return is_array($name) && isset($name[0]) && is_object($name[0]); - } - - private function resolveCallableColumn($columnName) - { - return call_user_func($this->c[self::COLUMNS][$columnName], $this); - } - /** * Returns the array of all metadata, or one requested metadata value. * @@ -287,16 +259,7 @@ class Row implements \ArrayAccess, \IteratorAggregate */ public function getColumns() { - $values = array(); - foreach ($this->c[self::COLUMNS] as $columnName => $val) { - if ($this->isColumnValueCallable($val)) { - $values[$columnName] = $this->resolveCallableColumn($columnName); - } else { - $values[$columnName] = $val; - } - } - - return $values; + return $this->c[self::COLUMNS]; } /** @@ -517,11 +480,6 @@ class Row implements \ArrayAccess, \IteratorAggregate continue; } - if ($this->isColumnValueCallable($columnToSumValue)) { - $this->setColumn($columnToSumName, $columnToSumValue); - continue; - } - $thisColumnValue = $this->getColumn($columnToSumName); $operation = 'sum'; |