How to Create a Blog with Laravel 5+ Part 7 (CRUD Comment & Helper) Final Part

Advertisement

We’ve done a great job so far, on the previous part, Part 7 (Articles and Comment Form) it focuses on adding a new menu to display lists of blog posts, blog single page, and a comment form and on this article we’ll work on Comment CRUD methods, display approved comments and managing comments in the dashboard area.

Let’s get started.

articles/index.blade.php

With an updated slug, we used slug now instead of the default id, slug is used to display single blog post, e.g. http://127.0.0.1:8000/article/laravel-tutorial-part-7-crud-comment compare to id http://127.0.0.1:8000/article/1.


@extends('main')

@section('title', '| Blog Tutorial')

@section('content')
    <div class="blog-header">
        <h1 class="blog-title">Articles</h1>
        <p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p>
    </div>
    
    <div class="row">
        <div class="col-sm-8 blog-main">
            
            @if( $posts->count() )
                @foreach( $posts as $post )
                    
                    <div class="blog-post">
                        <h2 class="blog-post-title">
                            <a href="/article/{{ $post->post_slug }}">{{ $post->post_title }}</a>
                        </h2>
                        <p class="blog-post-meta">{{ date('M j, Y', strtotime( $post->created_at )) }} by <a href="#">{{ Helper::get_userinfo( $post->author_ID )->name }}</a></p>
                    
                        <div class="blog-content">
                            {!! nl2br( $post->post_content ) !!}
                        </div>
                    </div>

                @endforeach
            @else

                <p>No post added yet!</p>

            @endif

            {{-- Display pagination only if more than the required pagination --}}
            @if( $posts->total() > 6 )
                <nav>
                    <ul class="pager">
                        @if( $posts->firstItem() > 1 )
                            <li><a href="{{ $posts->previousPageUrl() }}">Previous</a></li>
                        @endif
                        
                        @if( $posts->lastItem() < $posts->total() )
                            <li><a href="{{ $posts->nextPageUrl() }}">Next</a></li>
                        @endif
                    </ul>
                </nav>
            @endif

        </div><!-- /.blog-main -->
        
        <!--Sidebar-->
        @include('partials._sidebar')

    </div><!-- /.row -->
@endsection

articles/single.blade.php

Added helper to display Category Name instead of just Category ID and we also display lists of comments added, Helper code below.


@extends('main')

@section('title')
    | {{ $post->post_title }}
@endsection

@section('content')
   
    <div class="blog-header">
        <h1 class="blog-title">{{ $post->post_title }}</h1>
        <p>{{ Helper::get_category( $post->category_ID )->category_name }} / {{ date('M j, Y', strtotime( $post->created_at )) }} <a href="{{ route('posts.edit', $post->id) }}">{Edit}</a></p>
    </div>
    
    <div class="row">
        <div class="col-sm-8 blog-main">
            
            <div class="blog-content">
                {!! nl2br( $post->post_content ) !!}
            </div><!-- /.blog-post -->
            
            <section class="mt-5" id="respond">
                <h2>Comments</h2>

                {{--display approved comments--}}
                <?php
                    echo Helper::get_comments( $post->id );
                ?>
            </section>
            
            <section class="mt-5" id="comment">
                {{-- display comment form --}}
                @includeIf('comments.form', ['post_id' => $post->id])
            </section>
            
        </div><!-- /.blog-main -->
        
        <!--Sidebar-->
        @include('partials._sidebar')
    </div><!-- /.row -->

@endsection

Now that articles views have been updated, lets work on the CRUD methods for comments.

comments/edit.blade.php


@extends('main')

@section('title', '| Edit Comment')

