Build Your First Admin Bundle for Laravel

It's hard to deny the fact that the PHP community is excited for Laravel 4. Among other things, the framework leverages the power of Composer, which means it's able to utilize any package or script from Packagist.

In the meantime, Laravel offers "Bundles", which allow us to modularize code for use in future projects. The bundle directory is full of excellent scripts and packages that you can use in your applications. In this lesson, I'll show you how to build one from scratch!

Wait, What's a Bundle?

Bundles offer an easy way to group related code. If you're familiar with CodeIgniter, bundles are quite similar to "Sparks". This is apparent when you take a look at the folder structure.

Folder Structure

Creating a bundle is fairly simple. To illustrate the process, we'll build an admin panel boilerplate that we can use within future projects. Firstly, we need to create an 'admin' directory within our 'bundles' folder. Try to replicate the folder structure from the image above.

Before we begin adding anything to our bundle, we need to first register it with Laravel. This is done in your application's bundles.php file. Once you open this file, you should see an array being returned; we simply need to add our bundle and define a handle. This will become the URI in which we access our admin panel.

Here, I've named mine, "admin," but feel free to call yours whatever you wish.

Once we've got that setup, we need to create a start.php file. Here, we're going to set up a few things, such as our namespaces. If you're not bothered by this, then you don't actually need a start file for your bundle to work, as expected.

Laravel's autoloader class allows us to do a couple of things: map our base controller, and autoload namespaces.

Namespacing will ensure that we don't conflict with any other models or libraries already included in our application. You'll notice that we haven't opted to not namespace our controllers to make things a little easier.

Publishing Assets

For the admin panel, we'll take advantage of Twitter's Bootstrap, so go grab a copy. We can pop this into a public folder inside our bundle in order to publish to our application later on.

When you're ready to publish them, just run the following command through artisan.

This will copy the folder structure and files to the bundles directory in our public folder, within the root of the Laravel installation. We can then use this in our bundle's base controller.

Setting up the Base Controller

It's always a smart idea to setup a base controller, and extend from there. Here, we can setup restful controllers, define the layout, and include any assets. We just need to call this file, base.php, and pop it into our controller's directory.

Firstly, let's get some housekeeping out of the way. We'll of course want to use Laravel's restful controllers.

And we'll specify a layout that we'll create shortly. If you're not used to controller layouts, then you're in for a treat.

The bundle name, followed by two colons, is a paradigm in Laravel we'll be seeing more of in the future, so keep an eye out.

When handling assets within our bundle, we can do things as expected and specify the path from the root of the public folder. Thankfully, Laravel is there to make our lives easier. In our construct, we need to specify the bundle, before adding to our asset containers.

If you're unfamiliar with asset containers, don't worry; they're merely sections of a page where you want to house your assets. Here, we'll be including stylesheets in the header, and scripts in the footer.

Now, with that out of the way, we can include our bootstrap styles and scripts easily. Our completed base controller should look similar to:

We've also brought across the catch-all request from the application's base controller to return a 404 response, should a page not be found.

Before we do anything else, let's make the file for that layout, views/layout/main.blade.php, so we don't encounter any errors later on.

Securing the Bundle

As we're building an admin panel, we're going to want to keep people out. Thankfully, we can use Laravel's built in Auth class to accomplish this with ease..

First, we need to create our table; I'm going to be using 'admins' as my table name, but you can change it, if you wish. Artisan will generate a migration, and pop it into our bundle's migrations directory. Just run the following in the command line.

Building the Schema

If you're unfamiliar with the schema builder, I recommend that you take a glance at the documentation. We're going to include a few columns:

  • id - This will auto-increment and become our primary key
  • name
  • username
  • password
  • email
  • role - We won't be taking advantage of this today, but it will allow you to extend the bundle later on

We'll also include the default timestamps, in order to follow best practices.

Now that we've got our database structure in place, we need to create an associated model for the table. This process is essentially identical to how we might accomplish this in our main application. We create the file and model, based on the singular form of our table name - but we do need to ensure that we namespace correctly.

Above, we've ensured that we're using the namespace that we defined in start.php. Also, so we can reference Eloquent correctly, we create an alias.

Extending Auth

To keep our bundle entirely self contained, we'll need to extend auth. This will allow us to define a table just to login to our admin panel, and not interfere with the main application.

Before we create our custom driver, we'll create a configuration file, where you can choose if you'd like to use the username or email columns from the database table.

If you want to alter the columns that we'll be using, simply adjust the values here.

We next need to create the driver. Let's call it, "AdminAuth," and include it in our libraries folder. Since we're extending Auth, we only need to overwrite a couple of methods to get everything working, as we intended.

