#63 - Stable against restructures (from r84861)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@89155 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Sam Minnee 2009-10-15 21:46:13 +00:00
parent 7277ada137
commit 4ab8055c29
4 changed files with 271 additions and 3 deletions

View File

@ -1300,9 +1300,50 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
DataObject::set_context_obj(null); DataObject::set_context_obj(null);
$this->syncLinkTracking();
parent::onBeforeWrite(); parent::onBeforeWrite();
} }
function syncLinkTracking() {
// Set LinkTracking appropriately
$links = HTTP::getLinksIn($this->Content);
$linkedPages = array();
$linkedFiles = array();
$this->HasBrokenLink = false;
$this->HasBrokenFile = false;
if($links) foreach($links as $link) {
if(preg_match('/^([A-Za-z0-9_-]+)\/?(#.*)?$/', $link, $parts)) {
$candidatePage = DataObject::get_one("SiteTree", "\"URLSegment\" = '" . urldecode( $parts[1] ). "'", false);
if($candidatePage) {
$linkedPages[] = $candidatePage->ID;
} else {
$this->HasBrokenLink = true;
}
} else if($link == '' || $link[0] == '/') {
$this->HasBrokenLink = true;
} else if($candidateFile = DataObject::get_one("File", "\"Filename\" = '" . Convert::raw2sql(urldecode($link)) . "'", false)) {
$linkedFiles[] = $candidateFile->ID;
}
}
$images = HTTP::getImagesIn($this->Content);
if($images) {
foreach($images as $image) {
$image = Director::makeRelative($image);
if(substr($image,0,7) == 'assets/') {
$candidateImage = DataObject::get_one("File", "\"Filename\" = '$image'");
if($candidateImage) $linkedFiles[] = $candidateImage->ID;
else $this->HasBrokenFile = true;
}
}
}
$this->LinkTracking()->setByIDList($linkedPages);
$this->ImageTracking()->setByIDList($linkedFiles);
}
function onAfterWrite() { function onAfterWrite() {
// Need to flush cache to avoid outdated versionnumber references // Need to flush cache to avoid outdated versionnumber references
$this->flushCache(); $this->flushCache();
@ -1314,6 +1355,19 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$page->write(); $page->write();
} }
// If the URLSegment has been changed, rewrite links
if($this->isChanged('URLSegment', 2)) {
if($this->hasMethod('BackLinkTracking')) {
$links = $this->BackLinkTracking();
if($links) {
foreach($links as $link) {
$link->rewriteLink($this->original['URLSegment'] . '/', $this->URLSegment . '/');
$link->write();
}
}
}
}
parent::onAfterWrite(); parent::onAfterWrite();
} }
@ -1739,12 +1793,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// Handle activities undertaken by decorators // Handle activities undertaken by decorators
$this->extend('onBeforePublish', $original); $this->extend('onBeforePublish', $original);
$this->Status = "Published"; $this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID; //$this->PublishedByID = Member::currentUser()->ID;
$this->write(); $this->write();
$this->publish("Stage", "Live"); $this->publish("Stage", "Live");
if(DB::getConn() instanceof MySQLDatabase) { if(DB::getConn() instanceof MySQLDatabase) {
// Special syntax for MySQL (grr!) // Special syntax for MySQL (grr!)
// More ANSI-compliant syntax // More ANSI-compliant syntax
@ -1769,6 +1823,31 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$page->doPublish(); $page->doPublish();
} }
// Fix links that are different on staging vs live
$needsWriting = false;
$this->syncLinkTracking();
foreach($this->LinkTracking() as $linkedPage) {
$livePage = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $linkedPage->ID);
if($livePage && $livePage->URLSegment != $linkedPage->URLSegment) {
$needsWriting = true;
$this->rewriteLink($linkedPage->URLSegment . '/', $livePage->URLSegment . '/');
}
}
if($needsWriting) {
$this->writeToStage('Live');
}
// If this url has changed, then we need to fix pages linked to this one
if($original->URLSegment && $original->URLSegment != $this->URLSegment) {
foreach($this->BackLinkTracking() as $linkedPage) {
$linkedPageLive = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $linkedPage->ID);
$linkedPageLive->rewriteLink($original->URLSegment . '/', $this->URLSegment . '/');
$linkedPageLive->writeToStage('Live');
}
}
// Handle activities undertaken by decorators // Handle activities undertaken by decorators
$this->extend('onAfterPublish', $original); $this->extend('onAfterPublish', $original);
} }

View File

@ -141,6 +141,7 @@ class HtmlEditorField extends TextareaField {
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) { if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
$tracker->removeByFilter(sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d', $this->name, $record->ID)); $tracker->removeByFilter(sprintf('"FieldName" = \'%s\' AND "SiteTreeID" = %d', $this->name, $record->ID));
$fieldName = $this->name;
if($linkedFiles) foreach($linkedFiles as $item) { if($linkedFiles) foreach($linkedFiles as $item) {
$tracker->add($item, array('FieldName' => $this->name)); $tracker->add($item, array('FieldName' => $this->name));
} }

View File

