DEV Community

loading...
Cover image for Laravel 8 Tutorial #7: Create Routes, Controllers and Views

Laravel 8 Tutorial #7: Create Routes, Controllers and Views

ericnanhu profile image Eric Hu Originally published at techjblog.com Updated on ・7 min read

You can download the source code of this tutorial here: https://www.techjblog.com/index.php/laravel-tutorial-for-beginners/

Registering Routes

Route::get('/', IndexController::class);
Route::get('/category/{slug}', CategoryController::class);
Route::get('/tag/{slug}', TagController::class);
Route::get('/post/{slug}', [PostController::class, 'show']);
Enter fullscreen mode Exit fullscreen mode

We didn’t use single action controller for post controller becase we are giong to add search function here in the next post.

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
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

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
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

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
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

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,
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Views

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

img

You can download the source code here:

DOWNLOAD TEMPLATE

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Related Articles

How to Make Your Server More Secure

Laravel Tutorial For Beginners

Django Tutorial For Beginners

Build A Unit Converter with Vue.js

Discussion (1)

pic
Editor guide
Collapse
rsevero profile image
Rodrigo Severo

I believe there is a section missing in this page that should detail the changes to the controllers and views for Voyager users (that didn't implement the General model).