on Tutorials

Laravel 4 tutorial – simple website with backend – Part 2

60 comments
Getting started with Laravel
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

One month ago, we started this Laravel 4 tutorial series with the first part in which the basics were explained. This time we’re continuing on that, so go ahead and read the first part if you didn’t already.

There is a part 3 of the series available on Laravel 4 – Validation and frontend

As said earlier, this tutorial is not for beginners, so some knowledge is expected from the friendly reader/developer. All source files are available on GitHub.

Laravel 4 tutorial – Layouts and views

The first thing we need is a simple layout for our backend so we need to create the following file:

app/views/admin/_layouts/defaut.blade.php

<!doctype html>
<html lang="en">
<head>
        <meta charset="utf-8">
        <title>L4 Site</title>

        @include('admin._partials.assets')
</head>
<body>
<div class="container">
        <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="navbar-inner">
                <div class="container">
                        <a class="brand" href="{{ URL::route('admin.pages.index') }}">L4 Site</a>

                        @include('admin._partials.navigation')
                </div>
        </div>
</div>

<hr>

        @yield('main')
</div>
</body>
</html>

This will be our main layout that will load our views through the yield() function.

Laravel 4 Authentication

Every backend should have some kind of authentication and this Laravel 4 tutorial will help you build one.

Laravel support basic HTTP authentication, which is great for quick protection, but we’ll create our own login page.

We’re leveraging the great Sentry package, which I mentioned in the first part of the tutorial. So if you haven’t installed it, do so now. Just add it to your composer.json file and run composer update.

We need to create our authentication controller. I prefer to do this with a controller, while another way to go would be to create the auth routes with closures. It’s just a matter of preference.
We have our layout defined but we also need a view for the login form:

app/views/admin/auth/login.blade.php

@extends('admin._layouts.default')

@section('main')

        <div id="login" class="login">
                {{ Form::open() }}

                        @if ($errors->has('login'))
                                <div class="alert alert-error">{{ $errors->first('login', ':message') }}</div>
                        @endif

                        <div class="control-group">
                                {{ Form::label('email', 'Email') }}
                                <div class="controls">
                                        {{ Form::text('email') }}
                                </div>
                        </div>

                        <div class="control-group">
                                {{ Form::label('password', 'Password') }}
                                <div class="controls">
                                        {{ Form::password('password') }}
                                </div>
                        </div>

                        <div class="form-actions">
                                {{ Form::submit('Login', array('class' => 'btn btn-inverse btn-login')) }}
                        </div>

                {{ Form::close() }}
        </div>

@stop

And the controller:

app/controllers/admin/AuthController.php

<?php namespace App\Controllers\Admin;

use Auth, BaseController, Form, Input, Redirect, Sentry, View;

class AuthController extends BaseController {

        /**
         * Display the login page
         * @return View
         */
        public function getLogin()
        {
                return View::make('admin.auth.login');
        }

        /**
         * Login action
         * @return Redirect
         */
        public function postLogin()
        {
                $credentials = array(
                        'email' => Input::get('email'),
                        'password' => Input::get('password')
                );

                try
                {
                        $user = Sentry::authenticate($credentials, false);

                        if ($user)
                        {
                                return Redirect::route('admin.pages.index');
                        }
                }
                catch(\Exception $e)
                {
                        return Redirect::route('admin.login')->withErrors(array('login' => $e->getMessage()));
                }
        }

        /**
         * Logout action
         * @return Redirect
         */
        public function getLogout()
        {
                Sentry::logout();

                return Redirect::route('admin.login');
        }

}

Ok, now we have a default layout, an authentication controller and a login view. The only thing missing is a route that will connect those 3. I like to create these routes like this:

app/routes.php

Route::get('admin/logout', array('as' => 'admin.logout', 'uses' => 'App\Controllers\Admin\AuthController@getLogout'));
Route::get('admin/login', array('as' => 'admin.login', 'uses' => 'App\Controllers\Admin\AuthController@getLogin'));
Route::post('admin/login', array('as' => 'admin.login.post', 'uses' => 'App\Controllers\Admin\AuthController@postLogin'));