Now that we've created the driver, we need to let Laravel know. We can use Auth's extend method to do this in our start.php file.

One final thing that we need to do is configure Auth to use this at runtime. We can do this in our base controller's constructor with the following.

Routes & Controllers

Before we can route to anything, we need to create a controller. Let's create our dashboard controller, which is what we'll see after logging in.

As we'll want this to show up at the root of our bundle (i.e. the handle we defined earlier), we'll need to call this home.php. Laravel uses the 'home' keyword to establish what you want to show up at the root of your application or bundle.

Extend your base controller, and create an index view. For now, simply return 'Hello World' so we can ensure that everything is working okay.

Now that our controller is setup, we can route to it. Create a routes.php within your bundle, if you haven't already. Similar to our main application, each bundle can have its own routes file that works identically.

Here, I've registered the home controller, which Laravel will automatically assign to /. Later , we'll add our login controller to the array.

If you head to /admin (or whatever handle you defined earlier) in your browser, then you should see 'Hello World'.

Building the Login Form

Let's create the login controller, however, rather than extending the base controller, we'll instead extend Laravel's main controller. The reason behind this decision will become apparent shortly.

Because we're not extending, we need to set a couple of things up before beginning - namely restful layouts, the correct auth driver, and our assets.

Let's also create our view. We're going to be using Blade - Laravel's templating engine - to speed things up a bit. Within your bundles views directory, create a 'login' directory and an 'index.blade.php' file within it.

We'll pop in a standard HTML page structure and echo the assets.

Now, let's make sure that the view is being created in the controller. As we're using restful controllers, we can take advantage of the 'get' verb in our method.

Awesome! We're now good to start building our form, which we can create with the Form class.

Login Form

Above, we created a form that will post to itself (exactly what we want), along with various form elements and labels to go with it. The next step is to process the form.

As we're posting the form to itself and using restful controllers, we just need to create the post_index method and use this to process our login. If you've never used Auth before, then go and have a peek at the documentation before moving on.

If the credentials are correct, the user will be redirected to the dashboard. Otherwise, they'll be redirected back with an error that we can check for in the login view. As this is just session data, and not validation errors, we only need to implement a simple check.

We'll also need to log users out; so let's create a get_logout method, and add the following. This will log users out, and then redirect them when visiting /admin/login/logout.

The last thing we should do is add the login controller to our routes file.

Filtering routes

To stop people from bypassing our login screen, we need to filter our routes to determine if they're authorized users. We can create the filter in our routes.php, and attach it to our base controller, to filter before the route is displayed.

At this point, all that's left to do is call this in our base controller's constructor. If we extended our login controller from our base, then we'd have an infinite loop that would eventually time out.

Setting up the Views

Earlier, we created our main.blade.php layout; now, we're going to do something with it. Let's get an HTML page and our assets being brought in.

You'll notice that I've also echoed out a couple of variables: $title and $content. We'll be able to use magic methods from our controller to pass data through to these. I've also popped $content inside the container div that Bootstrap will provide the styling for.

Next, let's create the view for our dashboard. As we'll be nesting this, we only need to put the content we want to put into our container.

Save this as index.blade.php within the views/dashboard directory inside of your bundle.

We now need to set our controller to take advantage of the layout and view files that we just created. Within the get_index method that we created earlier, add the following.

title is a magic method that we can then echo out as a variable in our layout. By using nest, we're able to include a view inside the layout straight from our controller.

Creating a Task

In order to speed things up, Laravel provides us with an easy way to execute code from the command line. These are called "Tasks"; it's a good idea to create one to add a new user to the database easily.

We simply need to ensure that the file takes on the name of our task, and pop it into our bundle's tasks directory. I'm going to call this setup.php, as we'll use it just after installing the bundle.

Laravel will pass through an array of arguments; we can count these to ensure that we're getting exactly what we want. If not, we'll echo out an error. You'll also notice that we're using the Command class to run bundle:publish. This will allow you to run any command line task built into Laravel inside your application or bundle.

The main thing this task does is grab the arguments passed through to it, hash the password, and insert a new admin into the Admins table. To run this, we need to use the following in the command line.

What Now?

In this tutorial, we created an boilerplate admin panel that is quite easy to extend. For example, the roles column that we created could allow you to limit what your clients are able to see.

A bundle can be anything from an admin panel, like we built today, to Markdown parsers - or even the entire Zend Framework (I'm not kidding). Everything that we covered here will set you on your way to writing awesome Laravel bundles, which can be published to Laravel's bundle directory.

Learn more about creating Laravel bundles here on Nettuts+.



Related Articles