/** * Traverses a DataTable tree using an array of labels and returns the row * it finds or `false` if it cannot find one. The number of path segments that * were successfully walked is also returned. * * If `$missingRowColumns` is supplied, the specified path is created. When * a subtable is encountered w/o the required label, a new row is created * with the label, and a new subtable is added to the row. * * Read [http://en.wikipedia.org/wiki/Tree_(data_structure)#Traversal_methods](http://en.wikipedia.org/wiki/Tree_(data_structure)#Traversal_methods) * for more information about tree walking. * * @param array $path The path to walk. An array of label values. The first element * refers to a row in this DataTable, the second in a subtable of * the first row, the third a subtable of the second row, etc. * @param array|bool $missingRowColumns The default columns to use when creating new rows. * If this parameter is supplied, new rows will be * created for path labels that cannot be found. * @param int $maxSubtableRows The maximum number of allowed rows in new subtables. New * subtables are only created if `$missingRowColumns` is provided. * @return array First element is the found row or `false`. Second element is * the number of path segments walked. If a row is found, this * will be == to `count($path)`. Otherwise, it will be the index * of the path segment that we could not find. */ public function walkPath($path, $missingRowColumns = false, $maxSubtableRows = 0) { $pathLength = count($path); $table = $this; $next = false; for ($i = 0; $i < $pathLength; ++$i) { $segment = $path[$i]; $next = $table->getRowFromLabel($segment); if ($next === false) { // if there is no table to advance to, and we're not adding missing rows, return false if ($missingRowColumns === false) { return array(false, $i); } else { // if we're adding missing rows, add a new row $row = new DataTableSummaryRow(); $row->setColumns(array('label' => $segment) + $missingRowColumns); $next = $table->addRow($row); if ($next !== $row) { // if the row wasn't added, the table is full // Summary row, has no metadata $next->deleteMetadata(); return array($next, $i); } } } $table = $next->getSubtable(); if ($table === false) { // if the row has no table (and thus no child rows), and we're not adding // missing rows, return false if ($missingRowColumns === false) { return array(false, $i); } elseif ($i != $pathLength - 1) { // create subtable if missing, but only if not on the last segment $table = new DataTable(); $table->setMaximumAllowedRows($maxSubtableRows); $table->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME] = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME); $next->setSubtable($table); // Summary row, has no metadata $next->deleteMetadata(); } } } return array($next, $i); }
/** * Executes the filter. See {@link AddSummaryRow}. * * @param DataTable $table */ public function filter($table) { $row = new DataTableSummaryRow($table); $row->setColumn('label', $this->labelSummaryRow); $table->addSummaryRow($row); }
private function moveSitesHavingAGroupIntoSubtables(DataTable $sites) { /** @var DataTableSummaryRow[] $groups */ $groups = array(); $sitesByGroup = $this->makeCloneOfDataTableSites($sites); $sitesByGroup->enableRecursiveFilters(); // we need to make sure filters get applied to subtables (groups) foreach ($sites->getRows() as $site) { $group = $site->getMetadata('group'); if (!empty($group) && !array_key_exists($group, $groups)) { $row = new DataTableSummaryRow(); $row->setColumn('label', $group); $row->setMetadata('isGroup', 1); $row->setSubtable($this->createGroupSubtable($sites)); $sitesByGroup->addRow($row); $groups[$group] = $row; } if (!empty($group)) { $groups[$group]->getSubtable()->addRow($site); } else { $sitesByGroup->addRow($site); } } foreach ($groups as $group) { // we need to recalculate as long as all rows are there, as soon as some rows are removed // we can no longer recalculate the correct value. We might even calculate values for groups // that are not returned. If this becomes a problem we need to keep a copy of this to recalculate // only actual returned groups. $group->recalculate(); } return $sitesByGroup; }