You might have noticed in our auth controller that upon a successful login we redirect the user to the route admin.pages.index. This route doesn’t exist so we’ll create it also, and we also add the entire group of routes for our admin controllers that we still need to create:

app/routes.php

Route::group(array('prefix' => 'admin', 'before' => 'auth.admin'), function()
{
        Route::any('/', 'App\Controllers\Admin\PagesController@index');
        Route::resource('articles', 'App\Controllers\Admin\ArticlesController');
        Route::resource('pages', 'App\Controllers\Admin\PagesController');
});

You can always check out your defined routes with the command php artisan routes.

So these routes need to be protected by our authentication logic. This is done via the ‘before’ filter which is set to auth.admin. This filter needs to be defined in our app/filters.php file.

You already have some filters predefined, but we need to create our own since we’re using the Sentry package. It’s actually really simple, just a few lines of code:

app/filters.php

Route::filter('auth.admin', function()
{
        if ( ! Sentry::check())
        {
                return Redirect::route('admin.login');
        }
});

Now just fire up your server. I like to use the PHP built in server and I just run php artisan serve and the site can be accessed through http://localhost:8000.

What we’re interested in right now is the login page which you can access through http://localhost:8000/admin/login. If you did everything correctly you should see your login view inside the default layout.

It should be styled by Twitter Bootstrap. Just try entering some dummy login data, and you should also see that we have error messages displayed. For now the message is simply the exception message that Sentry throws.

We created a database seed for an admin user in the last part, so we can login with the email admin@admin.com, and the password admin. Try that and you should be redirected to the route admin.pages.index. The route exists but we still need to create the controller and views.

Good job. Have a cup of tea or something, then come back.

Creating our controllers

In Laravel 4 you can route the requests in many different ways. I personally like to use controllers, and perhaps sometimes closures for simple actions.

For our backend panel we need a couple of controllers for now:

app/controllers/admin/ArticlesController.php

As you may remember from earlier, we used resourceful routes for the controllers. This means that Laravel 4 has created routes for all the CRUD actions for our resources. You can read more on this in the docs: http://four.laravel.com/docs/controllers#resource-controllers

This basically means you now have predefined routes that are mapped to specific methods in your controller. Eg. the “Pages” resource is mapped to the controller class “App\Controllers\Admin\PagesController”.

Laravel 4 makes use of the HTTP methods for each of the CRUD action. So for example a GET request to /pages will list all pages by calling the index() method in the PagesController class. For more details just check the docs, but for now let me show you the PagesController:

app/controllers/admin/PagesController.php

<?php namespace App\Controllers\Admin;

use App\Models\Page;
use Input, Redirect, Sentry, Str;

class PagesController extends \BaseController {

        public function index()
        {
                return \View::make('admin.pages.index')->with('pages', Page::all());
        }

        public function show($id)
        {
                return \View::make('admin.pages.show')->with('page', Page::find($id));
        }

        public function create()
        {
                return \View::make('admin.pages.create');
        }

        public function store()
        {
                $page = new Page;
                $page->title = Input::get('title');
                $page->slug = Str::slug(Input::get('title'));
                $page->body = Input::get('body');
                $page->user_id = Sentry::getUser()->id;
                $page->save();

                return Redirect::route('admin.pages.edit', $page->id);
        }

        public function edit($id)
        {
                return \View::make('admin.pages.edit')->with('page', Page::find($id));
        }

        public function update($id)
        {
                $page = Page::find($id);
                $page->title = Input::get('title');
                $page->slug = Str::slug(Input::get('title'));
                $page->body = Input::get('body');
                $page->user_id = Sentry::getUser()->id;
                $page->save();

                return Redirect::route('admin.pages.edit', $page->id);
        }

        public function destroy($id)
        {
                $page = Page::find($id);
                $page->delete();

                return Redirect::route('admin.pages.index');
        }

}

