Custom 404 in Laravel 4.2 with layout

My page is using a global layout and there are many views with native controllers that use this layout. View called from controller action like this:

class NewsController extends BaseController {

  protected $layout = 'layouts.master';

  public function index()
  {
    $news = News::getNewsAll();

    $this->layout->content = View::make('news.index', array(
        'news' => $news
    ));
  }
}

      

I would like to create a custom 404 page in the same way because I need a normal page layout for a nested custom 404 design. Is this possible somehow? The problem is I can't set the HTTP status code to 404 from the controller, so it's just soft-404. I know the correct path would be sent Response::view('errors.404', array(), 404)

from filter.php

to App::missing()

, but I can't seem to set the layout in there just a view that is not enough. Or am I wrong and this is possible somehow?

Thank!

Update : I created a Gist for this issue with the files I am using in the project. Perhaps this helps to better understand my current state.

+3


source to share


7 replies


This is my approach. Just add the following code to the /app/start/global.php

file



App::missing(function($exception)
{
    $layout = \View::make('layouts.error');
    $layout->content = \View::make('views.errors.404');
    return Response::make($layout, 404);
});

      

+7


source


You can do the trick by adding something like this to global.php and create the required error views.

App::error(function(Exception $exception, $code)
{
    $pathInfo = Request::getPathInfo();
    $message = $exception->getMessage() ?: 'Exception';
    Log::error("$code - $message @ $pathInfo\r\n$exception");

    if (Config::get('app.debug')) {
        return;
    }

    switch ($code)
    {
        case 403:
            return Response::view( 'error/403', compact('message'), 403);

        case 500:
            return Response::view('error/500', compact('message'), 500);

        default:
            return Response::view('error/404', compact('message'), $code);
    }
});

      



You can also check the available laravel-starter-kit packages and check how they do things like this. Here is my version of laravel-admin-template

+5


source


Hmmmm ... why not end up at the top of your 404.blade.php, just expand your layout? Also ... @extends ('layouts.master')

+1


source


I can't tell you if this is the best approach or considered best practice, but like you, I was frustrated and found an alternative solution using the callAction method in Illuminate \ Routing \ Controller.

app / start / global.php

App::missing(function($exception)
{
    return App::make("ErrorController")->callAction("missing", []);
});

      

app / controllers / ErrorController.php

<?php

class ErrorController extends BaseController {

    protected $layout = 'layouts.master';

    public function missing()
    {
        $this->layout->content = View::make('errors.missing');
    }
}

      

Hope it helps!

+1


source


I know I'm late to the party, but since this question remains unanswered and ranks relatively high in the search results for the query, "Laravel 404 Error in exception handler". Just because this SO page remains a common problem and there is no solution, I would like to add more information and another possible solution for many users.

When you follow the methods suggested here and elsewhere and use the app / start / global.php file to implement App: error (), it should be noted that the base_controller is created after this file, so any variables you might pass to your regular view files (eg $ user) are not installed. If any of these variables are listed in the template that you are distributing, you get an error.

You can extend your template if you revisit your viewfiles and check if the variables are set with isset () and handle false conditions by setting default values.

For example:

@yield('styles')
<style type="text/css">
body{
    background-color: {{ $user->settings->bg_color }};
}
</style>

      

The above error will throw an error message because there is no user object at the time of execution of this object. A normal exception handler would have provided more details, but disabled it due to the need to actually show the 404 page so that you can hardly proceed with anything. However, if you are using isset () or empty (), you can post this case.

<style type="text/css">
body{
    @if(isset($user))
        background-color: {{ $user->settings->bg_color }};
    @else
        background-color: #FFCCFF;
    @endif
}
</style>

      

This simple solution doesn't help if you have multiple links in your top level layout or header file. You may need to change your @extends from the main layout to your own. For example. views / layouts / errors.blade.php.

Then in your 404.blade.php file you do something like this

@extends('layouts.errors')

      

And create views / layouts / errors.blade.php with new headers independent of $ user (or whatever).

Hope it helps.

+1


source


I scratched my head a bit on this one, here is the solution:

In app /start/global.php:

App::error(function(Exception $exception, $code) {
    if ($exception instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
      Log::error('NotFoundHttpException Route: ' . Request::url() );
    }

    Log::error($exception);

    // HTML output on staging and production only
    if (!Config::get('app.debug'))
        return App::make("ErrorsController")->callAction("error", ['code'=>$code]);
});

      

( NOTE : the above snippet only displays these custom error pages in environments where the debug mode is correct. Set the debug mode in various environments in the appropriate app.php file: http://laravel.com/docs/4.2/configuration#environment-configuration )

In app / controllers / ErrorsController.php:

protected $layout = "layouts.main";

/*
|--------------------------------------------------------------------------
| Errors Controller
|--------------------------------------------------------------------------
*/

public function error($code) {
    switch ($code) {
        case 404:
            $this->layout->content = View::make('errors.404');
        break;

        default:
            $this->layout->content = View::make('errors.500');
        break;
    }
}

      

}

( NOTE : protected $ layout = "layouts.main" refers to my main layout, which is called 'main'. Your master layout might be named something else, like "master" ,.)

Finally, create app / views / errors / 404.blade.php and app / views / errors / 500.blade.php and put whatever HTML you want for the error pages. It will automatically be wrapped in layouts.main!

Missing Pages and 500 Internal Errors will now automatically render custom error pages using the layout. You can manually invoke the error page from any controller by calling: return App::make("ErrorsController")->callAction("error", ['code'=>404]);

(replace 404 with whatever error code you want)

+1


source


OK, this is how you can achieve what you want (change if necessary).

App::error(function(Symfony\Component\HttpKernel\Exception\NotFoundHttpException $exception, $code) use ($path, $referer, $ip)
{
    // Log the exception
    Log::error($exception);

    // This is a custom model that logs the 404 in the database (so I can manage redirects etc within my app)
    ErrorPage::create(['destination_page' => $path, 'referer' => $referer, 'ip' => $ip]);

    // Return a response for the master layout
    $layout = Response::view('layouts.frontend');

    // Instantiate your error controller and run the required action/method, make sure to return a response from the action
    $view = App::make('Namespace\Controllers\Frontend\ErrorsController')->notFound();

    // Merge data from both views from the responses into a single array
    $data = array_merge($layout->original->getData(), $view->original->getData());

    // There appears to be a bug (at least in Laravel 4.2.11) where,
    // the response will always return a 200 HTTP status code, so
    // set the status code here.
    http_response_code(404);

    // Return your custom 404 error response view and pass the required data and status code.
    // Make sure your error view extends your master layout.
    return Response::view('404', $data, 404);
});

      

So, in essence, here we return a response for both the master layout and the custom 404 / error view, and then extract data from objects of the form of these responses, concatenating the data into one array, and then returning the response and passing our custom 404 / error, data, and HTTP status code.

NOTE . There seems to be a bug (at least in Laravel 4.2.11) where the response will always return a 200-status HTTP code no matter what you pass to either view () or do (). That being said, you need to manually set the response code using http_response_code (404).

0


source







All Articles