Kohana 3 — обработка ошибок (404)

По умолчанию в php фреймворке Kohana 3 обработка ошибки 404 выглядит так:

ReflectionException [ -1 ]: Class controller_logins does not exist
SYSPATH/classes/kohana/request.php [ 864 ]

859 		}

860 
861 		try
862 		{
863 			// Load the controller using reflection
864 			$class = new ReflectionClass($prefix.$this->controller);
865 

866 			if ($class->isAbstract())
867 			{
868 				throw new Kohana_Exception('Cannot create instances of abstract :controller',
869 					array(':controller' => $prefix.$this->controller));
SYSPATH/classes/kohana/request.php [ 864 ] » ReflectionClass->__construct(arguments)

APPPATH/bootstrap.php [ 132 ] » Kohana_Request->execute()

DOCROOT/index.php [ 103 ] » require(arguments)

Environment

Естественно что такой вариант никого не устроит. Я долго гуглил на эту тему… Почти все варианты решения проблемы основаны на перехвате ошибок перед выводом данных пользователю. Это происходит в файле bootstrap.php (используется конструкция try catch)
К сожелению все маны по этой теме оказались не полными или даже с ошибками, так что постараюсь все расписать…
1)В файле application/bootstrap.php в конце

echo Request::instance()
        ->execute()
        ->send_headers()
        ->response;
меняем на
/**
* Set the production status
*/
define('IN_PRODUCTION', FALSE);
 
/**
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
* If no source is specified, the URI will be automatically detected.
*/
$request = Request::instance();
 
try
{
    $request->execute();
}
catch (ReflectionException $e)
{
        $request = Request::factory('error/404')->execute();
}
catch (Exception $e)
{
    if ( ! IN_PRODUCTION )
    {
        throw $e;
    }
 
    $request = Request::factory('error/500')->execute();
}
 
echo $request->send_headers()->response;

2)Создаем контроллер application/classes/controller/error.php:

<?php defined('SYSPATH') or die('No direct script access.');
 
class Controller_Error extends Controller {
 
    public function action_404()
    {
        $this->request->status = 404;
        $this->request->headers['HTTP/1.1'] = '404';
        $this->request->response = 'Ошибка 404! Страница не существует.';
    }
 
    public function action_403()
    {
        $this->request->status = 403;
        $this->request->headers['HTTP/1.1'] = '403';
        $this->request->response = 'Ошибка 403';
    }
 
    public function action_500()
    {
        $this->request->status = 500;
        $this->request->headers['HTTP/1.1'] = '500';
        $this->request->response = 'Ошибка 500';
    }
} // End Error

3)вернемся к маршрутам (application/bootstrap.php). Стандартный такой:

Route::set('default', '((/(/)))')
        ->defaults(array(
                'controller' => 'welcome',
                'action'     => 'index',
            
        ));

а мы добавим еще один:

Route::set('files', '()',array('file' => '.+'))
        ->defaults(array(
                'controller' => 'error',
                'action'     => '404',
            
        ));

Теперь если пользователь введет нечто не подходящее под стандартный маршрут, то он получит не ошибку от Kohana с куском кода, а страницу 404.

Бывает что нужно перекинуть пользователя на страницу 404 из контроллеров… Для этого можно обойтись таким:

$this->request->redirect('error/404','404');

Второй параметр не обязателен (он указывает код ответа в заголовках).