As you can see I already mapped some of the methods to views, and I’m also passing data to the views through the Page model using Eloquent methods. All of this is pretty simple, but this is fine for now.
Our index() method should list the pages from our database. The view looks something like this:

app/views/admin/pages/index.blade.php

@extends('admin._layouts.default')

@section('main')

        <table class="table table-striped">
                <thead>
                        <tr>
                                <th>#</th>
                                <th>Title</th>
                                <th>When</th>
                                <th><i class="icon-cog"></i></th>
                        </tr>
                </thead>
                <tbody>
                        @foreach ($pages as $page)
                                <tr>
                                        <td>{{ $page->id }}</td>
                                        <td><a href="{{ URL::route('admin.pages.show', $page->id) }}">{{ $page->title }}</a></td>
                                        <td>{{ $page->created_at }}</td>
                                        <td>
                                                <a href="{{ URL::route('admin.pages.edit', $page->id) }}" class="btn btn-success btn-mini pull-left">Edit</a>

                                                {{ Form::open(array('route' => array('admin.pages.destroy', $page->id), 'method' => 'delete')) }}
                                                        <button type="submit" href="{{ URL::route('admin.pages.destroy', $page->id) }}" class="btn btn-danger btn-mini">Delete</button>
                                                {{ Form::close() }}
                                        </td>
                                </tr>
                        @endforeach
                </tbody>
        </table>

@stop

You may notice that the delete button is inside a form. The reason for this is that the destroy() method from our controller needs a DELETE request, and this can be done in this way. If the button was a simple link, the request would be sent via the GET method, and we wouldn’t call the destroy() method.

We’re also missing the actual actions that would manipulate our data in the database. We’ll do this first without validation, and later on we’ll setup some validation rules in our models. So for now our store() method should create a new page, and this looks something like this:

app/controllers/admin/PagesController.php

public function store()
        {
                $page = new Page;
                $page->title = Input::get('title');
                $page->slug = Str::slug(Input::get('title'));
                $page->body = Input::get('body');
                $page->user_id = Sentry::getUser()->id;
                $page->save();

                return Redirect::route('admin.pages.edit', $page->id);
        }

But before this method works we also need a view to display the form for creating new pages. This view we’ll be shown when the method create() is called:

app/views/admin/pages/create.blade.php

@extends('admin._layouts.default')

@section('main')

        <h2>Create new page</h2>

        {{ Form::open(array('route' => 'admin.pages.store')) }}

                <div class="control-group">
                        {{ Form::label('title', 'Title') }}
                        <div class="controls">
                                {{ Form::text('title') }}
                        </div>
                </div>

                <div class="control-group">
                        {{ Form::label('body', 'Content') }}
                        <div class="controls">
                                {{ Form::textarea('body') }}
                        </div>
                </div>

                <div class="form-actions">
                        {{ Form::submit('Save', array('class' => 'btn btn-success btn-save btn-large')) }}
                        <a href="{{ URL::route('admin.pages.index') }}" class="btn btn-large">Cancel</a>
                </div>

        {{ Form::close() }}

@stop

The form will submit to the route admin.pages.store, and we don’t need to define a HTTP method, since POST is the default method, and POST is linked to the store() method mentioned above.

After the page is stored there’s a redirect to the screen where we can edit the entry. The method is defined but we’re still missing the view which is pretty similar to the create() view:

app/views/admin/pages/edit.blade.php

@extends('admin._layouts.default')

@section('main')

        <h2>Edit page</h2>

        {{ Form::model($page, array('method' => 'put', 'route' => array('admin.pages.update', $page->id))) }}

                <div class="control-group">
                        {{ Form::label('title', 'Title') }}
                        <div class="controls">
                                {{ Form::text('title') }}
                        </div>
                </div>

                <div class="control-group">
                        {{ Form::label('body', 'Content') }}
                        <div class="controls">
                                {{ Form::textarea('body') }}
                        </div>
                </div>

                <div class="form-actions">
                        {{ Form::submit('Save', array('class' => 'btn btn-success btn-save btn-large')) }}
                        <a href="{{ URL::route('admin.pages.index') }}" class="btn btn-large">Cancel</a>
                </div>

        {{ Form::close() }}

