Creating a Blog Using Laravel 4 Part 4: Layout and Views

Previous parts of this tutorial:

This will be the last part of the Creating a Blog using Laravel series, In this part, we will cover the layout and views for the Blog Application we are creating. Let’s see what we have already covered:

  • Laravel Setup
  • Laravel Migrations
  • Model creation using Eloquent ORM
  • Database Seeding
  • Controllers
  • Routing

View: The V in MVC

Views in a MVC web framework are used to isolate the presentation logic from the business, and the application logic. In a typical MVC web framework, whenever a request is received, the routing component parses the request and figures out the right controller action to handle the request. The controller action, then fetches the requested data from the model and passes it to the view. And finally, a response is returned containing the HTML markup generated by the view to present the data.

Now, let us consider the following example to elaborate the idea using Laravel:

<?php
//file: app/controllers/IndexController.php

class IndexController extends BaseController {

    public function index()
    {
        return View::make('index',['name'=>'usman']);
    }
}

//file: app/routes.php

Route::get('index','IndexController@index');

//file: app/views/index.blade.php
<html>
<head>
    <title>Index page</title>
</head>
<body>
    <p> my name is {{$name}}</p>
</body>
</html>

In the above code, the file IndexController.php contains a simple controller class with an index action. In routes.php, we have registered a route to this action using Route::get(). Inside index() action, we are simply generating a view based on index.blade.php with a variable name. This variable is then presented inside index.blade.php using a p tag.

The Master Layout

The master layout is used to define a uniform look and feel of a web application, and usually contains the elements that are common to all the views. For example: header, footer and sidebars etc. Laravel has two options for creating the master layouts:

  • Controller layouts
  • Blade Template inheritance

Since, our controllers have already been set up to use controller layouts, covering the second option here is beyond the scope of this article.

Let us see the markup for the master layout (app/views/master.blade.php):

<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    @section('title')
        <title>{{{$title}}}</title>
    @show
    {{ HTML::style('assets/css/foundation.css') }}
    {{ HTML::style('assets/css/custom.css') }}
    {{ HTML::script('./assets/js/vendor/custom.modernizr.js') }}
</head>
<body>
<div class="row main">
    <div class="small-12 large-12 column" id="masthead">
        <header>
            <nav class="top-bar" data-topbar>
                <ul class="title-area">
                    <!-- Title Area -->
                    <li class="name"></li>
                    <!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone -->
                    <li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
                </ul>
                <section class="top-bar-section">
                    <ul class="left">
                        <li class="{{(strcmp(URL::full(), URL::to('/')) == 0) ? 'active' : ''}}"><a href="{{URL::to('/')}}">Home</a></li>
                    </ul>
                    <ul class="right">
                        @if(Auth::check())
                            <li class="{{ (strpos(URL::current(), URL::to('admin/dash-board'))!== false) ? 'active' : '' }}">
                                {{HTML::link('admin/dash-board','Dashboard')}}
                            </li>
                            <li class="{{ (strpos(URL::current(), URL::to('logout'))!== false) ? 'active' : '' }}" >
                                {{HTML::link('logout','Logout')}}
                            </li>
                        @else
                            <li class="{{ (strpos(URL::current(), URL::to('login'))!== false) ? 'active' : '' }}">
                                {{HTML::link('login','Login')}}
                            </li>
                        @endif
                    </ul>
                </section>
            </nav>
            <div class="sub-header">
                <hgroup>
                    <h1>{{HTML::link('/','Laravel 4 Blog')}}</h1>
                    <h2>Laravel 4 Simple Blog tutorial</h2>
                </hgroup>
            </div>
        </header>
    </div>
    <div class="row">
        {{$main}}
    </div>
    <div class="row">
        <div class="small-12 large-12 column">
            <footer class="site-footer"></footer>
        </div>
    </div>
</div>
{{ HTML::script('./assets/js/vendor/jquery.js') }}
{{ HTML::script('./assets/js/foundation.min.js') }}
<script>
    $(document).foundation();
</script>
</body>
</html>

NOTE 1:
To use the master layout across all the controllers, we need to define the protected $layout='master'; property in the BaseController, so that all the controllers inherit layout property.

