Properly handle 404 errors
Use 404 template instead of default Slim error page if the route is not found. Fixes #827
This commit is contained in:
parent
e2dff28b44
commit
d52ab0b1e9
6 changed files with 121 additions and 5 deletions
|
@ -10,6 +10,7 @@
|
|||
use Shaarli\Feed\FeedBuilder;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\Front\Controller\Visitor\ErrorController;
|
||||
use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
|
||||
use Shaarli\History;
|
||||
use Shaarli\Http\HttpAccess;
|
||||
use Shaarli\Netscape\NetscapeBookmarkUtils;
|
||||
|
@ -149,6 +150,9 @@ public function build(): ShaarliContainer
|
|||
);
|
||||
};
|
||||
|
||||
$container['notFoundHandler'] = function (ShaarliContainer $container): ErrorNotFoundController {
|
||||
return new ErrorNotFoundController($container);
|
||||
};
|
||||
$container['errorHandler'] = function (ShaarliContainer $container): ErrorController {
|
||||
return new ErrorController($container);
|
||||
};
|
||||
|
|
|
@ -24,21 +24,22 @@
|
|||
/**
|
||||
* Extension of Slim container to document the injected objects.
|
||||
*
|
||||
* @property string $basePath Shaarli's instance base path (e.g. `/shaarli/`)
|
||||
* @property string $basePath Shaarli's instance base path (e.g. `/shaarli/`)
|
||||
* @property BookmarkServiceInterface $bookmarkService
|
||||
* @property CookieManager $cookieManager
|
||||
* @property ConfigManager $conf
|
||||
* @property mixed[] $environment $_SERVER automatically injected by Slim
|
||||
* @property callable $errorHandler Overrides default Slim exception display
|
||||
* @property mixed[] $environment $_SERVER automatically injected by Slim
|
||||
* @property callable $errorHandler Overrides default Slim exception display
|
||||
* @property FeedBuilder $feedBuilder
|
||||
* @property FormatterFactory $formatterFactory
|
||||
* @property History $history
|
||||
* @property HttpAccess $httpAccess
|
||||
* @property LoginManager $loginManager
|
||||
* @property NetscapeBookmarkUtils $netscapeBookmarkUtils
|
||||
* @property callable $notFoundHandler Overrides default Slim exception display
|
||||
* @property PageBuilder $pageBuilder
|
||||
* @property PageCacheManager $pageCacheManager
|
||||
* @property callable $phpErrorHandler Overrides default Slim PHP error display
|
||||
* @property callable $phpErrorHandler Overrides default Slim PHP error display
|
||||
* @property PluginManager $pluginManager
|
||||
* @property SessionManager $sessionManager
|
||||
* @property Thumbnailer $thumbnailer
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Front\Controller\Visitor;
|
||||
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* Controller used to render the 404 error page.
|
||||
*/
|
||||
class ErrorNotFoundController extends ShaarliVisitorController
|
||||
{
|
||||
public function __invoke(Request $request, Response $response): Response
|
||||
{
|
||||
// Request from the API
|
||||
if (false !== strpos($request->getRequestTarget(), '/api/v1')) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
// This is required because the middleware is ignored if the route is not found.
|
||||
$this->container->basePath = rtrim($request->getUri()->getBasePath(), '/');
|
||||
|
||||
$this->assignView('error_message', t('Requested page could not be found.'));
|
||||
|
||||
return $response->withStatus(404)->write($this->render('404'));
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
use Shaarli\Feed\FeedBuilder;
|
||||
use Shaarli\Formatter\FormatterFactory;
|
||||
use Shaarli\Front\Controller\Visitor\ErrorController;
|
||||
use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
|
||||
use Shaarli\History;
|
||||
use Shaarli\Http\HttpAccess;
|
||||
use Shaarli\Netscape\NetscapeBookmarkUtils;
|
||||
|
@ -75,6 +76,7 @@ public function testBuildContainer(): void
|
|||
static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
|
||||
static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
|
||||
static::assertInstanceOf(ErrorController::class, $container->phpErrorHandler);
|
||||
static::assertInstanceOf(ErrorNotFoundController::class, $container->notFoundHandler);
|
||||
static::assertInstanceOf(PluginManager::class, $container->pluginManager);
|
||||
static::assertInstanceOf(SessionManager::class, $container->sessionManager);
|
||||
static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer);
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shaarli\Front\Controller\Visitor;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
use Slim\Http\Uri;
|
||||
|
||||
class ErrorNotFoundControllerTest extends TestCase
|
||||
{
|
||||
use FrontControllerMockHelper;
|
||||
|
||||
/** @var ErrorNotFoundController */
|
||||
protected $controller;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->createContainer();
|
||||
|
||||
$this->controller = new ErrorNotFoundController($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test displaying 404 error
|
||||
*/
|
||||
public function testDisplayNotFoundError(): void
|
||||
{
|
||||
$request = $this->createMock(Request::class);
|
||||
$request->expects(static::once())->method('getRequestTarget')->willReturn('/');
|
||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
||||
$uri = $this->createMock(Uri::class);
|
||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
||||
|
||||
return $uri;
|
||||
});
|
||||
|
||||
$response = new Response();
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
$this->assignTemplateVars($assignedVariables);
|
||||
|
||||
$result = ($this->controller)(
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
|
||||
static::assertSame(404, $result->getStatusCode());
|
||||
static::assertSame('404', (string) $result->getBody());
|
||||
static::assertSame('Requested page could not be found.', $assignedVariables['error_message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test displaying 404 error from REST API
|
||||
*/
|
||||
public function testDisplayNotFoundErrorFromAPI(): void
|
||||
{
|
||||
$request = $this->createMock(Request::class);
|
||||
$request->expects(static::once())->method('getRequestTarget')->willReturn('/sufolder/api/v1/links');
|
||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
||||
$uri = $this->createMock(Uri::class);
|
||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
||||
|
||||
return $uri;
|
||||
});
|
||||
|
||||
$response = new Response();
|
||||
|
||||
// Save RainTPL assigned variables
|
||||
$assignedVariables = [];
|
||||
$this->assignTemplateVars($assignedVariables);
|
||||
|
||||
$result = ($this->controller)($request, $response);
|
||||
|
||||
static::assertSame(404, $result->getStatusCode());
|
||||
static::assertSame([], $assignedVariables);
|
||||
}
|
||||
}
|
|
@ -94,7 +94,6 @@ protected function createContainer(): void
|
|||
protected function assignTemplateVars(array &$variables): void
|
||||
{
|
||||
$this->container->pageBuilder
|
||||
->expects(static::atLeastOnce())
|
||||
->method('assign')
|
||||
->willReturnCallback(function ($key, $value) use (&$variables) {
|
||||
$variables[$key] = $value;
|
||||
|
|
Loading…
Reference in a new issue