@stop

In this view we’re leveraging the Form::model() method, which simply fills the input fields inside the form with data from the Page model that is passed to the view by the controller. It also handles submitted data if the validation fails, but for now there’s no validation so more on this subject later.

The method that stores the changes to the page is update(). This method is called when the controller receives a PUT request, and this is also handled via the Form::model() helper. The actual method is almost the same as the create method:

app/controllers/admin/PagesController.php

public function update($id)
        {
                $validation = new PageValidator;

                if ($validation->passes())
                {
                        $page = Page::find($id);
                        $page->title = Input::get('title');
                        $page->slug = Str::slug(Input::get('title'));
                        $page->body = Input::get('body');
                        $page->user_id = Sentry::getUser()->id;
                        $page->save();

                        Notification::success('The page was saved.');

                        return Redirect::route('admin.pages.edit', $page->id);
                }

                return Redirect::back()->withInput()->withErrors($validation->errors);
        }

The last method needed is the destroy method:

app/controllers/admin/PagesController.php

public function update($id)
        {
                $page = Page::find($id);
                $page->title = Input::get('title');
                $page->slug = Str::slug(Input::get('title'));
                $page->body = Input::get('body');
                $page->user_id = Sentry::getUser()->id;
                $page->save();

                return Redirect::route('admin.pages.edit', $page->id);
        }

There’s also the show() method which could be useful for previewing the content:

public function show($id)
        {
                return \View::make('admin.pages.show')->with('page', Page::find($id));
        }

We also have another resource for our articles, but at this point we’ll just copy almost everything to this resource.

I know this might seem like bad practice, but eventually we’ll expand each resource. Eg. the pages resource well be able to have parent pages, and the articles will be categorised.

Custom commands

You may remember our app:refresh command from part 1. Well, now we can play with our pages and articles as much as we want, and if we want to go back to the starting point, simply run the command. This is extremely useful if for any reason the data in the DB becomes corrupted during development. Awesome…

Notifications and modals

When we perform those CRUD actions on our data, we don’t have any feedback when something happens, and I find this bad. You should always display some feedback, so we’re going to implement a simple notification system.

We could write a simple system ourselves, but it would be too much for this tutorial, so we’re use the force of Laravel 4 community again. I’m going to use this notification package: https://github.com/edvinaskrucas/notification

To install the package just add it to your composer.json file:

"edvinaskrucas/notification": "1.*"

Run composer update, and add the service provider and facade to your app configuration:

'Krucas\Notification\NotificationServiceProvider'

and

'Notification' => 'Krucas\Notification\Facades\Notification'

So basically every time we perform an action and redirect back, we need to add a notification. To keep thing simple for now we’re only gonna show success messages, since we don’t even have any validation in place …
Also keep in mind that if you want to use the Notification class, you need to either reference it with a backslash, or the way I do it add a use statement on the top:

...
use Notification;
...

So eg. in out update() method in the pages controller, before redirecting, we add the notification, and our method should look like this:

app/controllers/admin/PagesController.php

public function update($id)
        {
                $validation = new PageValidator;

                if ($validation->passes())
                {
                        $page = Page::find($id);
                        $page->title = Input::get('title');
                        $page->slug = Str::slug(Input::get('title'));
                        $page->body = Input::get('body');
                        $page->user_id = Sentry::getUser()->id;
                        $page->save();

                        Notification::success('The page was saved.');

                        return Redirect::route('admin.pages.edit', $page->id);
                }

                return Redirect::back()->withInput()->withErrors($validation->errors);
        }

To display the notification, we need to place the code inside our view. Since we redirect to the edit view after saving the page, I’ll just put the code right beneath the h2 tag:

app/views/admin/pages/edit.blade.php

{{ Notification::showAll() }}

@if ($errors->any())
        <div class="alert alert-error">
                {{ implode('<br>', $errors->all()) }}
        </div>
