Laravel Tutorial #7: Create Routes, Controllers and Views


    More Tutorials on Web Development


    Registering Routes

    use App\Http\Controllers\CategoryController;
    use App\Http\Controllers\IndexController;
    use App\Http\Controllers\PostController;
    use App\Http\Controllers\TagController;
    
    Route::get('/', IndexController::class);
    Route::get('/category/{slug}', CategoryController::class);
    Route::get('/tag/{slug}', TagController::class);
    Route::get('/post/{slug}', [PostController::class, 'show']);

    We didn’t use the single-action controller for the post controller because we are going to add a search function here in the next article.

    For now, your IDE will probably give you an error, because we haven’t created these controllers yet.

    Controllers

    Index Controller

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\General;
    use App\Models\Post;
    use App\Models\Tag;
    use App\Models\Category;
    use Illuminate\Http\Request;
    
    class IndexController extends Controller
    {
        public function __invoke()
        {
            //get the general information about the website
            $website = General::query()->firstOrFail();
    
            //get the posts that are published, sort by decreasing order of "id".
            $posts = Post::query()
                ->where('is_published',true)
                ->orderBy('id','desc')
                ->get();
    
            //get the featured posts
            $featured_posts = Post::query()
                ->where('is_published',true)
                ->where('is_featured',true)
                ->orderBy('id','desc')
                ->take(5)
                ->get();
    
            //get all the categories
            $categories = Category::all();
    
            //get all the tags
            $tags = Tag::all();
    
            //get the recent 5 posts
            $recent_posts = Post::query()
                ->where('is_published',true)
                ->orderBy('created_at','desc')
                ->take(5)
                ->get();
    
            //return the data to the corresponding view
            return view('home', [
                'website' => $website,
                'posts' => $posts,
                'featured_posts' => $featured_posts,
                'categories' => $categories,
                'tags' => $tags,
                'recent_posts' => $recent_posts
            ]);
        }
    }
    

    Category Controller

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\General;
    use App\Models\Post;
    use App\Models\Tag;
    use App\Models\Category;
    use Illuminate\Http\Request;
    
    class CategoryController extends Controller
    {
        public function __invoke($slug)
        {
            //get the general information about the website
            $website = General::query()->firstOrFail();
    
            //get the requested category
            $category = Category::query()
                ->where('slug', $slug)
                ->firstOrFail();
    
            //get the posts in that category
            $posts = $category->posts()
                ->where('is_published',true)
                ->orderBy('id','desc')
                ->get();
    
            //get all the categories
            $categories = Category::all();
    
            //get all the tags
            $tags = Tag::all();
    
            //get the recent 5 posts
            $recent_posts = Post::query()
                ->where('is_published',true)
                ->orderBy('created_at','desc')
                ->take(5)
                ->get();
    
            //return the data to the corresponding view
            return view('category', [
                'website' => $website,
                'category' => $category,
                'posts' => $posts,
                'categories' => $categories,
                'tags' => $tags,
                'recent_posts' => $recent_posts
            ]);
        }
    }
    

    Tag Controller

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\General;
    use App\Models\Post;
    use App\Models\Tag;
    use App\Models\Category;
    use Illuminate\Http\Request;
    
    class TagController extends Controller
    {
        public function __invoke($slug)
        {
            //get the general information about the website
            $website = General::query()->firstOrFail();
    
            //get the requested tag
            $tag = Tag::query()
                ->where('slug', $slug)
                ->firstOrFail();
    
            //get the posts with that tag
            $posts = $tag->posts()
                ->where('is_published',true)
                ->orderBy('id','desc')
                ->get();
    
            //get all the categories
            $categories = Category::all();
    
            //get all the tags
            $tags = Tag::all();
    
            //get the recent 5 posts
            $recent_posts = Post::query()
                ->where('is_published',true)
                ->orderBy('created_at','desc')
                ->take(5)
                ->get();
    
            //return the data to the corresponding view
            return view('tag', [
                'website' => $website,
                'tag' => $tag,
                'posts' => $posts,
                'categories' => $categories,
                'tags' => $tags,
                'recent_posts' => $recent_posts
            ]);
        }
    }
    

    Post Controller

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\General;
    use App\Models\Post;
    use App\Models\Tag;
    use App\Models\Category;
    use Illuminate\Http\Request;
    
    class PostController extends Controller
    {
        public function show($slug)
        {
            //get the general information about the website
            $website = General::query()->firstOrFail();
    
            //get the requested post, if it is published
            $post = Post::query()
                ->where('is_published', true)
                ->where('slug', $slug)
                ->firstOrFail();
    
            //get all the categories
            $categories = Category::all();
    
            //get all the tags
            $tags = Tag::all();
    
            //get the recent 5 posts
            $recent_posts = Post::query()
                ->where('is_published', true)
                ->orderBy('created_at', 'desc')
                ->take(5)
                ->get();
    
            //return the data to the corresponding view
            return view('post', [
                'website' => $website,
                'post' => $post,
                'categories' => $categories,
                'tags' => $tags,
                'recent_posts' => $recent_posts,
            ]);
        }
    }
    

    Views

    In this tutorial, we will be using this Bootstrap template for our views.

    img

    You can download the source code here:

    Assuming you understand how HTML, CSS and JS work. This is the view structure I designed:

    Layout

    • views
      • vendor
        • posts-list.blade.php
        • sidebar.blade.php
      • master.blade.php
      • home.blade.php
      • category.blade.php
      • tag.blade.php
      • post.blade.php

    Master

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
    
    @yield('meta')
    
    @yield('title')
    
    <!-- Bootstrap core CSS -->
        <link href="{{asset('vendor/bootstrap/css/bootstrap.css')}}" rel="stylesheet">
    
        <!-- Custom styles for this template -->
        <link href="{{asset('vendor/css/mystyle.css')}}" rel="stylesheet">
    </head>
    
    <body>
    
    <!-- Navigation -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
        <div class="container">
            <a class="navbar-brand" href="/">{{$website['website_title']}}</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
                    aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarResponsive">
                <ul class="navbar-nav ml-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="/">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="https://www.techjblog.com/index.php/laravel-tutorial-for-beginners/">Laravel
                            Tutorial</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="/nova">Admin</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    
    <!-- Page Content -->
    <div class="container">
    
        @yield('content')
    
    </div>
    <!-- /.container -->
    
    <!-- Footer -->
    <footer class="py-5 bg-dark">
        <div class="container">
            <p class="m-0 text-center text-white">Copyright
                © {{$website['website_title']}} <?php echo date("Y"); ?></p>
        </div>
        <!-- /.container -->
    </footer>
    
    <!-- Bootstrap core JavaScript -->
    <script src="{{asset('vendor/bootstrap/js/jquery/jquery.min.js')}}"></script>
    <script src="{{asset('vendor/bootstrap/js/bootstrap.bundle.min.js')}}"></script>
    
    </body>
    </html>
    

    Line 11, {{asset('vendor/css/bootstrap.min.css')}} generates the URL /public/vendor/css/bootstrap.min.css.

    Post List

    @foreach($posts as $post)
        <!-- Blog Post -->
        <div class="card mb-4">
            <img class="card-img-top" src="{{\Illuminate\Support\Facades\Storage::url($post['featured_image'])}}" alt="Card image cap">
            <div class="card-body">
                <h2 class="card-title">{{$post['title']}}</h2>
                <p class="card-text">{{\Illuminate\Support\Str::limit(strip_tags($post['content']), 200, '...')}}</p>
                <a href="/post/{{$post['slug']}}" class="btn btn-primary">Read More →</a>
            </div>
            <div class="card-footer text-muted">
                Posted on {{$post->created_at->format('M d Y')}} by
                <a href="#">{{$post->user['name']}}</a>
            </div>
        </div>
    @endforeach
    

    Line 7, strip_tags() will eliminate the HTML tags, \Illuminate\Support\Str::limit() can limit the number of characters that are shown, in this case, limit the string to 200 char and end with “...

    Line 11, format('M d Y') changes the format of the date.

    Sidebar

    <!-- Sidebar Widgets Column -->
    <div class="col-md-4">
    
        <!-- Search Widget -->
        <div class="card my-4">
            <h5 class="card-header">Search</h5>
            <form class="card-body" action="" method="GET" role="search">
                <div class="input-group">
                    <input type="text" class="form-control" placeholder="Search for..." name="q">
                    <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Go!</button>
                  </span>
                </div>
            </form>
        </div>
        <a href="https://www.techjblog.com/index.php/tutorials/laravel-tutorial-9-search-pagination-related-posts-and-other-functions/#0-search/">How
            to Add Search Function for Your Blog</a>
    
    
        <!-- Categories Widget -->
        <div class="card my-4">
            <h5 class="card-header">Categories</h5>
            <div class="card-body">
                <div class="row">
                    <div class="col-lg-6">
                        <ul class="list-unstyled mb-0">
                            @foreach($categories as $category)
                                <li>
                                    <a href="/category/{{$category['slug']}}">{{$category['name']}}</a>
                                </li>
                            @endforeach
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    
        <!-- Tags Widget -->
        <div class="card my-4">
            <h5 class="card-header">Tags</h5>
            <div class="card-body">
                <div class="row">
                    <div class="col-lg-6">
                        <ul class="list-unstyled mb-0">
                            @foreach($tags as $tag)
                                <li>
                                    <a href="/tag/{{$tag['slug']}}">{{$tag['name']}}</a>
                                </li>
                            @endforeach
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    
        <!-- Recent Posts Widget -->
        <div class="card my-4">
            <h5 class="card-header">Recent Posts</h5>
            <div class="card-body">
                <div class="row">
                    <div class="col-lg-12">
                        <ul class="list-unstyled mb-0">
                            @foreach($recent_posts as $post)
                                <li>
                                    <a href="/post/{{$post['slug']}}">{{$post['title']}}</a>
                                </li>
                                <hr>
                            @endforeach
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    
        <!-- Side Widget -->
        <div class="card my-4">
            <h5 class="card-header">Tutorial</h5>
            <div class="card-body">
                <ul class="list-unstyled mb-0">
                    <li>
                        <a href="https://www.techjblog.com/index.php/laravel-tutorial-for-beginners/">Laravel Tutorial For
                            Beginners</a>
                    </li>
                </ul>
            </div>
        </div>
    
    </div>
    

    Home Page

    @extends('master')
    
    @section('meta')
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="description" content="{{$website['description']}}">
        <meta name="author" content="Eric Hu">
    @endsection
    
    @section('title')
        <title>{{$website['website_title']}}</title>
    @endsection
    
    @section('content')
        <div class="row">
            <!-- Blog Entries Column -->
            <div class="col-md-8">
    
                <h1 class="my-4">Laravel Blog
                    <small>Home Page</small>
                </h1>
    
                @include('vendor.posts-list')
    
            </div>
            @include('vendor.sidebar')
        </div>
    @endsection
    

    Category Page

    @extends('master')
    
    @section('meta')
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="description" content="{{$website['description']}}">
        <meta name="author" content="Eric Hu">
    @endsection
    
    @section('title')
        <title>{{$website['website_title']}} - Category:{{$category['name']}}</title>
    @endsection
    
    @section('content')
        <div class="row">
            <!-- Blog Entries Column -->
            <div class="col-md-8">
    
                <h1 class="my-4">Category:
                    <small>{{$category['name']}}</small>
                </h1>
    
                @include('vendor.posts-list')
    
            </div>
            @include('vendor.sidebar')
        </div>
    @endsection
    

    Tag Page

    @extends('master')
    
    @section('meta')
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="description" content="{{$website['description']}}">
        <meta name="author" content="Eric Hu">
    @endsection
    
    @section('title')
        <title>{{$website['website_title']}} - Tag:{{$tag['name']}}</title>
    @endsection
    
    @section('content')
        <div class="row">
            <!-- Blog Entries Column -->
            <div class="col-md-8">
    
                <h1 class="my-4">Tag:
                    <small>{{$tag['name']}}</small>
                </h1>
    
                @include('vendor.posts-list')
    
            </div>
            @include('vendor.sidebar')
        </div>
    @endsection
    

    Post Page

    @extends('master')
    
    @section('meta')
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta name="description" content="{{$website['description']}}">
        <meta name="author" content="Eric Hu">
    @endsection
    
    @section('title')
        <title>{{$post['title']}}{{$website['website_title']}}</title>
    @endsection
    
    @section('content')
        <div class="row">
    
            <!-- Post Content Column -->
            <div class="col-lg-8">
    
                <!-- Title -->
                <h1 class="mt-4">{{$post['title']}}</h1>
    
                <!-- Author -->
                <p class="lead">
                    by
                    <a href="#">{{$post->user['name']}}</a>
                </p>
                <hr>
    
                <!-- Date/Time -->
                <p>Posted on {{$post->created_at->format('M d, Y')}}</p>
                <hr>
    
                <!-- Preview Image -->
                <img class="img-fluid rounded" src="{{\Illuminate\Support\Facades\Storage::url($post->featured_image)}}" alt="">
                <hr>
    
                <!-- Post Content -->
                {!! $post->content !!}
                <hr>
    
            </div>
            @include('vendor.sidebar')
    
        </div>
    @endsection
    

    Line 39, {!! $post->content !!} get the content for the post. {!! !!} must be used or the HTML tags will not work.

    By default, Blade {{ }} statements are automatically sent through PHP’s htmlspecialchars function to prevent XSS attacks.

    Leave a Reply

    Your email address will not be published. Required fields are marked *