arse/includes/core/urls.inc.php
Emmanuel BENOîT b80ac7ee91 Added really basic error view
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.
2012-02-05 18:22:01 +01:00

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( );
}
}