BUGFIX: Fixed bugs with copying custom fields into Virtual pages, generally made virtual pages more robust and performant.

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.4@101112 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2010-03-16 02:37:01 +00:00
parent 48d3f48edb
commit 25836a1bea

View File

@ -46,6 +46,31 @@ class VirtualPage extends Page {
return $virtualFields; return $virtualFields;
} }
function CopyContentFrom() {
if(empty($this->record['CopyContentFromID'])) return new SiteTree();
if(!isset($this->components['CopyContentFrom'])) {
$this->components['CopyContentFrom'] = DataObject::get_by_id("SiteTree",
$this->record['CopyContentFromID']);
// Don't let VirtualPages point to other VirtualPages
if($this->components['CopyContentFrom'] instanceof VirtualPage) {
$this->components['CopyContentFrom'] = null;
}
// has_one component semantics incidate than an empty object should be returned
if(!$this->components['CopyContentFrom']) {
$this->components['CopyContentFrom'] = new SiteTree();
}
}
return $this->components['CopyContentFrom'];
}
function setCopyContentFromID($val) {
if(DataObject::get_by_id('SiteTree', $val) instanceof VirtualPage) $val = 0;
return $this->setField("CopyContentFromID", $val);
}
function ContentSource() { function ContentSource() {
return $this->CopyContentFrom(); return $this->CopyContentFrom();
} }
@ -59,6 +84,8 @@ class VirtualPage extends Page {
public function syncLinkTracking() { public function syncLinkTracking() {
if($this->CopyContentFromID) { if($this->CopyContentFromID) {
$this->HasBrokenLink = !(bool) DataObject::get_by_id('SiteTree', $this->CopyContentFromID); $this->HasBrokenLink = !(bool) DataObject::get_by_id('SiteTree', $this->CopyContentFromID);
} else {
$this->HasBrokenLink = true;
} }
} }
@ -110,7 +137,8 @@ class VirtualPage extends Page {
_t('VirtualPage.CHOOSE', "Choose a page to link to"), _t('VirtualPage.CHOOSE', "Choose a page to link to"),
"SiteTree" "SiteTree"
); );
$copyContentFromField->setFilterFunction(create_function('$item', 'return $item->ClassName != "VirtualPage";')); // filter doesn't let you select children of virtual pages as as source page
//$copyContentFromField->setFilterFunction(create_function('$item', 'return !($item instanceof VirtualPage);'));
// Setup virtual fields // Setup virtual fields
if($virtualFields = $this->getVirtualFields()) { if($virtualFields = $this->getVirtualFields()) {
@ -129,7 +157,7 @@ class VirtualPage extends Page {
$fields->addFieldToTab("Root.Content.Main", $copyContentFromField, "Title"); $fields->addFieldToTab("Root.Content.Main", $copyContentFromField, "Title");
// Create links back to the original object in the CMS // Create links back to the original object in the CMS
if($this->CopyContentFromID) { if($this->CopyContentFrom()->ID) {
$linkToContent = "<a class=\"cmsEditlink\" href=\"admin/show/$this->CopyContentFromID\">" . $linkToContent = "<a class=\"cmsEditlink\" href=\"admin/show/$this->CopyContentFromID\">" .
_t('VirtualPage.EDITCONTENT', 'click here to edit the content') . "</a>"; _t('VirtualPage.EDITCONTENT', 'click here to edit the content') . "</a>";
$fields->addFieldToTab("Root.Content.Main", $fields->addFieldToTab("Root.Content.Main",
@ -149,15 +177,17 @@ class VirtualPage extends Page {
// On regular write, this will copy from published source. This happens on every publish // On regular write, this will copy from published source. This happens on every publish
if($this->extension_instances['Versioned']->migratingVersion if($this->extension_instances['Versioned']->migratingVersion
&& Versioned::current_stage() == 'Live') { && Versioned::current_stage() == 'Live') {
$performCopyFrom = true; if($this->CopyContentFromID) {
$performCopyFrom = true;
$stageSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree\" WHERE \"ID\" = $this->CopyContentFromID")->value(); $stageSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree\" WHERE \"ID\" = $this->CopyContentFromID")->value();
$liveSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree_Live\" WHERE \"ID\" = $this->CopyContentFromID")->value(); $liveSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree_Live\" WHERE \"ID\" = $this->CopyContentFromID")->value();
// We're going to create a new VP record in SiteTree_versions because the published // We're going to create a new VP record in SiteTree_versions because the published
// version might not exist, unless we're publishing the latest version // version might not exist, unless we're publishing the latest version
if($stageSourceVersion != $liveSourceVersion) { if($stageSourceVersion != $liveSourceVersion) {
$this->extension_instances['Versioned']->migratingVersion = null; $this->extension_instances['Versioned']->migratingVersion = null;
}
} }
// On regular write, this will copy from draft source. This is only executed when the source // On regular write, this will copy from draft source. This is only executed when the source
@ -173,7 +203,7 @@ class VirtualPage extends Page {
$source = DataObject::get_one("SiteTree",sprintf('"SiteTree"."ID" = %d', $this->CopyContentFromID)); $source = DataObject::get_one("SiteTree",sprintf('"SiteTree"."ID" = %d', $this->CopyContentFromID));
// Leave the updating of image tracking until after write, in case its a new record // Leave the updating of image tracking until after write, in case its a new record
$this->copyFrom($source, false); $this->copyFrom($source, false);
$this->URLSegment = $source->URLSegment . '-' . $this->ID; $this->URLSegment = $source->URLSegment;
} }
parent::onBeforeWrite(); parent::onBeforeWrite();
@ -234,18 +264,13 @@ class VirtualPage extends Page {
* @return mixed * @return mixed
*/ */
function __get($field) { function __get($field) {
$return = parent::__get($field); if(parent::hasMethod($funcName = "get$field")) {
if ($return === null) { return $this->$funcName();
if($this->copyContentFrom()->hasMethod($funcName = "get$field")) { } else if(parent::hasField($field)) {
$return = $this->copyContentFrom()->$funcName(); return $this->getField($field);
} else if($this->copyContentFrom()->hasField($field)) { } else {
$return = $this->copyContentFrom()->getField($field); return $this->copyContentFrom()->$field;
} else if($field == 'Content') {
return '<p>' . _t('VirtualPage.NOTFOUND', 'We could not find the content for this virtual page.') . '</p>';
}
} }
return $return;
} }
/** /**
@ -255,17 +280,22 @@ class VirtualPage extends Page {
* @param string $args * @param string $args
*/ */
function __call($method, $args) { function __call($method, $args) {
try { if(parent::hasMethod($method)) {
return parent::__call($method, $args); return parent::__call($method, $args);
} catch (Exception $e) { } else {
// Hack... detect exception type. We really should use exception subclasses. return call_user_func_array(array($this->copyContentFrom(), $method), $args);
// if the exception isn't a 'no method' error, rethrow it
if ($e->getCode() !== 2175) throw $e;
$original = $this->copyContentFrom();
return call_user_func_array(array($original, $method), $args);
} }
} }
public function hasField($field) {
return (
array_key_exists($field, $this->record)
|| $this->hasDatabaseField($field)
|| array_key_exists($field, $this->db()) // Needed for composite fields
|| parent::hasMethod("get{$field}")
|| $this->CopyContentFrom()->hasField($field)
);
}
/** /**
* Overwrite to also check for method on the original data object * Overwrite to also check for method on the original data object
* *
@ -273,9 +303,8 @@ class VirtualPage extends Page {
* @return bool * @return bool
*/ */
function hasMethod($method) { function hasMethod($method) {
$haveIt = parent::hasMethod($method); if(parent::hasMethod($method)) return true;
if (!$haveIt) $haveIt = $this->copyContentFrom()->hasMethod($method); return $this->copyContentFrom()->hasMethod($method);
return $haveIt;
} }
} }