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 * @param int $minNodeCount
* @return string * @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) { if($limitToMarked && $rootCall) {
$this->markingFinished(); $this->markingFinished($numChildrenMethod);
} }
if($this->owner->hasMethod($childrenMethod)) { if($this->owner->hasMethod($childrenMethod)) {
@ -60,7 +60,7 @@ class Hierarchy extends DataObjectDecorator {
if(!$limitToMarked || $child->isMarked()) { if(!$limitToMarked || $child->isMarked()) {
$foundAChild = true; $foundAChild = true;
$output .= eval("return $titleEval;") . "\n" . $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. * @param int $minNodeCount The minimum amount of nodes to mark.
* @return int The actual number of nodes marked. * @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; if(!is_numeric($minNodeCount)) $minNodeCount = 30;
$this->markedNodes = array($this->owner->ID => $this->owner); $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 // foreach can't handle an ever-growing $nodes list
while(list($id, $node) = each($this->markedNodes)) { while(list($id, $node) = each($this->markedNodes)) {
$this->markChildren($node, $context, $childrenMethod); $this->markChildren($node, $context, $childrenMethod, $numChildrenMethod);
if($minNodeCount && sizeof($this->markedNodes) >= $minNodeCount) { if($minNodeCount && sizeof($this->markedNodes) >= $minNodeCount) {
break; break;
} }
@ -154,7 +154,7 @@ class Hierarchy extends DataObjectDecorator {
* Mark all children of the given node that match the marking filter. * Mark all children of the given node that match the marking filter.
* @param DataObject $node Parent node. * @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)) { if($node->hasMethod($childrenMethod)) {
$children = $node->$childrenMethod($context); $children = $node->$childrenMethod($context);
} else { } else {
@ -166,7 +166,7 @@ class Hierarchy extends DataObjectDecorator {
if($children) { if($children) {
foreach($children as $child) { foreach($children as $child) {
if(!$this->markingFilter || $this->markingFilterMatches($child)) { if(!$this->markingFilter || $this->markingFilterMatches($child)) {
if($child->numChildren()) { if($child->$numChildrenMethod()) {
$child->markUnexpanded(); $child->markUnexpanded();
} else { } else {
$child->markExpanded(); $child->markExpanded();
@ -181,11 +181,11 @@ class Hierarchy extends DataObjectDecorator {
* Ensure marked nodes that have children are also marked expanded. * Ensure marked nodes that have children are also marked expanded.
* Call this after marking but before iterating over the tree. * Call this after marking but before iterating over the tree.
*/ */
protected function markingFinished() { protected function markingFinished($numChildrenMethod = "numChildren") {
// Mark childless nodes as expanded. // Mark childless nodes as expanded.
if($this->markedNodes) { if($this->markedNodes) {
foreach($this->markedNodes as $id => $node) { foreach($this->markedNodes as $id => $node) {
if(!$node->isExpanded() && !$node->numChildren()) { if(!$node->isExpanded() && !$node->$numChildrenMethod()) {
$node->markExpanded(); $node->markExpanded();
} }
} }
@ -482,6 +482,16 @@ class Hierarchy extends DataObjectDecorator {
"\"ParentID\" = " . (int)$this->owner->ID, "\"$baseClass\".\"ID\" ASC"); "\"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. * Return the number of direct children.
* By default, values are cached after the first invocation. * 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 // Also write all VPs pointing here
$suffix = Versioned::current_stage() == 'Live' ? '_Live' : ''; $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() calls syncLinkTracking, which does all the hard work for us.
$page->write(); $page->write();
} }

View File

@ -579,7 +579,6 @@ class Versioned extends DataObjectDecorator {
$_GET['stage'] = ucfirst(strtolower($_GET['stage'])); $_GET['stage'] = ucfirst(strtolower($_GET['stage']));
Session::set('currentStage', $_GET['stage']); Session::set('currentStage', $_GET['stage']);
Session::clear('archiveDate'); Session::clear('archiveDate');
Cookie::set('bypassStaticCache', '1', 0);
} }
if(isset($_GET['archiveDate'])) { if(isset($_GET['archiveDate'])) {
Session::set('archiveDate', $_GET['archiveDate']); Session::set('archiveDate', $_GET['archiveDate']);
@ -592,6 +591,12 @@ class Versioned extends DataObjectDecorator {
} else { } else {
Versioned::reading_stage("Live"); 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. * In particular, this will query deleted records as well as active ones.
*/ */
static function get_including_deleted($class, $filter = "", $sort = "") { 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; $oldStage = Versioned::$reading_stage;
Versioned::$reading_stage = null; Versioned::$reading_stage = null;
@ -827,12 +846,9 @@ class Versioned extends DataObjectDecorator {
$query->from[$archiveTable] = "INNER JOIN \"$archiveTable\" $query->from[$archiveTable] = "INNER JOIN \"$archiveTable\"
ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" ON \"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\"
AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\""; AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
// Process into a DataObjectSet
$result = $SNG->buildDataObjectSet($query->execute(), 'DataObjectSet', null, $class);
Versioned::$reading_stage = $oldStage; 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"), $this->assertEquals(array("Page 1", "Page 2", "Page 3"),
singleton('Page')->AllHistoricalChildren()->column('Title')); singleton('Page')->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(3, singleton('Page')->numHistoricalChildren());
// Check that both page 2 children are returned // Check that both page 2 children are returned
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture('Page', 'page2');
$this->assertEquals(array("Page 2a", "Page 2b"), $this->assertEquals(array("Page 2a", "Page 2b"),
$page2->AllHistoricalChildren()->column('Title')); $page2->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(2, $page2->numHistoricalChildren());
// Page 3 has been deleted; let's bring it back from the grave // Page 3 has been deleted; let's bring it back from the grave
$page3 = Versioned::get_including_deleted("SiteTree", "\"Title\" = 'Page 3'")->First(); $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 // Check that both page 3 children are returned
$this->assertEquals(array("Page 3a", "Page 3b"), $this->assertEquals(array("Page 3a", "Page 3b"),
$page3->AllHistoricalChildren()->column('Title')); $page3->AllHistoricalChildren()->column('Title'));
// Check numHistoricalChildren
$this->assertEquals(2, $page3->numHistoricalChildren());
} }