API CHANGE: Added Hierarchy::numHistoricalChildren() and Versioned::get_including_deleted_query()

API CHANGE: Added numChildrenMethod arg to getChildrenAsUL, markPartialTree, markChildren, markingFinished
BUGFIX: Clear the bypassStaticCache cookie when you return to the live site. (from r91165) (from r96739)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102365 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2010-04-12 02:33:46 +00:00
parent 6f8f7ba90a
commit 848b7805e2
4 changed files with 52 additions and 15 deletions

View File

@ -37,9 +37,9 @@ class Hierarchy extends DataObjectDecorator {
* @param int $minNodeCount
* @return string
*/
public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child->Title', $extraArg = null, $limitToMarked = false, $childrenMethod = "AllChildrenIncludingDeleted", $rootCall = true, $minNodeCount = 30) {
public function getChildrenAsUL($attributes = "", $titleEval = '"<li>" . $child->Title', $extraArg = null, $limitToMarked = false, $childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren", $rootCall = true, $minNodeCount = 30) {
if($limitToMarked && $rootCall) {
$this->markingFinished();
$this->markingFinished($numChildrenMethod);
}
if($this->owner->hasMethod($childrenMethod)) {
@ -60,7 +60,7 @@ class Hierarchy extends DataObjectDecorator {
if(!$limitToMarked || $child->isMarked()) {
$foundAChild = true;
$output .= eval("return $titleEval;") . "\n" .
$child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked, $childrenMethod, false, $minNodeCount) . "</li>\n";
$child->getChildrenAsUL("", $titleEval, $extraArg, $limitToMarked, $childrenMethod, $numChildrenMethod, false, $minNodeCount) . "</li>\n";
}
}
@ -83,7 +83,7 @@ class Hierarchy extends DataObjectDecorator {
* @param int $minNodeCount The minimum amount of nodes to mark.
* @return int The actual number of nodes marked.
*/
public function markPartialTree($minNodeCount = 30, $context = null, $childrenMethod = "AllChildrenIncludingDeleted") {
public function markPartialTree($minNodeCount = 30, $context = null, $childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren") {
if(!is_numeric($minNodeCount)) $minNodeCount = 30;
$this->markedNodes = array($this->owner->ID => $this->owner);
@ -91,7 +91,7 @@ class Hierarchy extends DataObjectDecorator {
// foreach can't handle an ever-growing $nodes list
while(list($id, $node) = each($this->markedNodes)) {
$this->markChildren($node, $context, $childrenMethod);
$this->markChildren($node, $context, $childrenMethod, $numChildrenMethod);
if($minNodeCount && sizeof($this->markedNodes) >= $minNodeCount) {
break;
}
@ -154,7 +154,7 @@ class Hierarchy extends DataObjectDecorator {
* Mark all children of the given node that match the marking filter.
* @param DataObject $node Parent node.
*/
public function markChildren($node, $context = null, $childrenMethod = "AllChildrenIncludingDeleted") {
public function markChildren($node, $context = null, $childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren") {
if($node->hasMethod($childrenMethod)) {
$children = $node->$childrenMethod($context);
} else {
@ -166,7 +166,7 @@ class Hierarchy extends DataObjectDecorator {
if($children) {
foreach($children as $child) {
if(!$this->markingFilter || $this->markingFilterMatches($child)) {
if($child->numChildren()) {
if($child->$numChildrenMethod()) {
$child->markUnexpanded();
} else {
$child->markExpanded();
@ -181,11 +181,11 @@ class Hierarchy extends DataObjectDecorator {
* Ensure marked nodes that have children are also marked expanded.
* Call this after marking but before iterating over the tree.
*/
protected function markingFinished() {
protected function markingFinished($numChildrenMethod = "numChildren") {
// Mark childless nodes as expanded.
if($this->markedNodes) {
foreach($this->markedNodes as $id => $node) {
if(!$node->isExpanded() && !$node->numChildren()) {
if(!$node->isExpanded() && !$node->$numChildrenMethod()) {
$node->markExpanded();
}
}
@ -482,6 +482,16 @@ class Hierarchy extends DataObjectDecorator {
"\"ParentID\" = " . (int)$this->owner->ID, "\"$baseClass\".\"ID\" ASC");
}
/**
* Return the number of children that this page ever had, including pages that were deleted
*/
public function numHistoricalChildren() {
$query = Versioned::get_including_deleted_query(ClassInfo::baseDataClass($this->owner->class),
"ParentID = " . (int)$this->owner->ID);
return $query->unlimitedRowCount();
}
/**
* Return the number of direct children.
* By default, values are cached after the first invocation.

View File

@ -1375,7 +1375,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// Also write all VPs pointing here
$suffix = Versioned::current_stage() == 'Live' ? '_Live' : '';
foreach(DataObject::get('VirtualPage', "SiteTree$suffix.ID = SiteTree$suffix.ID AND CopyContentFromID = {$this->ID}") as $page) {
$virtualPages = DataObject::get('VirtualPage', "SiteTree$suffix.ID = SiteTree$suffix.ID AND CopyContentFromID = {$this->ID}");
if($virtualPages) foreach($virtualPages as $page) {
// $page->write() calls syncLinkTracking, which does all the hard work for us.
$page->write();
}

View File

@ -579,7 +579,6 @@ class Versioned extends DataObjectDecorator {
$_GET['stage'] = ucfirst(strtolower($_GET['stage']));
Session::set('currentStage', $_GET['stage']);
Session::clear('archiveDate');
Cookie::set('bypassStaticCache', '1', 0);
}
if(isset($_GET['archiveDate'])) {
Session::set('archiveDate', $_GET['archiveDate']);
@ -592,6 +591,12 @@ class Versioned extends DataObjectDecorator {
} else {
Versioned::reading_stage("Live");
}
if(Versioned::current_stage() == 'Live') {
Cookie::set('bypassStaticCache', null, 0);
} else {
Cookie::set('bypassStaticCache', '1', 0);
}
}
/**
@ -815,6 +820,20 @@ class Versioned extends DataObjectDecorator {
* In particular, this will query deleted records as well as active ones.
*/
static function get_including_deleted($class, $filter = "", $sort = "") {
$query = self::get_including_deleted_query($class, $filter, $sort);
// Process into a DataObjectSet
$SNG = singleton($class);
return $SNG->buildDataObjectSet($query->execute(), 'DataObjectSet', null, $class);
}
/**
* Return the query for the equivalent of a DataObject::get() call, querying the latest
* version of each page stored in the (class)_versions tables.
*
* In particular, this will query deleted records as well as active ones.
*/
static function get_including_deleted_query($class, $filter = "", $sort = "") {
$oldStage = Versioned::$reading_stage;
Versioned::$reading_stage = null;
@ -827,12 +846,9 @@ class Versioned extends DataObjectDecorator {
$query->from[$archiveTable] = "INNER JOIN \"$archiveTable\"
ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\"
AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
// Process into a DataObjectSet
$result = $SNG->buildDataObjectSet($query->execute(), 'DataObjectSet', null, $class);
Versioned::$reading_stage = $oldStage;
return $result;
return $query;
}
/**

View File

@ -16,10 +16,17 @@ class HierarchyTest extends SapphireTest {
$this->assertEquals(array("Page 1", "Page 2", "Page 3"),
singleton('Page')->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(3, singleton('Page')->numHistoricalChildren());
// Check that both page 2 children are returned
$page2 = $this->objFromFixture('Page', 'page2');
$this->assertEquals(array("Page 2a", "Page 2b"),
$page2->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(2, $page2->numHistoricalChildren());
// Page 3 has been deleted; let's bring it back from the grave
$page3 = Versioned::get_including_deleted("SiteTree", "\"Title\" = 'Page 3'")->First();
@ -27,6 +34,9 @@ class HierarchyTest extends SapphireTest {
// Check that both page 3 children are returned
$this->assertEquals(array("Page 3a", "Page 3b"),
$page3->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(2, $page3->numHistoricalChildren());
}