@section('content')
	
	<div class="container">
		
		{{-- Check if current user is logged-in or a guest --}}
		@if (Auth::guest())
			
			<p class="mt-5">Cheatn?, please <a href="/login/">login</a> to continue.</p>
			
		@else
			<div class="blog-header">
		        <h1 class="blog-title">Edit Comment</h1>
		    </div>

			@php
                $post = Helper::get_post( $comment->post_id  );
            @endphp

			<div class="row">
				<div class="col-md-8">
					
					{{--
						Check route:list for `comments.update` for more info
						URL is comments/{comment}, `{comment}` meaning that we have to supply ID
					--}}	
					<form action="{{ route('comments.update', $comment->id) }}" method="POST">
						{{ csrf_field() }}
						
						{{--
							HTML forms do not support PUT, PATCH or DELETE actions.
							So, when defining PUT, PATCH or  DELETE routes that are called from an HTML form,
							you will need to add a hidden _method field to the form.
						--}}
						{{ method_field('PUT') }}
						
						<input type="hidden" name="post_id" value="{{ $comment->post_id }}" />
						
						<div class="form-group{{ $errors->has('comment_author') ? ' has-error' : '' }}">
							<label for="comment_author">Name *</label> <br/>
							<input type="text" name="comment_author" value="{{ $comment->comment_author }}" />
							
							@if ($errors->has('comment_author'))
					            <span class="help-block">
					                <strong>{{ $errors->first('comment_author') }}</strong>
					            </span>
					        @endif
						</div>
						
						<div class="form-group{{ $errors->has('comment_author_email') ? ' has-error' : '' }}">
							<label for="comment_author_email">Email Address *</label> <br/>
							<input type="text" name="comment_author_email" value="{{ $comment->comment_author_email }}" />

							@if ($errors->has('comment_author_email'))
					            <span class="help-block">
					                <strong>{{ $errors->first('comment_author_email') }}</strong>
					            </span>
					        @endif
						</div>
						
						<div class="form-group">
							<label for="comment_author_url">Website</label> <br/>
							<input type="text" name="comment_author_url" value="{{ $comment->comment_author_url }}" />
						</div>
						
						<div class="form-group">
							<label for="comment_content">Message</label> <br/>
							<textarea cols="60" rows="6" name="comment_content">{{ $comment->comment_content }}</textarea>
						</div>
						
						<div class="form-group">
							<input type="submit" class="btn btn-primary" value="Update" />
							<a class="btn btn-primary" href="{{ route('comments.index') }}">Cancel</a>
						</div>
					</form> 

				</div>

				<div class="col-md-4">
					<p>Submitted on: {{ date('F j, Y', strtotime( $comment->created_at )) }} @ {{ date('h:i', strtotime( $comment->created_at )) }}</p>
					<p>In response to: <a target="_blank" href="{{ route('single', $post->post_slug) }}"><strong>{{ $post->post_title }}</strong></a></p>
				</div>
			</div>

		@endif

	</div>
@endsection

comments/index.blade.php

This file is used to display lists of added comments, we also add a capability to Approved and Unapproved comments, as well as display, only approved comments.


@extends('main')

@section('title', 'Comments')

@section('content')
	
	<div class="container">
        
        {{-- Check if current user is logged-in or a guest --}}
        @if (Auth::guest())
            
            <p class="mt-5">Cheatn?, please <a href="/login/">login</a> to continue.</p>
            
        @else
            
            <div class="blog-header">
                <h1 class="blog-title">Comments</h1>
            </div>
            
            <div class="row">
                <div class="col-md-12">
                    
                    <a href="{{ route('comments.index') }}">All</a> | <a href="{{ route('comments.index') }}/?comment_status=1">Approved</a>
        
                    <table class="table">
	                    <tr>
                            <th>Author</th>
                            <th>Comment</th>
                            <th>In Response To</th>
                            <th>Submitted On</th>
                            <th width="24%">&nbsp;</th>
                        </tr>
                        <tr>
                            {{-- Blade if and else --}}
                            @if( $comments->count() )
                                {{-- Blade foreach --}}
                                @foreach( $comments as $comment )
									<tr>
                                        <td>
                                            <strong>
                                                <a href="{{ route('comments.edit', $comment->id) }}">
                                                    {{ $comment->comment_author }}
                                                </a> <br/>
                                                
												<a href="mailto:{{ $comment->comment_author_email }}">
                                                	{{ $comment->comment_author_email }}
                                                </a> <br/>
												
                                                {{ $comment->comment_author_ip }}
                                            </strong>
                                        </td>
										<td>
											{{ $comment->comment_content }}
										</td>
										<td>
                                            @php
                                                $post = Helper::get_post( $comment->post_id  );
                                            @endphp

                                            {{ $post->post_title }} <br/>
											<a target="_blank" href="{{ route('single', Helper::get_post_slug( $post->post_slug ) ) }}">View Post</a>
										</td>
                                        <td>
                                            {{ date('F j, Y', strtotime( $comment->created_at )) }} @ {{ date('h:i', strtotime( $comment->created_at )) }}
                                        </td>
                                        <td>
                                            <?php if( $comment->comment_approved ) : ?>
                                                <form class="d-inline" action="{{ route('comment.unapprove', $comment->id) }}" method="POST">
                                                    {{ csrf_field() }}
                                                    
                                                    <input type="submit" value="Unapprove" class="btn btn-sm btn-success" />
                                                </form>
                                            <?php else : ?>
                                                <form class="d-inline" action="{{ route('comment.approve', $comment->id) }}" method="POST">
                                                    {{ csrf_field() }}
                                                    
                                                    <input type="submit" value="Approve" class="btn btn-sm btn-success" />
                                                </form>
                                            <?php endif; ?>
                                            |
                                            <form class="d-inline" action="{{ route('comments.destroy', $comment->id) }}" method="POST">
                                                {{ csrf_field() }}
                                                {{ method_field('DELETE') }}

                                                <input type="submit" value="Delete" class="btn btn-sm btn-danger" />
                                            </form>
											
                                            <a class="btn btn-sm btn-info" href="{{ route('comments.edit', $comment->id) }}">Edit</a>
                                        </td>
                                    </tr>
                                @endforeach
                    		@else
                            	
                                <tr>
                                    <td colspan="5">No comment has been added yet!</td>
                                </tr>

                            @endif
                        </tr>
                    </table>

                    {{ $comments->links() }}

                </div>
            </div>

        @endif

    </div>
    