NOTE 2:
I have used the Foundation 5 framework for the styling purpose, you can read my previous article on Foundation 5 to understand the markup and CSS classes I have used in the views.

In the head section of the master layout, I have linked the style sheets using HTML::style() method which generates a link tag with the href attribute set to the path provided as an argument. Similarly, HTML::script() is used to generate the links to the required JavaScript files.

Quick Tips:

  • In Laravel we use Blade Template Engine to write views.
  • To use Blade Template Engine, we save files with a blade.php extension.
  • In a view we can output content using {{ $title }}, this is Blade’s equivalent to <?php echo $title; ?>.
  • We can use control structures by using @if() @endif, @foreach @endforeach etc.
  • We can escape HTML by using triple curly brace syntax like: {{{ $title }}}.
  • See Blade’s Documentation for further details.

In the header section, the navigation for the blog is defined and some conditional expressions are used to display the active links. The dashboard and logout links will be displayed only if a user is logged in. {{$main}} is the pluggable section of the master layout which is used in controllers to insert child views.

A snippet from the getIndex action of the BlogController:

 <?php

//used to set the title variable in master layout.
$this->layout->title = 'Home Page | Laravel 4 Blog'; 

//used to insert partial view named as home.blade.php in the master layout.
//by using nest() we are injecting index view in the home view, exciting huh?
$this->layout->main = View::make('home')->nest('content','index',compact('posts'));

Creating Views

The app/views directory is used to hold the view files for an application. Here is a screenshot of our application’s views directory:

Creating a Blog Using Laravel 4 Part 4 Layout and Views
Views Directory Screenshot

Home, index and sidebar

home.blade.php

{{-- home page --}}
<div class="small-8 large-8 column">
  <div class="content">
    {{$content}}
  </div>
</div>
<div class="small-4 large-4 column">
  <aside class="sidebar">
    @include('sidebar')
  </aside>
</div>

index.blade.php

@if(!empty($notFound))
<p>Sorry nothing found for your query!</p>
@else
@foreach($posts as $post)
    <article class="post">
        <header class="post-header">
            <h1 class="post-title">
                {{link_to_route('post.show',$post->title,$post->id)}}
            </h1>
            <div class="clearfix">
                <span class="left date">{{explode(' ',$post->created_at)[0]}}</span>
                <span class="right label">{{$post->comment_count}} comments </span>
            </div>
        </header>
        <div class="post-content">
            <p>{{$post->read_more.' ...'}}</p>
            <span>{{link_to_route('post.show','Read full article',$post->id)}}
        </div>
        <footer class="post-footer">
            <hr>
        </footer>
    </article>
@endforeach
{{$posts->links()}}
@endif

sidebar.blade.php

{{ Form::open(['url' => 'search','method'=>'get']) }}
    <div class="row">
        <div class="small-8 large-8 column">
            {{ Form::text('s',Input::old('username'),['placeholder'=>'Search blog...']) }}
        </div>
            {{ Form::submit('Search',['class'=>'button tiny radius']) }}
    </div>
{{ Form::close() }}
<div>
    <h3>Recent Posts</h3>
    <ul>
    @foreach($recentPosts as $post)
        <li>{{link_to_route('post.show',$post->title,$post->id)}}</li>
    @endforeach
    </ul>
</div>

The home page contains two div elements: one to show the index content and the other is used to include the sidebar partial view using Blade’s @include directive.

In the index.blade.php, we are iterating through all the posts to show an index of published posts along with the Read More links.

Creating a Blog Using Laravel 4 Part 4 Layout and Views
Index Page Screenshot

View Composers
View Composers in Laravel, are callbacks that help us in defining the view logic. We can register a callback by using View::composer(). Whenever a view is rendered for which a callback is registered, Laravel will execute the callback before rendering the view.

You would have noticed that, we did not pass the $recentPosts variable to the sidebar partial in any controller action. This variable is actually populated by using the View Composer callback:

<?php
 View::composer('sidebar', function($view)
{
    $view->recentPosts = Post::orderBy('id','desc')->take(5)->get();
});

Dashboard, post listings and comment listings

dash.blade.php

