Amitav Roy

Blog on web and travel

Working with workbench and building packages in Laravel 4

Posted on July 2019

Laravel

I come from the world of Drupal where every code that we write is part of a module. This is very useful because over time I am able to develop modules which I can re-use in all of my projects. Codeigniter has this feature using HMVC which I showed in the tutorialHMVS architecture with Codeigniter. The same approach can be followed in Laravel 4 using workbench to create packages. This way we can make an independent piece of code (or some dependent on other modules) and once we plug it in, the module is ready to do what it is supposed to do. In this tutorial I will start with a blog module which will be independent; it will have its own migrations, controllers, models, views and its own routes.

Setting up workbench file and create the package

To create a package using workbench, first, we need to configure the workbench.php file inside the app/config folder. Nothing much, we just need to add a name and email address which will be used to identify the owner of the package created inside the composer.json file. In my case, I used my email address used for my Github account. Once this setting is done, we are good to create a new package.

File on github

The command to create a new package which you can find in Laravel 4 docs is

php artisan workbench vendor/package --resources

What it exactly does is, first it will create a workbench folder (if it doesn’t exist which I assume is your case as well). Then inside the workbench folder, it will create a folder which is same as what you mentioned for vendor and inside that a package folder whose name will be same as what we put instead of package. And about the resources – well it creates predefined files and folders which are very much required. So, like for this tutorial, I ran the command:

php artisan workbench amitavroy/blogger --resources

So, inside my workbench folder there is a folder called amitavroy and inside this folder is another folder blogger which contains all the code for the package.

Register the package and the Service Provider

Once we create a package, we need to tell Laravel 4 to load that package during bootstrap. This can be done by adding one line of code inside the app.php files providers array. When a package is created, a Service provider php file is created inside the src/vendor/package folder. And so in my case that one line of code inside the providers array was‘Amitavroy\Blogger\BloggerServiceProvider’.

File on github

Once this is done, we are ready to create our migration for the blog post table. When we create a normal migration, we can run a command something like

php artisan migrate:make create_blog_post_table

But now that we want to create a migration for a package, if we see the Laravel 4 docs, we would realize that the command is almost the same. The only thing which we need to do is add –bench=”vendor/package”. So something like

php artisan migrate:make create_blog_post_table --bench="amitavroy/blogger"

which create the migration inside workbench/amitavroy/blogger/src/migrations folder. And then we can even run the migration using the command

php artisan migrate --bench="vendor/package"

So, I created a migration which creates a blog post table with some basic columns and also inserted a dummy post.

Registering routes

Now that we have the migrations, we would want to create a page where we would want to list the blog post. And if we are working on a blog module then it makes sense to have routes inside the module itself. So, to register a route inside a package, we create a routes.php file inside the src folder of the package and then we edit the Service provider file a bit to include the routes.php file.

Inside the service provider file’s boot function I had $this->package(‘amitavroy/blogger’); and below this I just added include DIR . ‘/../../routes.php’; and that will make sure all the routes we define inside the file are registered by Laravel 4.

File on github

Once this is done, we are ready to write our own routes inside this file. But for the controllers and models to get registered / auto load, we need to add those folders inside composer.json of the package. By default in the composer.json file only the migrations folder is included, so we will add our folders here. We can even make a helper folder and create class files inside that folder and later on refer them. So here is my composer.json file.

So once we add the lines to include our models and controllers, we should do a dump-autoload (especially do it once by going inside the package directory i.e. amitavroy/blogger folder). Once this is done, we are good to go.

For this tutorial, I have one route which is to list the blog list (currently two posts) and one to show the full view. The route inside my package will use a controller, model and view from inside the package and do the listing.

Time to code now

The following code will help you understand how things are done

The route

Route::get('blog/list', 'BloggerController@handleBlogListingPage');
Route::get('blog/view/{id}', 'BloggerController@handleBlogSinglePage');

There are two routes, one for listing the blog posts and one for the full view. Here I am referring to the BloggerController from the package.

The controller

class BloggerController extends BaseController
{
  protected $layout = 'master';
    
  public function handleBlogListingPage()
  {
    // get the blog posts by loading the model
    $Blog = new Blog;
    $blogPosts = $Blog->getBlogPost()->get();
      
    // setting the view with content
    $this->layout->content = View::make('blogger::blog-list')->with('blogposts', $blogPosts);
  }
    
  public function handleBlogSinglePage($blogId)
  {
    // get the blog posts by loading the model
    $Blog = new Blog;
    $blogPost = $Blog->getBlogPost($blogId)->first();
      
    // setting the view with content
    $this->layout->content = View::make('blogger::blog-fullview')->with('blogpost', $blogPost);
  }
}

Inside the controller I have two functions to handle the two pages. The first one is calling the model Blog which is again inside the package’s model folder and getting the blog posts. The model always returns the query object hence I have the liberty to change the data I am getting in the controller.

The model

class Blog extends Eloquent
{
  public function getBlogPost($blog_id = NULL, $take = NULL, $skip = NULL)
  {
    $query = DB::table('blog_post');
    $query->where('status', 1);
    $query->orderBy('updated_at', 'desc');
      
    if ($take != NULL)
      $query->take($take);
      
    if ($skip != NULL)
      $query->skip($skip);
      
    return $query;
  }
}

The model has only one function which is to return the query object.

TIP: If you see in the listing function I used get() function and for the full view I used first(). And also this also helps us to call the pagination function on a function if we require it. Hence it’s a good ideal for the model to always return query object. We can even extend the query in another model function.

The view

  1. blog-list.blade.php
  2. blog-teaser.blade.php
  3. blog-fullview.blade.php

Also if you check the view, you will see that I have three views. One is blog-list view which is like the main view for the listing page. This view calls the blog-teaser view and passes each blog object. Then it’s the responsibility of the teaser view to control the markup of each blog teaser. Any layout level changes can be handled in the listing view and any change in the teaser view will have its own view to handle.

Final code on github