Merge pull request #1083 from mateusz/fix-link-tracking

API Change broken link hihglighting to write to database.
This commit is contained in:
Sean Harvey 2014-08-15 13:10:01 +12:00
commit 23e70009d8
7 changed files with 43 additions and 112 deletions

View File

@ -4,6 +4,3 @@ LeftAndMain:
Security: Security:
extensions: extensions:
- ErrorPageControllerExtension - ErrorPageControllerExtension
HtmlEditorField:
extensions:
- SiteTreeLinkTracking_Highlighter

View File

@ -37,15 +37,39 @@ class SiteTreeLinkTracking extends DataExtension {
"ImageTracking" => array("FieldName" => "Varchar") "ImageTracking" => array("FieldName" => "Varchar")
); );
function trackLinksInField($field) { public function trackLinksInField($fieldName) {
$record = $this->owner; $record = $this->owner;
$linkedPages = array(); $linkedPages = array();
$linkedFiles = array(); $linkedFiles = array();
$htmlValue = Injector::inst()->create('HTMLValue', $record->$field); $htmlValue = Injector::inst()->create('HTMLValue', $record->$fieldName);
$links = $this->parser->process($htmlValue); $links = $this->parser->process($htmlValue);
// Highlight broken links in the content.
foreach ($links as $link) {
$classStr = trim($link['DOMReference']->getAttribute('class'));
if (!$classStr) {
$classes = array();
} else {
$classes = explode(' ', $classStr);
}
// Add or remove the broken class from the link, depending on the link status.
if ($link['Broken']) {
$classes = array_unique(array_merge($classes, array('ss-broken')));
} else {
$classes = array_diff($classes, array('ss-broken'));
}
if (!empty($classes)) {
$link['DOMReference']->setAttribute('class', implode(' ', $classes));
} else {
$link['DOMReference']->removeAttribute('class');
}
}
$record->$fieldName = $htmlValue->getContent();
// Populate link tracking for internal links & links to asset files. // Populate link tracking for internal links & links to asset files.
foreach ($links as $link) { foreach ($links as $link) {
switch ($link['Type']) { switch ($link['Type']) {
@ -88,13 +112,13 @@ class SiteTreeLinkTracking extends DataExtension {
if($record->ID && $record->many_many('LinkTracking') && $tracker = $record->LinkTracking()) { if($record->ID && $record->many_many('LinkTracking') && $tracker = $record->LinkTracking()) {
$tracker->removeByFilter(sprintf( $tracker->removeByFilter(sprintf(
'"FieldName" = \'%s\' AND "%s" = %d', '"FieldName" = \'%s\' AND "%s" = %d',
$field, $fieldName,
$tracker->getForeignKey(), $tracker->getForeignKey(),
$record->ID $record->ID
)); ));
if($linkedPages) foreach($linkedPages as $item) { if($linkedPages) foreach($linkedPages as $item) {
$tracker->add($item, array('FieldName' => $field)); $tracker->add($item, array('FieldName' => $fieldName));
} }
} }
@ -102,18 +126,18 @@ class SiteTreeLinkTracking extends DataExtension {
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) { if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
$tracker->removeByFilter(sprintf( $tracker->removeByFilter(sprintf(
'"FieldName" = \'%s\' AND "%s" = %d', '"FieldName" = \'%s\' AND "%s" = %d',
$field, $fieldName,
$tracker->getForeignKey(), $tracker->getForeignKey(),
$record->ID $record->ID
)); ));
if($linkedFiles) foreach($linkedFiles as $item) { if($linkedFiles) foreach($linkedFiles as $item) {
$tracker->add($item, array('FieldName' => $field)); $tracker->add($item, array('FieldName' => $fieldName));
} }
} }
} }
function augmentSyncLinkTracking() { public function augmentSyncLinkTracking() {
// Reset boolean broken flags // Reset boolean broken flags
$this->owner->HasBrokenLink = false; $this->owner->HasBrokenLink = false;
$this->owner->HasBrokenFile = false; $this->owner->HasBrokenFile = false;
@ -134,51 +158,6 @@ class SiteTreeLinkTracking extends DataExtension {
} }
} }
/**
* Extension for enabling highlighting of broken links in the HtmlEditorFields.
*/
class SiteTreeLinkTracking_Highlighter extends Extension {
public $parser;
private static $dependencies = array(
'parser' => '%$SiteTreeLinkTracking_Parser'
);
/**
* Adds an ability to highlight broken links in the content.
* It reuses the parser the SiteTreeLinkTracking uses for maintaining the references and the "broken" flags
* to make sure all pages listed in the BrokenLinkChecker highlight these in their content.
*/
public function onBeforeRender($field) {
// Handle situation when the field has been customised, i.e. via $properties on the HtmlEditorField::Field call.
$obj = $this->owner->getCustomisedObj() ?: $this->owner;
$value = $obj->value;
// Parse the text as DOM.
$htmlValue = Injector::inst()->create('HTMLValue', $value);
$links = $this->parser->process($htmlValue);
foreach ($links as $link) {
$classStr = $link['DOMReference']->getAttribute('class');
$classes = explode(' ', $classStr);
// Add or remove the broken class from the link, depending on the link status.
if ($link['Broken']) {
$classes = array_unique(array_merge($classes, array('ss-broken')));
} else {
$classes = array_diff($classes, array('ss-broken'));
}
$link['DOMReference']->setAttribute('class', implode(' ', $classes));
}
$obj->customise(array(
'Value' => htmlentities($htmlValue->getContent(), ENT_COMPAT, 'UTF-8')
));
}
}
/** /**
* A helper object for extracting information about links. * A helper object for extracting information about links.
*/ */

View File

@ -292,13 +292,6 @@ class SiteTreeBrokenLinksTest extends SapphireTest {
$this->assertFalse((bool)$vp->HasBrokenLink); $this->assertFalse((bool)$vp->HasBrokenLink);
$this->assertFalse((bool)$rp->HasBrokenLink); $this->assertFalse((bool)$rp->HasBrokenLink);
// However, the page isn't marked as modified on stage
$this->assertFalse($p2->IsModifiedOnStage);
$this->assertFalse($rp->IsModifiedOnStage);
// This is something that we know to be broken
//$this->assertFalse($vp->IsModifiedOnStage);
} }
public function testBrokenAnchorLinksInAPage() { public function testBrokenAnchorLinksInAPage() {

View File

@ -166,37 +166,4 @@ class SiteTreeHtmlEditorFieldTest extends FunctionalTest {
$this->assertFalse((bool) $sitetree->HasBrokenFile); $this->assertFalse((bool) $sitetree->HasBrokenFile);
} }
public function testBrokenLinkHighlighting() {
$sitetree = new SiteTree();
$editor = new HtmlEditorField('Content');
// SiteTree link highlighting
$editor->setValue('<a href="[sitetree_link,id=0]">Broken Link</a>');
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
$this->assertContains('ss-broken', (string) $element['class'], 'A broken SiteTree link is highlighted');
$editor->setValue(sprintf (
'<a href="[sitetree_link,id=%d]">Working Link</a>',
$this->idFromFixture('SiteTree', 'home')
));
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
$this->assertNotContains('ss-broken', (string) $element['class']);
// File link highlighting
$editor->setValue('<a href="[file_link,id=0]">Broken Link</a>');
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
$this->assertContains('ss-broken', (string) $element['class'], 'A broken File link is highlighted');
$editor->setValue(sprintf (
'<a href="[file_link,id=%d]">Working Link</a>',
$this->idFromFixture('File', 'example_file')
));
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
$this->assertNotContains('ss-broken', (string) $element['class']);
}
} }

View File

@ -35,10 +35,10 @@ class SiteTreeLinkTrackingTest extends SapphireTest {
} }
function highlight($content) { function highlight($content) {
$field = new SiteTreeLinkTrackingTest_Field('Test'); $page = new Page();
$field->setValue($content); $page->Content = $content;
$newContent = html_entity_decode($field->Field(), ENT_COMPAT, 'UTF-8'); $page->write();
return $newContent; return $page->Content;
} }
function testHighlighter() { function testHighlighter() {
@ -49,20 +49,15 @@ class SiteTreeLinkTrackingTest extends SapphireTest {
$content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>'); $content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>');
$this->assertEquals(substr_count($content, 'ss-broken'), 1, 'ss-broken class is added to the broken link.'); $this->assertEquals(substr_count($content, 'ss-broken'), 1, 'ss-broken class is added to the broken link.');
$page = new Page(); $otherPage = new Page();
$page->Content = ''; $otherPage->Content = '';
$page->write(); $otherPage->write();
$content = $this->highlight( $content = $this->highlight(
"<a href=\"[sitetree_link,id=$page->ID]\" class=\"existing-class ss-broken ss-broken\">link</a>" "<a href=\"[sitetree_link,id=$otherPage->ID]\" class=\"existing-class ss-broken ss-broken\">link</a>"
); );
$this->assertEquals(substr_count($content, 'ss-broken'), 0, 'All ss-broken classes are removed from good link'); $this->assertEquals(substr_count($content, 'ss-broken'), 0, 'All ss-broken classes are removed from good link');
$this->assertEquals(substr_count($content, 'existing-class'), 1, 'Existing class is not removed.'); $this->assertEquals(substr_count($content, 'existing-class'), 1, 'Existing class is not removed.');
} }
}
class SiteTreeLinkTrackingTest_Field extends HtmlEditorField implements TestOnly {
private static $extensions = array(
'SiteTreeLinkTracking_Highlighter'
);
} }