<div class="small-3 large-3 column">
    <aside class="sidebar">
        <h3>Menu</h3>
        <ul class="side-nav">
            <li>{{HTML::link('/','Home')}}</li>
            <li class="divider"></li>
            <li class="{{ (strpos(URL::current(),route('post.new'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('post.new','New Post')}}
            </li >
            <li class="{{ (strpos(URL::current(),route('post.list'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('post.list','List Posts')}}
            </li>
            <li class="divider"></li>
            <li class="{{ (strpos(URL::current(),route('comment.list'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('comment.list','List Comments')}}
            </li>
        </ul>
    </aside>
</div>
<div class="small-9 large-9 column">
    <div class="content">
        @if(Session::has('success'))
        <div data-alert class="alert-box round">
            {{Session::get('success')}}
            <a href="#" class="close">&times;</a>
        </div>
        @endif
        {{$content}}
    </div>
    <div id="comment-show" class="reveal-modal small" data-reveal>
        {{-- quick comment using ajax --}}
    </div>
</div>
Creating a Blog using Laravel 4 part 4 Layout and Views
Admin Dashboard Screenshot

In the admin dashboard, the links to the CRUD are shown in the left sidebar. The right pane is used to insert the partials for the CRUD operations: post listings, comment listings, new post etc.

The Reveal Modal plugin of Foundation 5 has a built-in support for Ajax, the last div element will be used by the Reveal Modal plugin to populate the Ajax content.

posts/list.blade.php

<h2 class="post-listings">Post listings</h2><hr>
<table>
    <thead>
    <tr>
        <th width="300">Post Title</th>
        <th width="120">Post Edit</th>
        <th width="120">Post Delete</th>
        <th width="120">Post View</th>
    </tr>
    </thead>
    <tbody>
        @foreach($posts as $post)
            <tr>
                <td>{{$post->title}}</td>
                <td>{{HTML::linkRoute('post.edit','Edit',$post->id)}}</td>
                <td>{{HTML::linkRoute('post.delete','Delete',$post->id)}}</td>
                <td>{{HTML::linkRoute('post.show','View',$post->id,['target'=>'_blank'])}}</td>
            </tr>
        @endforeach
    </tbody>
</table>
{{$posts->links()}}
Creating a Blog Using Laravel 4 Part 4 Layout and Views
Post Listing Screenshot

comments/list.blade.php

<h2 class="comment-listings">Comment listings</h2><hr>
<table>
    <thead>
    <tr>
        <th>Commenter</th>
        <th>Email</th>
        <th>At Post</th>
        <th>Approved</th>
        <th>Comment Delete</th>
        <th>Comment View</th>
    </tr>
    </thead>
    <tbody>
    @foreach($comments as $comment)
    <tr>
        <td>{{{$comment->commenter}}}</td>
        <td>{{{$comment->email}}}</td>
        <td>{{$comment->post->title}}</td>
        <td>
            {{Form::open(['route'=>['comment.update',$comment->id]])}}
            {{Form::select('status',['yes'=>'Yes','no'=>'No'],$comment->approved,['style'=>'margin-bottom:0','onchange'=>'submit()'])}}
            {{Form::close()}}
        </td>
        <td>{{HTML::linkRoute('comment.delete','Delete',$comment->id)}}</td>
        <td>{{HTML::linkRoute('comment.show','Quick View',$comment->id,['data-reveal-id'=>'comment-show','data-reveal-ajax'=>'true'])}}</td>
    </tr>
    @endforeach
    </tbody>
</table>
{{$comments->links()}}
Creating a Blog Using Laravel 4 part 4 Layout and Views
Comments Listings and Quick View using Ajax

Both the comments/list.blade.php and posts/list.blade.php share the same logic. In post/list.blade.php all the published posts are shown in a tabular form with links to certain admin CRUD operations like: edit, delete and view. The comments/list.blade.php has an additional form inside the td element. This form will be used for the comment moderation purpose.

The additional HTML attributes passed to the Quick View link are the requirements for the Reveal Model plugin to work properly.

Download Source Code

That’s all folks! I am skipping the rest of the views. You can download all the source code for the blog by using the above link and experiment as you like.

Thanks for reading this article and please write me your suggestions, or, if you have any questions, do not hesitate to ask!