Run the upgrader & linting tools

An initial (untested) run at a proper upgrade. Progress commit.
This commit is contained in:
Dylan Wagstaff 2017-11-23 12:56:44 +13:00
parent e6ddf0fe47
commit 1ed9a23a71
11 changed files with 750 additions and 657 deletions

View File

@ -2,14 +2,14 @@
namespace SilverStripe\ExternalLinks\Controllers; namespace SilverStripe\ExternalLinks\Controllers;
use Controller; use SilverStripe\Control\HTTP;
use HTTP; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use BrokenExternalPageTrackStatus; use SilverStripe\ExternalLinks\Jobs\CheckExternalLinksJob;
use CheckExternalLinksJob; use SilverStripe\ExternalLinks\Tasks\CheckExternalLinksTask;
use CheckExternalLinksTask; use SilverStripe\Control\Controller;
class CMSExternalLinks_Controller extends Controller
class CMSExternalLinks_Controller extends Controller { {
private static $allowed_actions = array('getJobStatus', 'start'); private static $allowed_actions = array('getJobStatus', 'start');
@ -18,7 +18,8 @@ class CMSExternalLinks_Controller extends Controller {
* *
* @return string JSON string detailing status of the job * @return string JSON string detailing status of the job
*/ */
public function getJobStatus() { public function getJobStatus()
{
// Set headers // Set headers
HTTP::set_cache_age(0); HTTP::set_cache_age(0);
HTTP::add_cache_headers($this->response); HTTP::add_cache_headers($this->response);
@ -29,22 +30,27 @@ class CMSExternalLinks_Controller extends Controller {
// Format status // Format status
$track = BrokenExternalPageTrackStatus::get_latest(); $track = BrokenExternalPageTrackStatus::get_latest();
if($track) return json_encode(array( if ($track) {
return json_encode(array(
'TrackID' => $track->ID, 'TrackID' => $track->ID,
'Status' => $track->Status, 'Status' => $track->Status,
'Completed' => $track->getCompletedPages(), 'Completed' => $track->getCompletedPages(),
'Total' => $track->getTotalPages() 'Total' => $track->getTotalPages()
)); ));
} }
}
/* /*
* Starts a broken external link check * Starts a broken external link check
*/ */
public function start() { public function start()
{
// return if the a job is already running // return if the a job is already running
$status = BrokenExternalPageTrackStatus::get_latest(); $status = BrokenExternalPageTrackStatus::get_latest();
if ($status && $status->Status == 'Running') return; if ($status && $status->Status == 'Running') {
return;
}
// Create a new job // Create a new job
if (class_exists('QueuedJobService')) { if (class_exists('QueuedJobService')) {

View File

@ -4,38 +4,44 @@ namespace SilverStripe\ExternalLinks\Jobs;
use AbstractQueuedJob; use AbstractQueuedJob;
use QueuedJob; use QueuedJob;
use CheckExternalLinksTask;
use SilverStripe\ExternalLinks\Tasks\CheckExternalLinksTask;
if(!class_exists('AbstractQueuedJob')) return; if (!class_exists('AbstractQueuedJob')) {
return;
}
/** /**
* A Job for running a external link check for published pages * A Job for running a external link check for published pages
* *
*/ */
class CheckExternalLinksJob extends AbstractQueuedJob implements QueuedJob { class CheckExternalLinksJob extends AbstractQueuedJob implements QueuedJob
{
public function getTitle() { public function getTitle()
{
return _t('CheckExternalLiksJob.TITLE', 'Checking for external broken links'); return _t('CheckExternalLiksJob.TITLE', 'Checking for external broken links');
} }
public function getJobType() { public function getJobType()
{
return QueuedJob::QUEUED; return QueuedJob::QUEUED;
} }
public function getSignature() { public function getSignature()
{
return md5(get_class($this)); return md5(get_class($this));
} }
/** /**
* Check an individual page * Check an individual page
*/ */
public function process() { public function process()
{
$task = CheckExternalLinksTask::create(); $task = CheckExternalLinksTask::create();
$track = $task->runLinksCheck(1); $track = $task->runLinksCheck(1);
$this->currentStep = $track->CompletedPages; $this->currentStep = $track->CompletedPages;
$this->totalSteps = $track->TotalPages; $this->totalSteps = $track->TotalPages;
$this->isComplete = $track->Status === 'Completed'; $this->isComplete = $track->Status === 'Completed';
} }
} }

View File

@ -2,11 +2,13 @@
namespace SilverStripe\ExternalLinks\Model; namespace SilverStripe\ExternalLinks\Model;
use DataObject; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrack;
use Member; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use Permission; use SilverStripe\Security\Member;
use Config; use SilverStripe\Security\Permission;
use SilverStripe\Core\Config\Config;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ORM\DataObject;
/** /**
* Represents a single link checked for a single run that is broken * Represents a single link checked for a single run that is broken
@ -14,7 +16,8 @@ use Config;
* @method BrokenExternalPageTrack Track() * @method BrokenExternalPageTrack Track()
* @method BrokenExternalPageTrackStatus Status() * @method BrokenExternalPageTrackStatus Status()
*/ */
class BrokenExternalLink extends DataObject { class BrokenExternalLink extends DataObject
{
private static $db = array( private static $db = array(
'Link' => 'Varchar(2083)', // 2083 is the maximum length of a URL in Internet Explorer. 'Link' => 'Varchar(2083)', // 2083 is the maximum length of a URL in Internet Explorer.
@ -22,8 +25,8 @@ class BrokenExternalLink extends DataObject {
); );
private static $has_one = array( private static $has_one = array(
'Track' => 'BrokenExternalPageTrack', 'Track' => BrokenExternalPageTrack::class,
'Status' => 'BrokenExternalPageTrackStatus' 'Status' => BrokenExternalPageTrackStatus::class
); );
private static $summary_fields = array( private static $summary_fields = array(
@ -40,15 +43,18 @@ class BrokenExternalLink extends DataObject {
/** /**
* @return SiteTree * @return SiteTree
*/ */
public function Page() { public function Page()
{
return $this->Track()->Page(); return $this->Track()->Page();
} }
public function canEdit($member = false) { public function canEdit($member = false)
{
return false; return false;
} }
public function canView($member = false) { public function canView($member = false)
{
$member = $member ? $member : Member::currentUser(); $member = $member ? $member : Member::currentUser();
$codes = array('content-authors', 'administrators'); $codes = array('content-authors', 'administrators');
return Permission::checkMember($member, $codes); return Permission::checkMember($member, $codes);
@ -59,13 +65,13 @@ class BrokenExternalLink extends DataObject {
* *
* @return string * @return string
*/ */
public function getHTTPCodeDescription() { public function getHTTPCodeDescription()
{
$code = $this->HTTPCode; $code = $this->HTTPCode;
if(empty($code)) { if (empty($code)) {
// Assume that $code = 0 means there was no response // Assume that $code = 0 means there was no response
$description = _t('BrokenExternalLink.NOTAVAILABLE', 'Server Not Available'); $description = _t('BrokenExternalLink.NOTAVAILABLE', 'Server Not Available');
} elseif( } elseif (($descriptions = Config::inst()->get(HTTPResponse::class, 'status_codes'))
($descriptions = Config::inst()->get('SS_HTTPResponse', 'status_codes'))
&& isset($descriptions[$code]) && isset($descriptions[$code])
) { ) {
$description = $descriptions[$code]; $description = $descriptions[$code];
@ -75,5 +81,3 @@ class BrokenExternalLink extends DataObject {
return sprintf("%d (%s)", $code, $description); return sprintf("%d (%s)", $code, $description);
} }
} }

View File

@ -2,33 +2,37 @@
namespace SilverStripe\ExternalLinks\Model; namespace SilverStripe\ExternalLinks\Model;
use DataObject; use SilverStripe\CMS\Model\SiteTree;
use Versioned; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use SilverStripe\ExternalLinks\Model\BrokenExternalLink;
use SilverStripe\Versioned\Versioned;
use SilverStripe\ORM\DataObject;
/** /**
* Represents a track for a single page * Represents a track for a single page
*/ */
class BrokenExternalPageTrack extends DataObject { class BrokenExternalPageTrack extends DataObject
{
private static $db = array( private static $db = array(
'Processed' => 'Boolean' 'Processed' => 'Boolean'
); );
private static $has_one = array( private static $has_one = array(
'Page' => 'SiteTree', 'Page' => SiteTree::class,
'Status' => 'BrokenExternalPageTrackStatus' 'Status' => BrokenExternalPageTrackStatus::class
); );
private static $has_many = array( private static $has_many = array(
'BrokenLinks' => 'BrokenExternalLink' 'BrokenLinks' => BrokenExternalLink::class
); );
/** /**
* @return SiteTree * @return SiteTree
*/ */
public function Page() { public function Page()
return Versioned::get_by_stage('SiteTree', 'Stage') {
return Versioned::get_by_stage(SiteTree::class, 'Stage')
->byID($this->PageID); ->byID($this->PageID);
} }
} }

View File

@ -2,9 +2,11 @@
namespace SilverStripe\ExternalLinks\Model; namespace SilverStripe\ExternalLinks\Model;
use DataObject; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrack;
use Versioned; use SilverStripe\ExternalLinks\Model\BrokenExternalLink;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Versioned\Versioned;
use SilverStripe\ORM\DataObject;
/** /**
* Represents the status of a track run * Represents the status of a track run
@ -14,7 +16,8 @@ use Versioned;
* @property int $TotalPages Get total pages count * @property int $TotalPages Get total pages count
* @property int $CompletedPages Get completed pages count * @property int $CompletedPages Get completed pages count
*/ */
class BrokenExternalPageTrackStatus extends DataObject { class BrokenExternalPageTrackStatus extends DataObject
{
private static $db = array( private static $db = array(
'Status' => 'Enum("Completed, Running", "Running")', 'Status' => 'Enum("Completed, Running", "Running")',
@ -22,8 +25,8 @@ class BrokenExternalPageTrackStatus extends DataObject {
); );
private static $has_many = array( private static $has_many = array(
'TrackedPages' => 'BrokenExternalPageTrack', 'TrackedPages' => BrokenExternalPageTrack::class,
'BrokenLinks' => 'BrokenExternalLink' 'BrokenLinks' => BrokenExternalLink::class
); );
/** /**
@ -31,7 +34,8 @@ class BrokenExternalPageTrackStatus extends DataObject {
* *
* @return self * @return self
*/ */
public static function get_latest() { public static function get_latest()
{
return self::get() return self::get()
->sort('ID', 'DESC') ->sort('ID', 'DESC')
->first(); ->first();
@ -42,20 +46,24 @@ class BrokenExternalPageTrackStatus extends DataObject {
* *
* @return DataList * @return DataList
*/ */
public function getIncompletePageList() { public function getIncompletePageList()
{
$pageIDs = $this $pageIDs = $this
->getIncompleteTracks() ->getIncompleteTracks()
->column('PageID'); ->column('PageID');
if($pageIDs) return Versioned::get_by_stage('SiteTree', 'Stage') if ($pageIDs) {
return Versioned::get_by_stage(SiteTree::class, 'Stage')
->byIDs($pageIDs); ->byIDs($pageIDs);
} }
}
/** /**
* Get the list of incomplete BrokenExternalPageTrack * Get the list of incomplete BrokenExternalPageTrack
* *
* @return DataList * @return DataList
*/ */
public function getIncompleteTracks() { public function getIncompleteTracks()
{
return $this return $this
->TrackedPages() ->TrackedPages()
->filter('Processed', 0); ->filter('Processed', 0);
@ -64,14 +72,16 @@ class BrokenExternalPageTrackStatus extends DataObject {
/** /**
* Get total pages count * Get total pages count
*/ */
public function getTotalPages() { public function getTotalPages()
{
return $this->TrackedPages()->count(); return $this->TrackedPages()->count();
} }
/** /**
* Get completed pages count * Get completed pages count
*/ */
public function getCompletedPages() { public function getCompletedPages()
{
return $this return $this
->TrackedPages() ->TrackedPages()
->filter('Processed', 1) ->filter('Processed', 1)
@ -83,7 +93,8 @@ class BrokenExternalPageTrackStatus extends DataObject {
* *
* @return self * @return self
*/ */
public static function get_or_create() { public static function get_or_create()
{
// Check the current status // Check the current status
$status = self::get_latest(); $status = self::get_latest();
if ($status && $status->Status == 'Running') { if ($status && $status->Status == 'Running') {
@ -99,13 +110,14 @@ class BrokenExternalPageTrackStatus extends DataObject {
* *
* @return self * @return self
*/ */
public static function create_status() { public static function create_status()
{
// If the script is to be started create a new status // If the script is to be started create a new status
$status = self::create(); $status = self::create();
$status->updateJobInfo('Creating new tracking object'); $status->updateJobInfo('Creating new tracking object');
// Setup all pages to test // Setup all pages to test
$pageIDs = Versioned::get_by_stage('SiteTree', 'Stage') $pageIDs = Versioned::get_by_stage(SiteTree::class, 'Stage')
->column('ID'); ->column('ID');
foreach ($pageIDs as $pageID) { foreach ($pageIDs as $pageID) {
$trackPage = BrokenExternalPageTrack::create(); $trackPage = BrokenExternalPageTrack::create();
@ -117,7 +129,8 @@ class BrokenExternalPageTrackStatus extends DataObject {
return $status; return $status;
} }
public function updateJobInfo($message) { public function updateJobInfo($message)
{
$this->JobInfo = $message; $this->JobInfo = $message;
$this->write(); $this->write();
} }
@ -125,7 +138,8 @@ class BrokenExternalPageTrackStatus extends DataObject {
/** /**
* Self check status * Self check status
*/ */
public function updateStatus() { public function updateStatus()
{
if ($this->CompletedPages == $this->TotalPages) { if ($this->CompletedPages == $this->TotalPages) {
$this->Status = 'Completed'; $this->Status = 'Completed';
$this->updateJobInfo('Setting to completed'); $this->updateJobInfo('Setting to completed');

View File

@ -2,13 +2,12 @@
namespace SilverStripe\ExternalLinks\Reports; namespace SilverStripe\ExternalLinks\Reports;
use SS_Report; use SilverStripe\Core\Convert;
use Convert; use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use BrokenExternalPageTrackStatus; use SilverStripe\ORM\ArrayList;
use ArrayList; use SilverStripe\View\Requirements;
use Requirements; use SilverStripe\Forms\LiteralField;
use LiteralField; use SilverStripe\Reports\Report;
/** /**
* Content side-report listing pages with external broken links * Content side-report listing pages with external broken links
@ -16,23 +15,26 @@ use LiteralField;
* @subpackage content * @subpackage content
*/ */
class BrokenExternalLinksReport extends SS_Report { class BrokenExternalLinksReport extends Report
{
/** /**
* Returns the report title * Returns the report title
* *
* @return string * @return string
*/ */
public function title() { public function title()
{
return _t('ExternalBrokenLinksReport.EXTERNALBROKENLINKS', "External broken links report"); return _t('ExternalBrokenLinksReport.EXTERNALBROKENLINKS', "External broken links report");
} }
public function columns() { public function columns()
{
return array( return array(
"Created" => "Checked", "Created" => "Checked",
'Link' => array( 'Link' => array(
'title' => 'External Link', 'title' => 'External Link',
'formatting' => function($value, $item) { 'formatting' => function ($value, $item) {
return sprintf( return sprintf(
'<a target="_blank" href="%s">%s</a>', '<a target="_blank" href="%s">%s</a>',
Convert::raw2att($item->Link), Convert::raw2att($item->Link),
@ -43,7 +45,7 @@ class BrokenExternalLinksReport extends SS_Report {
'HTTPCodeDescription' => 'HTTP Error Code', 'HTTPCodeDescription' => 'HTTP Error Code',
"Title" => array( "Title" => array(
"title" => 'Page link is on', "title" => 'Page link is on',
'formatting' => function($value, $item) { 'formatting' => function ($value, $item) {
$page = $item->Page(); $page = $item->Page();
return sprintf( return sprintf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
@ -60,17 +62,22 @@ class BrokenExternalLinksReport extends SS_Report {
* in {@link GridFieldExportButton} generateExportFileData method. * in {@link GridFieldExportButton} generateExportFileData method.
* @return array * @return array
*/ */
public function getColumns() { public function getColumns()
{
return $this->columns(); return $this->columns();
} }
public function sourceRecords() { public function sourceRecords()
{
$track = BrokenExternalPageTrackStatus::get_latest(); $track = BrokenExternalPageTrackStatus::get_latest();
if ($track) return $track->BrokenLinks(); if ($track) {
return $track->BrokenLinks();
}
return new ArrayList(); return new ArrayList();
} }
public function getCMSFields() { public function getCMSFields()
{
Requirements::javascript('externallinks/javascript/BrokenExternalLinksReport.js'); Requirements::javascript('externallinks/javascript/BrokenExternalLinksReport.js');
$fields = parent::getCMSFields(); $fields = parent::getCMSFields();

View File

@ -2,18 +2,23 @@
namespace SilverStripe\ExternalLinks\Tasks; namespace SilverStripe\ExternalLinks\Tasks;
use BuildTask;
use Debug;
use BrokenExternalPageTrack;
use DOMNode; use DOMNode;
use BrokenExternalLink;
use Config;
use BrokenExternalPageTrackStatus;
use Injector;
use DB;
class CheckExternalLinksTask extends BuildTask {
use SilverStripe\Dev\Debug;
use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrack;
use SilverStripe\ExternalLinks\Model\BrokenExternalLink;
use SilverStripe\Core\Config\Config;
use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DB;
use SilverStripe\Dev\BuildTask;
class CheckExternalLinksTask extends BuildTask
{
private static $dependencies = array( private static $dependencies = array(
'LinkChecker' => '%$LinkChecker' 'LinkChecker' => '%$LinkChecker'
@ -40,11 +45,15 @@ class CheckExternalLinksTask extends BuildTask {
* *
* @param string $message * @param string $message
*/ */
protected function log($message) { protected function log($message)
if(!$this->silent) Debug::message($message); {
if (!$this->silent) {
Debug::message($message);
}
} }
public function run($request) { public function run($request)
{
$this->runLinksCheck(); $this->runLinksCheck();
} }
/** /**
@ -52,21 +61,24 @@ class CheckExternalLinksTask extends BuildTask {
* *
* @param bool $silent * @param bool $silent
*/ */
public function setSilent($silent) { public function setSilent($silent)
{
$this->silent = $silent; $this->silent = $silent;
} }
/** /**
* @param LinkChecker $linkChecker * @param LinkChecker $linkChecker
*/ */
public function setLinkChecker(LinkChecker $linkChecker) { public function setLinkChecker(LinkChecker $linkChecker)
{
$this->linkChecker = $linkChecker; $this->linkChecker = $linkChecker;
} }
/** /**
* @return LinkChecker * @return LinkChecker
*/ */
public function getLinkChecker() { public function getLinkChecker()
{
return $this->linkChecker; return $this->linkChecker;
} }
@ -76,17 +88,20 @@ class CheckExternalLinksTask extends BuildTask {
* @param BrokenExternalPageTrack $pageTrack * @param BrokenExternalPageTrack $pageTrack
* @param DOMNode $link * @param DOMNode $link
*/ */
protected function checkPageLink(BrokenExternalPageTrack $pageTrack, DOMNode $link) { protected function checkPageLink(BrokenExternalPageTrack $pageTrack, DOMNode $link)
{
$class = $link->getAttribute('class'); $class = $link->getAttribute('class');
$href = $link->getAttribute('href'); $href = $link->getAttribute('href');
$markedBroken = preg_match('/\b(ss-broken)\b/', $class); $markedBroken = preg_match('/\b(ss-broken)\b/', $class);
// Check link // Check link
$httpCode = $this->linkChecker->checkLink($href); $httpCode = $this->linkChecker->checkLink($href);
if($httpCode === null) return; // Null link means uncheckable, such as an internal link if ($httpCode === null) {
return; // Null link means uncheckable, such as an internal link
}
// If this code is broken then mark as such // If this code is broken then mark as such
if($foundBroken = $this->isCodeBroken($httpCode)) { if ($foundBroken = $this->isCodeBroken($httpCode)) {
// Create broken record // Create broken record
$brokenLink = new BrokenExternalLink(); $brokenLink = new BrokenExternalLink();
$brokenLink->Link = $href; $brokenLink->Link = $href;
@ -97,8 +112,10 @@ class CheckExternalLinksTask extends BuildTask {
} }
// Check if we need to update CSS class, otherwise return // Check if we need to update CSS class, otherwise return
if($markedBroken == $foundBroken) return; if ($markedBroken == $foundBroken) {
if($foundBroken) { return;
}
if ($foundBroken) {
$class .= ' ss-broken'; $class .= ' ss-broken';
} else { } else {
$class = preg_replace('/\s*\b(ss-broken)\b\s*/', ' ', $class); $class = preg_replace('/\s*\b(ss-broken)\b\s*/', ' ', $class);
@ -112,13 +129,18 @@ class CheckExternalLinksTask extends BuildTask {
* @param int $httpCode * @param int $httpCode
* @return bool True if this is a broken code * @return bool True if this is a broken code
*/ */
protected function isCodeBroken($httpCode) { protected function isCodeBroken($httpCode)
{
// Null represents no request attempted // Null represents no request attempted
if($httpCode === null) return false; if ($httpCode === null) {
return false;
}
// do we have any whitelisted codes // do we have any whitelisted codes
$ignoreCodes = Config::inst()->get('CheckExternalLinks', 'IgnoreCodes'); $ignoreCodes = Config::inst()->get('CheckExternalLinks', 'IgnoreCodes');
if(is_array($ignoreCodes) && in_array($httpCode, $ignoreCodes)) return false; if (is_array($ignoreCodes) && in_array($httpCode, $ignoreCodes)) {
return false;
}
// Check if code is outside valid range // Check if code is outside valid range
return $httpCode < 200 || $httpCode > 302; return $httpCode < 200 || $httpCode > 302;
@ -130,13 +152,16 @@ class CheckExternalLinksTask extends BuildTask {
* @param int $limit Limit to number of pages to run, or null to run all * @param int $limit Limit to number of pages to run, or null to run all
* @return BrokenExternalPageTrackStatus * @return BrokenExternalPageTrackStatus
*/ */
public function runLinksCheck($limit = null) { public function runLinksCheck($limit = null)
{
// Check the current status // Check the current status
$status = BrokenExternalPageTrackStatus::get_or_create(); $status = BrokenExternalPageTrackStatus::get_or_create();
// Calculate pages to run // Calculate pages to run
$pageTracks = $status->getIncompleteTracks(); $pageTracks = $status->getIncompleteTracks();
if($limit) $pageTracks = $pageTracks->limit($limit); if ($limit) {
$pageTracks = $pageTracks->limit($limit);
}
// Check each page // Check each page
foreach ($pageTracks as $pageTrack) { foreach ($pageTracks as $pageTrack) {
@ -148,11 +173,13 @@ class CheckExternalLinksTask extends BuildTask {
$page = $pageTrack->Page(); $page = $pageTrack->Page();
$this->log("Checking {$page->Title}"); $this->log("Checking {$page->Title}");
$htmlValue = Injector::inst()->create('HTMLValue', $page->Content); $htmlValue = Injector::inst()->create('HTMLValue', $page->Content);
if (!$htmlValue->isValid()) continue; if (!$htmlValue->isValid()) {
continue;
}
// Check each link // Check each link
$links = $htmlValue->getElementsByTagName('a'); $links = $htmlValue->getElementsByTagName('a');
foreach($links as $link) { foreach ($links as $link) {
$this->checkPageLink($pageTrack, $link); $this->checkPageLink($pageTrack, $link);
} }
@ -164,7 +191,7 @@ class CheckExternalLinksTask extends BuildTask {
// Once all links have been created for this page update HasBrokenLinks // Once all links have been created for this page update HasBrokenLinks
$count = $pageTrack->BrokenLinks()->count(); $count = $pageTrack->BrokenLinks()->count();
$this->log("Found {$count} broken links"); $this->log("Found {$count} broken links");
if($count) { if ($count) {
// Bypass the ORM as syncLinkTracking does not allow you to update HasBrokenLink to true // Bypass the ORM as syncLinkTracking does not allow you to update HasBrokenLink to true
DB::query(sprintf( DB::query(sprintf(
'UPDATE "SiteTree" SET "HasBrokenLink" = 1 WHERE "ID" = \'%d\'', 'UPDATE "SiteTree" SET "HasBrokenLink" = 1 WHERE "ID" = \'%d\'',
@ -178,7 +205,8 @@ class CheckExternalLinksTask extends BuildTask {
return $status; return $status;
} }
private function updateCompletedPages($trackID = 0) { private function updateCompletedPages($trackID = 0)
{
$noPages = BrokenExternalPageTrack::get() $noPages = BrokenExternalPageTrack::get()
->filter(array( ->filter(array(
'TrackID' => $trackID, 'TrackID' => $trackID,
@ -191,9 +219,10 @@ class CheckExternalLinksTask extends BuildTask {
return $noPages; return $noPages;
} }
private function updateJobInfo($message) { private function updateJobInfo($message)
{
$track = BrokenExternalPageTrackStatus::get_latest(); $track = BrokenExternalPageTrackStatus::get_latest();
if($track) { if ($track) {
$track->JobInfo = $message; $track->JobInfo = $message;
$track->write(); $track->write();
} }

View File

@ -4,18 +4,19 @@ namespace SilverStripe\ExternalLinks\Tasks;
use SS_Cache; use SS_Cache;
/** /**
* Check links using curl * Check links using curl
*/ */
class CurlLinkChecker implements LinkChecker { class CurlLinkChecker implements LinkChecker
{
/** /**
* Return cache * Return cache
* *
* @return Zend_Cache_Frontend * @return Zend_Cache_Frontend
*/ */
protected function getCache() { protected function getCache()
{
return SS_Cache::factory( return SS_Cache::factory(
__CLASS__, __CLASS__,
'Output', 'Output',
@ -29,18 +30,23 @@ class CurlLinkChecker implements LinkChecker {
* @param string $href URL to check * @param string $href URL to check
* @return int HTTP status code, or null if not checkable (not a link) * @return int HTTP status code, or null if not checkable (not a link)
*/ */
public function checkLink($href) { public function checkLink($href)
{
// Skip non-external links // Skip non-external links
if(!preg_match('/^https?[^:]*:\/\//', $href)) return null; if (!preg_match('/^https?[^:]*:\/\//', $href)) {
return null;
}
// Check if we have a cached result // Check if we have a cached result
$cacheKey = md5($href); $cacheKey = md5($href);
$result = $this->getCache()->load($cacheKey); $result = $this->getCache()->load($cacheKey);
if($result !== false) return $result; if ($result !== false) {
return $result;
}
// No cached result so just request // No cached result so just request
$handle = curl_init($href); $handle = curl_init($href);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 10); curl_setopt($handle, CURLOPT_TIMEOUT, 10);
curl_exec($handle); curl_exec($handle);

View File

@ -2,13 +2,11 @@
namespace SilverStripe\ExternalLinks\Tasks; namespace SilverStripe\ExternalLinks\Tasks;
/** /**
* Provides an interface for checking that a link is valid * Provides an interface for checking that a link is valid
*/ */
interface LinkChecker { interface LinkChecker
{
/** /**
* Determine the http status code for a given link * Determine the http status code for a given link

View File

@ -1,6 +1,16 @@
<?php <?php
class ExternalLinksTest extends SapphireTest { use SilverStripe\ExternalLinks\Tasks\LinkChecker;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ExternalLinks\Tasks\CheckExternalLinksTask;
use SilverStripe\ExternalLinks\Model\BrokenExternalPageTrackStatus;
use SilverStripe\i18n\i18n;
use SilverStripe\Reports\Report;
use SilverStripe\ExternalLinks\Reports\BrokenExternalLinksReport;
use SilverStripe\Dev\SapphireTest;
class ExternalLinksTest extends SapphireTest
{
protected static $fixture_file = 'ExternalLinksTest.yml'; protected static $fixture_file = 'ExternalLinksTest.yml';
@ -12,7 +22,8 @@ class ExternalLinksTest extends SapphireTest {
'SiteTree' => array('Translatable') 'SiteTree' => array('Translatable')
); );
public function setUpOnce() { public function setUpOnce()
{
if (class_exists('Phockito')) { if (class_exists('Phockito')) {
Phockito::include_hamcrest(false); Phockito::include_hamcrest(false);
} }
@ -20,7 +31,8 @@ class ExternalLinksTest extends SapphireTest {
parent::setUpOnce(); parent::setUpOnce();
} }
public function setUp() { public function setUp()
{
parent::setUp(); parent::setUp();
// Check dependencies // Check dependencies
@ -30,7 +42,7 @@ class ExternalLinksTest extends SapphireTest {
} }
// Mock link checker // Mock link checker
$checker = Phockito::mock('LinkChecker'); $checker = Phockito::mock(LinkChecker::class);
Phockito::when($checker) Phockito::when($checker)
->checkLink('http://www.working.com') ->checkLink('http://www.working.com')
->return(200); ->return(200);
@ -71,10 +83,11 @@ class ExternalLinksTest extends SapphireTest {
->checkLink(Hamcrest_Matchers::anything()) // anything else is 404 ->checkLink(Hamcrest_Matchers::anything()) // anything else is 404
->return(404); ->return(404);
Injector::inst()->registerService($checker, 'LinkChecker'); Injector::inst()->registerService($checker, LinkChecker::class);
} }
public function testLinks() { public function testLinks()
{
// Run link checker // Run link checker
$task = CheckExternalLinksTask::create(); $task = CheckExternalLinksTask::create();
$task->setSilent(true); // Be quiet during the test! $task->setSilent(true); // Be quiet during the test!
@ -87,7 +100,7 @@ class ExternalLinksTest extends SapphireTest {
$this->assertEquals(5, $status->CompletedPages); $this->assertEquals(5, $status->CompletedPages);
// Check all pages have had the correct HTML adjusted // Check all pages have had the correct HTML adjusted
for($i = 1; $i <= 5; $i++) { for ($i = 1; $i <= 5; $i++) {
$page = $this->objFromFixture('ExternalLinksTestPage', 'page'.$i); $page = $this->objFromFixture('ExternalLinksTestPage', 'page'.$i);
$this->assertNotEmpty($page->Content); $this->assertNotEmpty($page->Content);
$this->assertEquals( $this->assertEquals(
@ -136,13 +149,17 @@ class ExternalLinksTest extends SapphireTest {
/** /**
* Test that broken links appears in the reports list * Test that broken links appears in the reports list
*/ */
public function testReportExists() { public function testReportExists()
$reports = SS_Report::get_reports(); {
$reports = Report::get_reports();
$reportNames = array(); $reportNames = array();
foreach($reports as $report) { foreach ($reports as $report) {
$reportNames[] = $report->class; $reportNames[] = $report->class;
} }
$this->assertContains('BrokenExternalLinksReport',$reportNames, $this->assertContains(
'BrokenExternalLinksReport is in reports list'); BrokenExternalLinksReport::class,
$reportNames,
'BrokenExternalLinksReport is in reports list'
);
} }
} }

View File

@ -1,5 +1,7 @@
<?php <?php
use SilverStripe\Dev\TestOnly;
class ExternalLinksTestPage extends Page implements TestOnly class ExternalLinksTestPage extends Page implements TestOnly
{ {
private static $db = array( private static $db = array(