View File

@ -29,12 +29,12 @@ class MigrateSiteTreeLinkingTaskTest extends SapphireTest {
$hashID = $this->idFromFixture('SiteTree', 'hash_link'); $hashID = $this->idFromFixture('SiteTree', 'hash_link');
$homeContent = sprintf ( $homeContent = sprintf (
'<a href="[sitetree_link,id=%d]">About</a><a href="[sitetree_link,id=%d]">Staff</a><a href="http://silverstripe.org/">External Link</a>', '<a href="[sitetree_link,id=%d]">About</a><a href="[sitetree_link,id=%d]">Staff</a><a href="http://silverstripe.org/">External Link</a><a name="anchor"></a>',
$aboutID, $aboutID,
$staffID $staffID
); );
$aboutContent = sprintf ( $aboutContent = sprintf (
'<a href="[sitetree_link,id=%d]">Home</a><a href="[sitetree_link,id=%d]">Staff</a>', '<a href="[sitetree_link,id=%d]">Home</a><a href="[sitetree_link,id=%d]">Staff</a><a name="second-anchor"></a>',
$homeID, $homeID,
$staffID $staffID
); );

View File

@ -2,11 +2,11 @@ SiteTree:
home: home:
Title: Home Page Title: Home Page
URLSegment: home URLSegment: home
Content: '<a href="about/">About</a><a href="staff">Staff</a><a href="http://silverstripe.org/">External Link</a>' Content: '<a href="about/">About</a><a href="staff">Staff</a><a href="http://silverstripe.org/">External Link</a><a name="anchor"></a>'
about: about:
Title: About Us Title: About Us
URLSegment: about URLSegment: about
Content: '<a href="home">Home</a><a href="staff/">Staff</a>' Content: '<a href="home">Home</a><a href="staff/">Staff</a><a name="second-anchor"></a>'
staff: staff:
Title: Staff Title: Staff
URLSegment: staff URLSegment: staff