@endif

And this is all you need. Just add notification in all the places you want. You can check out my code at the repo: https://github.com/bstrahija/l4-site-tutorial

Another thing I like to add to my apps is confirmation when deleting resources. So to demonstrate this we’ll add a simple JavaScript confirmation dialog on our delete buttons in the index view.

So we had a form wrapped around the button because of the required HTTP delete method. One way to do this is to intercept the submit action of the form, and the way I like to do this is by adding a HTML5 data parameter to the form:

app/views/admin/pages/index.blade.php

{{ Form::open(array('route' => array('admin.pages.destroy', $page->id), 'method' => 'delete', 'data-confirm' => 'Are you sure?')) }}
      <button type="submit" href="{{ URL::route('admin.pages.destroy', $page->id) }}" class="btn btn-danger btn-mini">Delete</button>
{{ Form::close() }}

As you can see the parameter data-confirm holds the message that we’ll show to the user. To actually display the message we need a simple JQuery script. So we’ll create the following file and include it in our main layout:

public/assets/js/script.js

$(function() {

        // Confirm deleting resources
        $("form[data-confirm]").submit(function() {
                if ( ! confirm($(this).attr("data-confirm"))) {
                        return false;
                }
        });

});

So this script find all form tags with a data-confirm attribute, takes the value from the attribute and display a confirmation dialog. If the user clicks Ok, the form is submitted.

What’s next?

This concludes the second part of Laravel 4 tutorial where we covered authentication and some basic CRUD actions, so by now you should have a foundation for your web app.

In the next part we’ll get busy with some validation, and we’ll also jump into the front end part of the web, and routing requests to our pages and articles.