@ -0,0 +1,172 @@
<?php
class SiteTreeBacklinksTest extends SapphireTest {
static $fixture_file = "sapphire/tests/SiteTreeBacklinksTest.yml";
function testSavingPageWithLinkAddsBacklink() {
// load page 1
$page1 = $this->objFromFixture('Page', 'page1');
// assert backlink to page 2 doesn't exist
$page2 = $this->objFromFixture('Page', 'page2');
$this->assertFalse($page1->BackLinkTracking()->containsIDs(array($page2->ID)), 'Assert backlink to page 2 doesn\'t exist');
// add hyperlink to page 1 on page 2
$page2->Content .= '<p><a href="page1/">Testing page 1 link</a></p>';
$page2->write();
// load page 1
$page1 = $this->objFromFixture('Page', 'page1');
// assert backlink to page 2 exists
$this->assertTrue($page1->BackLinkTracking()->containsIDs(array($page2->ID)), 'Assert backlink to page 2 exists');
}
function testRemovingLinkFromPageRemovesBacklink() {
// load page 1
$page1 = $this->objFromFixture('Page', 'page1');
// assert backlink to page 3 exits
$page3 = $this->objFromFixture('Page', 'page3');
$this->assertTrue($page1->BackLinkTracking()->containsIDs(array($page3->ID)), 'Assert backlink to page 3 exists');
// remove hyperlink to page 1
$page3->Content = '<p>No links anymore!</p>';
$page3->write();
// load page 1
$page1 = $this->objFromFixture('Page', 'page1');
// assert backlink to page 3 exists
$this->assertFalse($page1->BackLinkTracking()->containsIDs(array($page3->ID)), 'Assert backlink to page 3 doesn\'t exist');
}
function testChangingUrlOnDraftSiteRewritesLink() {
// load page 1
$page1 = $this->objFromFixture('Page', 'page1');
// assert backlink to page 3 exists
$page3 = $this->objFromFixture('Page', 'page3');
$this->assertTrue($page1->BackLinkTracking()->containsIDs(array($page3->ID)), 'Assert backlink to page 3 exists');
// assert hyperlink to page 1's current url exists on page 3
$links = HTTP::getLinksIn($page3->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3');
// change url of page 1
$page1->URLSegment = 'new-url-segment';
$page1->write();
// load page 3
$page3 = $this->objFromFixture('Page', 'page3');
// assert hyperlink to page 1's new url exists
$links = HTTP::getLinksIn($page3->Content);
$this->assertContains('new-url-segment/', $links, 'Assert hyperlink to page 1\'s new url exists on page 3');
}
function testChangingUrlOnLiveSiteRewritesLink() {
// publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1');
$page3 = $this->objFromFixture('Page', 'page3');
$page1->doPublish();
$page3->doPublish();
// load pages from live
$page1live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page1->ID);
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert backlink to page 3 exists
$this->assertTrue($page1live->BackLinkTracking()->containsIDs(array($page3live->ID)), 'Assert backlink to page 3 exists');
// assert hyperlink to page 1's current url exists on page 3
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3');
// change url of page 1
$page1live->URLSegment = 'new-url-segment';
$page1live->writeToStage('Live');
// load page 3 from live
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert hyperlink to page 1's new url exists
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('new-url-segment/', $links, 'Assert hyperlink to page 1\'s new url exists on page 3');
}
function testPublishingPageWithModifiedUrlRewritesLink() {
// publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1');
$page3 = $this->objFromFixture('Page', 'page3');
$page1->doPublish();
$page3->doPublish();
// load page 3 from live
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert hyperlink to page 1's current url exists
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3');
// rename url of page 1 on stage
$page1->URLSegment = 'new-url-segment';
$page1->write();
// assert hyperlink to page 1's current publish url exists
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3');
// publish page 1
$page1->doPublish();
// assert hyperlink to page 1's new published url exists
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('new-url-segment/', $links, 'Assert hyperlink to page 1\'s new published url exists on page 3');
}
function testPublishingPageWithModifiedLinksRewritesLinks() {
// publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1');
$page3 = $this->objFromFixture('Page', 'page3');
$page1->doPublish();
$page3->doPublish();
// assert hyperlink to page 1's current url exists
$links = HTTP::getLinksIn($page3->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3');
// change page 1 url on draft
$page1->URLSegment = 'new-url-segment';
// save page 1
$page1->write();
// assert page 3 on draft contains new page 1 url
$page3 = $this->objFromFixture('Page', 'page3');
$links = HTTP::getLinksIn($page3->Content);
$this->assertContains('new-url-segment/', $links, 'Assert hyperlink to page 1\'s current draft url exists on page 3');
// publish page 3
$page3->doPublish();
// assert page 3 on published site contains old page 1 url
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3');
// publish page 1
$page1->doPublish();
// assert page 3 on published site contains new page 1 url
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->Content);
$this->assertContains('new-url-segment/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3');
}
}
?>

View File

@ -0,0 +1,16 @@
Page:
page1:
Title: page1
URLSegment: page1
page2:
Title: page2
URLSegment: page2
page3:
Title: page3
URLSegment: page3
Content: <p><a href="page1/">Testing page 1 link</a></p>
LinkTracking: =>Page.page1