Emmanuel BENOîT
b80ac7ee91
Added a terribly ugly view that displays errors (e.g. 404's). It may be ugly but it's still better than a PHP exception.
168 lines
3.6 KiB
PHP
168 lines
3.6 KiB
PHP
<?php
|
|
|
|
|
|
final class URLMapperException extends Exception {}
|
|
|
|
|
|
final class URLMapper
|
|
implements PackageAware
|
|
{
|
|
private $package;
|
|
private $prefix;
|
|
private $configBase;
|
|
|
|
public function __construct( $prefix = null )
|
|
{
|
|
$this->prefix = $prefix;
|
|
$this->configBase = ( $prefix == null ) ? 'urls' : $prefix;
|
|
}
|
|
|
|
public function setPackage( Package $package )
|
|
{
|
|
if ( $this->package !== null ) {
|
|
throw new Exception( 'trying to call setPackage() twice' );
|
|
}
|
|
$this->package = $package;
|
|
}
|
|
|
|
|
|
public function fromPathInfo( )
|
|
{
|
|
if ( array_key_exists( 'PATH_INFO' , $_SERVER ) ) {
|
|
$path = $_SERVER[ 'PATH_INFO' ];
|
|
} else {
|
|
$path = '/' . $this->package->config( $this->configBase . '/default' , 'home' );
|
|
}
|
|
|
|
$this->fromPath( $path );
|
|
}
|
|
|
|
public function fromPath( $path )
|
|
{
|
|
if ( ! preg_match( '/^(\/[a-z0-9]+)+$/' , $path ) ) {
|
|
$this->showPageNotFound( );
|
|
return;
|
|
}
|
|
|
|
if ( $this->prefix == null ) {
|
|
$path = substr( $path , 1 );
|
|
} else {
|
|
$path = $this->prefix . $path;
|
|
}
|
|
try {
|
|
$this->showPageFor( $path );
|
|
} catch ( URLMapperException $e ) {
|
|
$this->showPageNotFound( $path );
|
|
}
|
|
}
|
|
|
|
|
|
private function showPageNotFound( $requestPath = '' )
|
|
{
|
|
$path = $this->package->config( $this->configBase . '/errors/404', 'errors/404' );
|
|
$this->showPageFor( $path . '/' . $requestPath , false );
|
|
}
|
|
|
|
|
|
private function showPageFor( $path )
|
|
{
|
|
$split = split( '/' , $path );
|
|
$extras = array( );
|
|
while ( !empty( $split ) ) {
|
|
$name = join( '_' , $split );
|
|
try {
|
|
$page = Loader::Page( $name );
|
|
break;
|
|
} catch ( LoaderException $e ) {
|
|
array_unshift( $extras , array_pop( $split ) );
|
|
}
|
|
}
|
|
|
|
if ( empty( $split ) ) {
|
|
throw new URLMapperException( $path );
|
|
}
|
|
|
|
$this->handlePage( $path , $page , join( '/' , $extras ) );
|
|
}
|
|
|
|
|
|
private function handlePage( $requestPath , Page $page , $extraPath = '' , $pathFailure = true )
|
|
{
|
|
if ( $page instanceof PathAware ) {
|
|
$success = $page->setExtraPath( $extraPath );
|
|
} else {
|
|
$success = ( $extraPath === '' );
|
|
}
|
|
|
|
if ( $pathFailure && !$success ) {
|
|
$this->showPageNotFound( $requestPath );
|
|
} else {
|
|
$page->handle( );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class View_BasicErrorDisplay
|
|
implements View
|
|
{
|
|
private $error;
|
|
private $site;
|
|
private $path;
|
|
|
|
public function __construct( $extraPath )
|
|
{
|
|
$this->error = array_shift( $extraPath );
|
|
if ( ! empty( $extraPath ) ) {
|
|
$this->site = array_shift( $extraPath );
|
|
$this->path = join( '/' , $extraPath );
|
|
}
|
|
}
|
|
|
|
public function render( )
|
|
{
|
|
$text = HTML::make( 'p' )
|
|
->setAttribute( 'class' , 'error' )
|
|
->appendText( 'An error occurred while trying to access this page.' )
|
|
->appendElement( HTML::make( 'br' ) )
|
|
->appendText( 'Error code ' )
|
|
->appendElement( HTML::make( 'strong' )->appendText( $this->error ) )
|
|
->appendText( ' was encountered' );
|
|
if ( $this->site !== null ) {
|
|
$text->appendText( ' while trying to access ' )
|
|
->appendElement( HTML::make( 'strong' )->appendText( '/' . $this->path ) )
|
|
->appendText( ' on site ' )
|
|
->appendElement( HTML::make( 'strong' )->appendText( $this->site ) );
|
|
}
|
|
return $text->appendText( '.' );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
class Page_Errors
|
|
extends Page_Basic
|
|
implements PathAware
|
|
{
|
|
private $httpError;
|
|
|
|
public function setExtraPath( $extraPath )
|
|
{
|
|
$extraPath = split( '/' , $extraPath );
|
|
if ( (int)$extraPath[ 0 ] != 0 ) {
|
|
$this->httpError = (int) $extraPath[ 0 ];
|
|
}
|
|
$this->setTitle( 'Error ' . $extraPath[ 0 ] );
|
|
$this->addView( Loader::View( 'basic_error_display' , $extraPath ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
public function render( )
|
|
{
|
|
if ( $this->httpError !== null ) {
|
|
header( 'HTTP/1.0 ' . $this->httpError );
|
|
}
|
|
return parent::render( );
|
|
}
|
|
}
|