Skip to content
This repository was archived by the owner on Aug 28, 2020. It is now read-only.

Commit 85aa81d

Browse files
author
Marvin Kuhn
authored
multi error page support added (#1)
1 parent 044344d commit 85aa81d

File tree

4 files changed

+120
-23
lines changed

4 files changed

+120
-23
lines changed

Classes/Utility/PathUtility.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
namespace Breadlesscode\ErrorPages\Utility;
3+
4+
class PathUtility
5+
{
6+
public static function cutLastPart($path, $delimiter = '/')
7+
{
8+
$pos = strrpos($path, $delimiter);
9+
10+
if ($pos === false || $pos === 1) {
11+
return null;
12+
}
13+
14+
return substr($path, 0, $pos);
15+
}
16+
public static function path2array($path, $delimiter = '/')
17+
{
18+
$array = [$path];
19+
20+
while ($path = self::cutLastPart($path))
21+
{
22+
$array[] = $path;
23+
}
24+
25+
if (\end($array) !== "") {
26+
$array[] = '';
27+
}
28+
return $array;
29+
}
30+
public static function compare($pathOne, $pathTwo, $delimiter = '/')
31+
{
32+
$pathOne = self::path2array($pathOne);
33+
$pathTwo = self::path2array($pathTwo);
34+
35+
for ($distance = 0; $distance < count($pathOne); $distance++) {
36+
for ($p2index = 0; $p2index < count($pathTwo); $p2index++) {
37+
if ($pathOne[$distance] === $pathTwo[$p2index]) {
38+
return $distance + $p2index;
39+
}
40+
}
41+
}
42+
43+
return -1;
44+
}
45+
}

Classes/ViewHelpers/PageViewHelper.php

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<?php
22
namespace Breadlesscode\ErrorPages\ViewHelpers;
33

4-
use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper;
4+
use Neos\ContentRepository\Domain\Model\Node;
55
use Neos\ContentRepository\Domain\Service\ContextFactoryInterface;
66
use Neos\Eel\FlowQuery\FlowQuery;
77
use Neos\Flow\Annotations as Flow;
8-
use Neos\Neos\View\FusionView;
8+
use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper;
99
use Neos\Neos\Routing\FrontendNodeRoutePartHandler;
10-
10+
use Neos\Neos\View\FusionView;
11+
use Breadlesscode\ErrorPages\Utility\PathUtility;
1112

1213
class PageViewHelper extends AbstractViewHelper
1314
{
@@ -36,11 +37,16 @@ class PageViewHelper extends AbstractViewHelper
3637
*/
3738
public function render($exception)
3839
{
39-
$statusCode = $exception->getStatusCode();
40-
$dimension = $this->getCurrentDimension();
41-
$errorPage = $this->findErrorPage($statusCode, $dimension);
40+
$requestPath = PathUtility::cutLastPart(
41+
$this->controllerContext
42+
->getRequest()
43+
->getHttpRequest()
44+
->getUri()
45+
->getPath()
46+
);
47+
$errorPage = $this->findErrorPage($requestPath, $exception->getStatusCode());
4248

43-
if($errorPage === null) {
49+
if ($errorPage === null) {
4450
throw new \Exception("Please setup a error page of type ".self::ERROR_PAGE_TYPE."!", 1);
4551
}
4652
// render error page
@@ -58,23 +64,49 @@ public function render($exception)
5864
* @param string $dimension
5965
* @return Neos\ContentRepository\Domain\Model\Node
6066
*/
61-
protected function findErrorPage($statusCode, $dimension)
67+
protected function findErrorPage($requestPath, $statusCode)
6268
{
69+
$dimension = $this->getDimensionOfPath($requestPath);
6370
$errorPages = collect($this->getErrorPages($dimension));
6471
$statusCode = (string) $statusCode;
6572
// find the correct error page
66-
return $errorPages
73+
$errorPages = $errorPages
6774
// filter invalid status codes
68-
->filter(function($page) use($statusCode) {
75+
->filter(function ($page) use ($statusCode) {
6976
$supportedStatusCodes = $page->getProperty('statusCodes');
70-
7177
return $supportedStatusCodes !== null && \in_array($statusCode, $supportedStatusCodes);
7278
})
7379
// filter invalid dimensions
74-
->filter(function($page) use($dimension) {
80+
->filter(function ($page) use ($dimension) {
7581
return \in_array($dimension, $page->getDimensions()['language']);
7682
})
77-
->first();
83+
// filter all pages which not in the correct path
84+
->sortBy(function ($page) use ($requestPath, $dimension) {
85+
return PathUtility::compare(
86+
$this->getPathWithoutDimensionPrefix($requestPath),
87+
PathUtility::cutLastPart($this->getPathWithoutDimensionPrefix($this->getUriOfNode($page)))
88+
);
89+
});
90+
return $errorPages->first();
91+
}
92+
/**
93+
* return path without the dimension prefix
94+
*
95+
* @param string $path
96+
* @param string $dimension
97+
* @return string
98+
*/
99+
protected function getPathWithoutDimensionPrefix($path)
100+
{
101+
$presets = collect($this->contentDimensionsConfig['presets']);
102+
$matches = [];
103+
preg_match(FrontendNodeRoutePartHandler::DIMENSION_REQUEST_PATH_MATCHER, ltrim($path, '/'), $matches);
104+
105+
if ($presets->pluck('uriSegment')->contains($matches['firstUriPart'])) {
106+
return substr(ltrim($path, '/'), strlen($matches['firstUriPart']));
107+
}
108+
109+
return $path;
78110
}
79111
/**
80112
* collects all error pages from the site
@@ -111,14 +143,13 @@ protected function getContext($dimension)
111143
*
112144
* @return string dimension preset key
113145
*/
114-
protected function getCurrentDimension()
146+
protected function getDimensionOfPath($path)
115147
{
116148
$matches = [];
117-
$requestPath = ltrim($this->controllerContext->getRequest()->getHttpRequest()->getUri()->getPath(), '/');
118-
preg_match(FrontendNodeRoutePartHandler::DIMENSION_REQUEST_PATH_MATCHER, $requestPath, $matches);
149+
preg_match(FrontendNodeRoutePartHandler::DIMENSION_REQUEST_PATH_MATCHER, ltrim($path, '/'), $matches);
119150

120151
$presets = collect($this->contentDimensionsConfig['presets'])
121-
->filter(function($value, $key) use($matches) {
152+
->filter(function ($value, $key) use ($matches) {
122153
$uriSegment = data_get($value, 'uriSegment');
123154
return (
124155
$uriSegment !== null && (
@@ -128,15 +159,32 @@ protected function getCurrentDimension()
128159
);
129160
});
130161

131-
if($presets->count() > 0) {
162+
if ($presets->count() > 0) {
132163
return $presets->keys()->first();
133164
}
134165

135-
if($this->supportEmptySegmentForDimensions) {
166+
if ($this->supportEmptySegmentForDimensions) {
136167
return $this->contentDimensionsConfig['defaultPreset'];
137168
}
138169

139170
return null;
140171
}
172+
/**
173+
* get the uri of a node
174+
*
175+
* @param Node $node
176+
* @return string
177+
*/
178+
protected function getUriOfNode(Node $node)
179+
{
180+
static $uriBuilder = null;
141181

182+
if ($uriBuilder === null) {
183+
$uriBuilder = $this->controllerContext->getUriBuilder();
184+
$uriBuilder->setRequest($this->controllerContext->getRequest()->getMainRequest());
185+
$uriBuilder->reset();
186+
}
187+
188+
return $uriBuilder->uriFor('show', ['node' => $node], 'Frontend\\Node', 'Neos.Neos');
189+
}
142190
}
File renamed without changes.

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@
33
[![Downloads](https://img.shields.io/packagist/dt/breadlesscode/neos-error-pages.svg)]()
44
[![license](https://img.shields.io/github/license/breadlesscode/neos-error-pages.svg)]()
55

6-
This package provides a error page NodeType.
6+
This package provides multible error pages for your NEOS CMS site.
7+
You can have a error page for each sub folder, this package shows the nearest error page.
78

89
## Installation
910
Install this package in your NEOS project root.
1011

1112
```
12-
composer require breadlesscode/neos-error-pages
13+
composer require breadlesscode/neos-error-pages
1314
```
15+
Nearly zero configuration!
1416

1517
## Usage
1618

1719
1. Create your error page in your dimension.
18-
2. Select the correct status codes in the NEOS inspector.
20+
2. Select the correct status codes in the NEOS inspector.
1921
3. Publish
2022

2123
## Todo
22-
- [ ] Multiple error pages. Select nearest error page
2324
- [ ] Write some tests (as always...)
25+
26+
## License
27+
The MIT License (MIT). Please see [License File](LICENSE) for more information.

0 commit comments

Comments
 (0)