There is a part 3 of the series available on Laravel 4 – Validation and frontend

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon



  • Kyle

    Great article, really enjoying the series so far. Any chance you are going to cover testing?

    • http://creolab.hr/ Boris Strahija

      Thanks. I’m not planning to cover testing since I still need to get on the whole TDD bandwagon, and also Jeffrey Way covered testing extensively over on nettuts. It’s hard to beat his tutorials ;)

  • John

    Hi, i make everything as you wrote, but I get
    Class App\Controllers\Admin\AuthController does not exist

    • http://creolab.hr/ Boris Strahija

      Do you have this controller in your “app/controllers/admin” directory?
      Is is properly namespaced?
      Did you run “composer dump-autoload” or even “artisan dump-autoload”?

      • AfzalivE

        That was a really important thing you missed in the tutorial. I actually added the admin folder to global.php until I discovered this composer auto-load thing.

        Please add it to the tutorial for future readers.

        • http://creolab.hr/ Boris Strahija

          I’m not really sure what you mean? It’s stated in the beginning of the tutorial that it isn’t for beginners, it is expected to know some things about composer, namespaces and how composer handles autoloading. If you have a specific question, I would be happy to answer it.

          • Chris

            Just wanted to say thank you Boris, for a good tut series and for sticking with the “this is not for beginners” thing. Too many tuts spend too much time trying to cover all the simple things, that rarely do we get to much mid and high level stuff. Keep it up.

          • Wojtek

            Hello!
            I’m Having the same issue with Class App\controllers\Admin\AuthController does not exist
            I tried to do :
            composer dump-autoload
            and
            artisan dump-autoload

            I checked all folders and everything should work ,but it’s not working. Can somebody help me ?

  • Joe

    Hi, thanks a lot for your tutorial Boris, it really help me to understand the framework along the documentation however, following all your steps till you mention to fire up the php server, I find the following L4 error when I navigate to https://localhost:8000/admin/login :

    Argument 1 passed to Illuminate\Html\FormBuilder::open() must be of the type array, string given, called in /srv/l4/bootstrap/compiled.php on line 6986 and defined

    Is there any configuration to avoid this error?

    • http://creolab.hr/ Boris Strahija

      Good catch, my mistake ;) You can actually setup the form like this:

      {{ Form::open() }}

      Since it submits to the same URL anyway.
      Or you can define it like:

      {{ Form::open(array('route' => 'admin.login')) }}

      I updated it now in the tutorial, and if you need more detailed info, just go here: http://four.laravel.com/docs/html#opening-a-form

  • gwilliker

    Hey Boris,

    This was another great post and was helpful to me. I had to stumble through another couple things so I’m going to post them here, just in case any one else experiences the same things.

    When it came to putting in the notifications I got this error:
    Class 'App\Controllers\Admin\Notification' not found

    To fix this, go to app/controllers/admin/PagesController.php and change

    use Input, Redirect, Sentry, Str;
    to
    use Input, Redirect, Sentry, Str, Notification;

    I also had an issue with the javascript not running as expected. I created the file as instructed and put the following line in default.blade.php (using the same structure as the css added there):

    <script src="{{ URL::asset('assets/js/script.js') }}">

    The js wasn’t running and by looking at the html source I realized that script.js wasn’t being included. To fix it I had to change the location of script.js to:

    public/assets/js/script.js

    I still had a problem after that, but that came down to my own stupidity. I had the script tag for script.js above the line that included the jquery, and that just didn’t work. Once I reordered those script tags everything finally worked as expected.

    Thanks again Boris! I look forwarded towards checking out part 3. :)

    • http://creolab.hr/ Boris Strahija

      I see the problem with the wrong path for the JS file, i fixed that.

      The notification part is just there to keep you on your toes ;) Just kidding :)
      I may need to add some remarks that everytime you want to use one of the facades defined in app/config/app.php you need to either call them with a backslash in front, or add the “use” statement on the top. Also run “artisan dump-autoload” when creating new classes.

  • Duramba

    Thank you. Looking forward to part 3 :)

  • Jan D.

    Thanks. Coming from Laravel 3 (and with limited PHP knowledge) I find L4 to be a bit confusing. The documentation is ok but it’s fragmented and not very useful for beginners. Your tutorial helped me.
    I had started building my own package and couldn’t figure out why View::make didn’t work until I saw here that it needs to be prefixed with ‘\’

    • http://creolab.hr/ Boris Strahija

      Well this is more of a namespace issue. Perhaps it would be good to first look into how namespace work in PHP. There’s a great explanation by Dayle Rees at: http://daylerees.com/php-namespaces-explained

  • Marcel de Cock

    I don’t think you need Auth, BaseController, Form in AuthController.
    Also, some redundancy in the controllers.
    Also, if you use Use View, you don’t need \View but can just call via View::make(….);

    • http://creolab.hr/ Boris Strahija

      Good catch, I guess those lines remained there from while I was testing things out. But I do like to have a base controller of some kind for my projects. In this simple tutorial it’s probably not needed for now, but maybe I’ll think of a good use for it later on.

  • austin

    Just want to thanks to you.Your articles are very helpful.

  • Rob

    Thanks for the Tutorials! I am trying to really learn how to create a nice backend and there aren’t very many tutorials for L4 yet so this has helped some. Quick question though. I am trying to redirect to a dashboard after login instead of pages, much like a wordpress dashboard. What would be the best way to do that? would I create another controller called dashboard, and then add the respective, model and view? And then next change the re rout from pages to dashboard in the authcontroller?

    • http://creolab.hr/ Boris Strahija

      Well you could create a new controller “App\Controllers\Admin\DashboardController”, and the admin route to it like this:

      Route::any('/', array('as' => 'admin.dashboard', 'uses' => 'App\Controllers\Admin\DashboardController@getIndex'));
      Route::controller('dashboard', 'App\Controllers\Admin\DashboardController');

      And if you want to change the redirect after the login action, you need to update your AuthController. Change the postLogin() method:

      return Redirect::route('admin.dashboard');

      I hope this helps.

      • Rob

        Thanks for the quick reply. Yea I had my routs wrong. I appreciate the help. I added the DashboardController like you said and put the new routs in to the routs.php file. In my DashboardController.php I have

        <?php namespace App\Controllers\Admin;

        class DashboardController extends \BaseController {

        public function getIndex()
        {
        return View::make('admin.dashboard');
        } }

        and I have dashboard.blade.php in views/admin

        and now when I login it is giving me an error

        Class 'App\Controllers\Admin\View' not found and showing me the DashboardController code above

        Any Idea what I'm doing wrong? I had to run composer dump-autoload for it to recognise the DashboardController, do I need to do anything else to make it recognize the view?

        • http://creolab.hr/ Boris Strahija

          Well like some people before, you need to find some articles (http://daylerees.com/php-namespaces-explained) on PHP namespaces. I noted the tutorial isn’t for beginners ;)

          Since your class is in the namespace “App\Controllers\Admin”, you can’t reference the View class like it’s in the same namespace. Think of it in a similar way as including files in PHP. If you in the directory “app/controllers/admin” you can’t simply include a view.php file that is in the applications root. All the Laravel facades are in the root namespace, so if you want to use them in a different namespace (App\Controllers\Admin) you need to either reference them from the root with a backslash (\View::make()), or you need to specify before the class definition that you’re gonna use the facade in the root namespace (use View;).

          I hope this makes sense ;)

          • Rob

            Aaaaahhh I can’t thank you enough. I actually did read that namespace tutorial in his e-book code bright. But it did not sink in until you mentioned it like calling to a path. Then his whole global namespace reference sunk in. Got it. I really appreciate the tutorial and the help. That just sent me over the plateau. Thanks again! Can’t wait for more tutorials.

  • http://www.webmasterdubai.com umefarooq

    here is general admin routing to access you all admin controllers http://paste.laravel.com/uLt

    • http://creolab.hr/ Boris Strahija

      That’s ok but I like to have a better control and overview of my routes. You asume all admin routes are resources, which most of the time they are not.
      Also try running “artisan routes” in the console. Nothing will be displayed ;)

      • http://www.webmasterdubai.com umefarooq

        artisan routes you will not able to see routes at all

        • http://creolab.hr/ Boris Strahija

          Exactly, that was my point. It’s not a good thing ;)

  • Rizky Hajar

    Why, in AuthController postLogin.

    Can’t use UserNotFoundException, WrongPasswordException & other Sentry Exception

    • http://creolab.hr/ Boris Strahija

      You can catch those exceptions if you want and handle them differently. I wanted to keep it simple.

  • Junior

    I’m having problems with namespaces, in Models I can’t user namespace ‘App\Models;’ and using app/controllers/admin/authcontroller.php he isn’t found.
    Error message: “Class App\Controllers\Admin\AuthController does not exist”.
    I had made exactly how you have write.
    What I can do?

    • Robin Kuiper

      I have the same, anyone knows the problem?

    • natpoong

      try $php artisan dump-autoload

  • Bob

    “NotFoundHttpException”
    I love how it doesn’t give any information whatsoever about the error.

    I even tried downloading the files from Github, replaced them with my own and then running “composer dump-autoload”, still, same stupid error.

  • Bob

    Hi! Please disregard my previous little rant.
    It turns out my Vhosts were completely screwed up, haven’t used Apache in a while (nice excuse…)

    I realized it was my Vhost when I tried accessing another non-laravel site only to see the same laravel error screen….

    • Lukas

      Hello i have the same error, how did you solve this ?
      Im using ‘php artisan server’ command
      if i open in browser localhost:8000/admin it throw
      “NotFoundHttpException” and localhost:8000/admin/login throw “Unable to generate a URL for the named route “admin.pages.index” as such route does not exist. “

      • Lukas

        yes because i forget to save my route file, what a newb am i :-)

  • http://Ikiji.com Georgi

    Hey there! I am a newbie to Laravel, however I found a small “bug”:

    Just before the section “Creating our controllers”, you are saying to try out the login, unfortunately – it throws an error that the route to admin.pages.index does not exist. What I’ve done is modify your routes.php by this:

    http://paste.laravel.com/FVe

    And I was able to see the login screen. Hope this helps some new developers. =))

    • Will Shaw

      I am getting the same issue but it seems that your link is no longer valid. What is it that you have done?

  • Peter

    “View [admin.auth.login] not found”
    any ideas?

    great tut btw :)

    • Fernando

      Try put folders _layouts, auth and pages in views/admin.
      Here works!

  • Vitor Martinelli Braga

    Hello good your tutorial, but I am facing the following difficulty: The Laravel 4.1 hasn’t compatibility library Notification. You know how to solve this?

  • ChozeRizes

    This is great tutorial! Thanks to you, Boris. Cheers!

  • Grigoryj

    Thanks Boris!! You’ve helped me a lot! :)

  • Dang Ngoc Long

    URL::route(‘admin.pages.show’, $page->id is not work on version 4.1
    should be URL::route(‘admin.pages.show’, array($page->id)

  • missprogrammer

    thanks, but
    why when i try to login, it says: “Method [authenicate] is not supported by Sentry or no User has been set on Sentry to access shortcut method.”

    • missprogrammer

      oh i had a mistake in typing authenticate:D

  • missprogrammer

    why app:refresh not working?
    i added your files from https://github.com/bstrahija/l4-site-tutorial/tree/master/app/commands but not working
    and said “There are no commands defined in the app namespace”
    please help me

  • http://battleprogrammer.wordpress.com Moch Lutfi

    Hi, there is typo in app/views/admin/_layouts/defaut.blade.php, I think it should be app/views/admin/_layouts/default.blade.php.
    Thanks

  • http://www.quillstudios.com.au andocobo

    I noticed a typo in the html for the delete button, it says ‘butfon’ instead of ‘button’, I think it prevents the confirm method from firing. If it still won’t fire remember you’ll need to add the js script asset to your default.blade.php file

    • http://creolab.hr/ Boris Strahija

      Good catch, updated

  • Eric

    Hi Boris,

    Thanks for the tutorial. Excellent. Much appreciated.

    can’g figure out why I’m getting this error

    Class ‘App\Services\Validators\ArticleValidator’ not found

    I’ve tried several things, can you point me in the right direction?

  • Eric

    Hello again,
    I was able to solve my above problem. My composer.json file was wrong and I was missing some files that I got from GitHub. Thanks again for the awesome tutorial.

  • Tomasz Dudzik

    Thaanks a million for this tutorial! It’s great ! :)

  • Teodor Sandu

    I don’t understand why Sentry doesn’t provide a “nickname” field into his schema, using instead the “email” field as unique. It is obsolete nowadays logging in with nickname+password? Would be good idea to add the “nickname” field into …_migration_cartalyst_sentry_install_users.php file? Thank you for your great tutorials

  • Tralalaravel

    Awesome tutorial, Boris! Thank you!!

    In case this might aid you and others who might follow after me, I think I encountered two typos, each easily surmounted.

    (1) On this web page (“tutorial part 2″), right after it says “The last method needed is the destroy method:”, it looks to me like the sample code excerpt that follows, for the file “app/controllers/admin/PagesController.php”, is a repeat of the “update” method instead of the intended “destroy” method. I copied the destroy method instead from your github repository at github.com/bstrahija/l4-site-tutorial/blob/master/app/controllers/admin/PagesController.php

    (2) In your github repository, on line 9 of the file “app/views/admin/pages/show.blade.php”, there appears to be an extraneous “@” character right after the opening “” tag.

    Thank you again! I hope these tiny suggestions will be of some assistance.

  • Kevin

    Can anyone help me? I’m stuck with this error “View [admin._partials.assets] not found.” Thanks!

  • Otemuyiwa Prosper

    Giving me an error in my View saying “Class Notification not found”…pls how do i go about it?

  • Khadri Ryan

    Please can someone tell me or teach me how to create a static page,am new to php

  • Sangam Uprety

    Just got the issue:
    Call to undefined method IlluminateCookieCookieJar::get()

    Fixed it by upgrading to Sentry 2.1.*. Thanks a lot.