Skip to content

Commit

Permalink
RedirectorPageController: Add extension hook to customise the HTTPRes…
Browse files Browse the repository at this point in the history
…ponse for empty links
  • Loading branch information
Marco Hermo committed May 31, 2021
1 parent 4c8823f commit fb5309e
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 1 deletion.
7 changes: 6 additions & 1 deletion code/Model/RedirectorPageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ public function index(HTTPRequest $request)
if (!$this->getResponse()->isFinished() && $link = $page->redirectionLink()) {
$this->redirect($link, 301);
}
return parent::handleAction($request, 'handleIndex');

$response = parent::handleAction($request, 'handleIndex');

$this->extend('onMissingLinkResponse', $response);

return $response;
}

/**
Expand Down
29 changes: 29 additions & 0 deletions tests/php/Model/RedirectorPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public function testEmptyRedirectors()
/* If a redirector page is misconfigured, then its link method will just return the usual URLSegment-generated value */
$page1 = $this->objFromFixture(RedirectorPage::class, 'badexternal');
$this->assertEquals('/bad-external/', $page1->Link());
$response = $this->get($page1->Link());
$this->assertEquals(200, $response->getStatusCode());

/* An error message will be shown if you visit it */
$content = $this->get(Director::makeRelative($page1->Link()))->getBody();
Expand All @@ -49,6 +51,33 @@ public function testEmptyRedirectors()
$this->assertEquals('/bad-internal/', $page2->Link());
$content = $this->get(Director::makeRelative($page2->Link()))->getBody();
$this->assertContains('message-setupWithoutRedirect', $content);
$response = $this->get($page2->Link());
$this->assertEquals(200, $response->getStatusCode());
}

public function testOnMissingLinkResponse()
{
/* And extension hook is configured to provide a custom behaviour for handling empty links */
RedirectorPageController::add_extension(RedirectorPageTest_MissingLinkExtension::class);

$page1 = $this->objFromFixture(RedirectorPage::class, 'badexternal');
$this->assertEquals('/bad-external/', $page1->Link());
$response = $this->get($page1->Link());
$this->assertEquals(404, $response->getStatusCode());

/* An error message will be shown if you visit it */
$content = $this->get(Director::makeRelative($page1->Link()))->getBody();
$this->assertContains('message-setupWithoutRedirect', $content);

/* This also applies for internal links */
$page2 = $this->objFromFixture(RedirectorPage::class, 'badinternal');
$this->assertEquals('/bad-internal/', $page2->Link());
$content = $this->get(Director::makeRelative($page2->Link()))->getBody();
$this->assertContains('message-setupWithoutRedirect', $content);
$response = $this->get($page2->Link());
$this->assertEquals(404, $response->getStatusCode());

RedirectorPageController::remove_extension(RedirectorPageTest_MissingLinkExtension::class);
}

public function testReflexiveAndTransitiveInternalRedirectors()
Expand Down
38 changes: 38 additions & 0 deletions tests/php/Model/RedirectorPageTest_MissingLinkExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace SilverStripe\CMS\Tests\Model;

use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Extension;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\FieldType\DBHTMLText;

class RedirectorPageTest_MissingLinkExtension extends Extension implements TestOnly
{

/**
* This extension is only applied whenever the link is null or not found
* One possible scenario is an internal link has been unpublished
* If lots of RedirectorPage then its hard to track and update
*
* An example use case is to change the content and status code to 404
* Another way is to redirect users to existing 404 page
*
* In this example, this extension only changes the status code to 404 for demonstration
*
* @see RedirectorPageController::index() as the owner
* @param $response
* @return void
*/
public function onMissingLinkResponse(&$response)
{
if ($response instanceof HTTPResponse) {
$response->setStatusCode(404);
}

if ($response instanceof DBHTMLText) {
$response = new HTTPResponse($response->forTemplate(), 404);
}
}

}

0 comments on commit fb5309e

Please sign in to comment.