@endsection

create.blade.php, If you allow adding comment manually in your blog dashboard area, go ahead and fill this file.

Advertisement

Controllers/CommentsController

This file controls the comments CRUD methods and approved and unapproved selected commentm, thus the name, Controller.


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Helpers\Helper;
use App\Comment;
use Session;

class CommentsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index( Request $request )
    {
        $comment_status = $request->query('comment_status');

        if( $comment_status )
            $comments = Comment::where('comment_approved', 1)->paginate( 10 );
        else
            $comments = Comment::paginate( 10 );
            
        return view('comments.index', ['comments' => $comments]);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'comment_author'        => 'required',
            'comment_author_email'  => 'required|email',
            'comment_author_url'    => 'sometimes|required',
            'comment_content'       => 'required'
        ]);

        $comment = new Comment;

        $comment->comment_author_ip     = $request->ip();
        $comment->user_id               = Auth::id();
        $comment->post_id               = $request->post_id;
        $comment->comment_author        = $request->comment_author;
        $comment->comment_author_email  = $request->comment_author_email;
        $comment->comment_author_url    = $request->comment_author_url;
        $comment->comment_content       = $request->comment_content;

        // We have two options for this add new Migration and add 0 as the default value
        // or this magic trick here :-D
        $comment->comment_approved      = 0;

        $comment->save();

        Session::flash('success', 'Your comment is waiting approval.');

        return redirect()->route('single', Helper::get_post_slug( $request->post_id ));
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $comment = Comment::findOrFail( $id );

        return view('comments.edit', ['comment' => $comment]);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request, [
            'comment_author'        => 'required',
            'comment_author_email'  => 'required|email',
            'comment_author_url'    => 'sometimes|required',
            'comment_content'       => 'required'
        ]);

        $comment = Comment::findOrFail( $id );

        $comment->comment_author        = $request->input('comment_author');
        $comment->comment_author_email  = $request->input('comment_author_email');
        $comment->comment_author_url    = $request->input('comment_author_url');
        $comment->comment_content       = $request->input('comment_content');

        // We have two options for this add new Migration and add 0 as the default value
        // or this magic trick here :-D
        $comment->comment_approved      = 0;

        $comment->save();

        Session::flash('success', 'Comment updated.');

        return redirect()->route('comments.edit', $id );
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $comment = Comment::findOrFail( $id );

        $comment->delete();

        Session::flash('success', 'Comment deleted');

        return redirect()->route('comments.index');
    }

    /**
     * Approved comment
     */
    public function approveComment( $id ) {
        
        // We have to make sure that ID is present and given during form submission
        if( empty( $id ) )
            return;

        $comment = Comment::findOrFail( $id );
        
        // Update this to 1, meaning approved
        $comment->comment_approved = 1;
        
        $comment->save();

        Session::flash('success', 'Comment approved.');

        return redirect()->route('comments.index' );
    }

    /**
     * Unapproved comment
     */
    public function unapproveComment( $id ) {
        
        // We have to make sure that ID is present and given during form submission
        if( empty( $id ) )
            return;

        $comment = Comment::findOrFail( $id );

        // Update this to 0, meaning unapproved
        $comment->comment_approved = 0;

        $comment->save();

        Session::flash('success', 'Comment unapproved.');

        return redirect()->route('comments.index' );
    }
}

routes/web.php

Lets update the routes file with an updated for comment and approved and unapproved comment.


