How to Create a Blog with Laravel 5+ Part 7 (CRUD Comment & Helper) Final Part
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%"> </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.
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