...
Route::get('/', 'PagesController@getIndex')->name('home');
Route::get('article/{slug}', 'ArticlesController@getSingle')->name('single');
Route::get('articles', 'ArticlesController@getIndex');
Route::resource('pages', 'PagesController');
Route::resource('posts', 'PostsController');
Route::resource('categories', 'CategoriesController');
Route::resource('comments', 'CommentsController');
Route::post('comments/{comment}/approve', 'CommentsController@approveComment')->name('comment.approve');
Route::post('comments/{comment}/unapprove', 'CommentsController@unapproveComment')->name('comment.unapprove');

Auth::routes();

One more thing…

Helpers/Helper.php

This file contains lists of handy functions for posts, page, category, comments and user. File and directory location /app/Helpers/Helper.


<?php

namespace App\Helpers;

use App\User;
use App\Post;
use App\Category;
use App\Comment;

class Helper
{
    /**
     * Return user selected infos
     */ 
    public static function get_userinfo( $user_id )
    {
        if( empty( $user_id ) )
            return;
        
        $user_infos = User::where('id', $user_id)->first();
        
        if( $user_infos )
            return $user_infos;

        return false;
    }

    /**
     * Return user selected infos
     */ 
    public static function get_users()
    {
        if( empty( $user_id ) )
            return;
        
        $users = User::get();
        
        if( $users )
            return $users;

        return false;
    }


    /**
     * Return post_slug
     */ 
    public static function get_post_slug( $post_id )
    {
        if( empty( $post_id ) )
            return;

        $post = Post::where('post_type', 'post')
                      ->where('id', $post_id)->first();
        
        if( $post )
            return $post->post_slug;

        return false;
    }

    /**
     * Get lists of posts
     */ 
    public static function get_posts()
    {
        $posts = Post::where('post_type', 'post')->get();
        
        return $posts;
    }
    
    /**
     * This return single page record
     * @param  INT $page_id Post ID supplied by user
     * @return Object Object of posts records
     */
    public static function get_post( $post_id )
    {
        if( empty( $post_id ) )
            return;

        $post = Post::where('id', $post_id)->first();
        
        return $post;
    }

    /**
     * Get lists of pages
     */ 
    public static function get_pages()
    {
        $pages = Post::where('post_type', 'page')->get();
        
        return $pages;
    }

    /**
     * This return single page record
     * @param  INT $page_id Page ID supplied by user
     * @return Object Object of pages records
     */
    public static function get_page( $page_id )
    {
        if( empty( $page_id ) )
            return;

        $page = Post::where('id', $page_id)->first();
        
        return $page;
    }

    /**
     * Return all category if any otherwise false
     */
    public static function get_categories() {

        $categories = Category::get();
           
        if( $categories )
            return $categories;

        return false;
    }

    /**
     * Return category data
     */
    public static function get_category( $category_id ) {

        if( empty( $category_id ) )
            return;
        
        $category = Category::where('id', $category_id)->first();
        
        return $category;
    }

    /**
     * Get lists of comments
     */ 
    public static function get_comments( $post_id, $args = array() )
    {
        if( empty( $post_id ) )
            return;

        $args = array_merge( $args, array(
            'comment_approved'  => 1,
            'order'             => 'desc',
            'orderby'           => 'created_at'
        ) );

        $comments = Comment::where('post_id', $post_id)
                        ->where('comment_approved', $args['comment_approved'])
                        ->orderBy($args['orderby'], $args['order'])
                        ->get();

        if( $comments )
            return self::get_comments_markup( $comments );

        return false;
    }

    /**
     * Display comment markup
     */
    public static function get_comments_markup( $comments )
    {
        ob_start();

        if( $comments->count() ) {
            ?>
            <ul>
                <?php foreach( $comments as $comment ) { ?>
                    <li>
                        <a rel="nofollow" target="_blank" href="<?php echo urlencode( $comment->comment_author_url ); ?>"><?php echo $comment->comment_author; ?></a>
                        
                        <div class="comment-body">
                            <?php echo $comment->comment_content; ?>
                        </div>
                    </li>
                <?php } ?>
            </ul>
            <?php
        } else {
            echo "Be the first to comment.";
        }

        return ob_get_clean();
    }
}

config/app.php

Laravel offer a way where we can create an alias for our Class, woah super handy, and it’s under app.php file, open the file and scroll down below where the aliases is hosted, code 'aliases' => [...],, that’s an array of added aliases including the Laravel defaults one, to create alias for Helper add the below code.


'Helper' => App\Helpers\Helper::class,

That’s it and happy coding ^_^, see ya in the next part

Advertisement