
In previous part of this tutorial we start building the app database and authentication, in this part we will create the resource controllers that will handle the crud of our application.
As we talking about single page application, the controllers must return a json response so we will utilize using laravel resourceful controllers so we will create a resource controller for each module, laravel supports the resource controllers simply append –resource option after the make controller artisan command like this:
php artisan make:controller CategoryController --resource php artisan make:controller TagsController --resource php artisan make:controller PostsController --resource php artisan make:controller CommentsController --resource php artisan make:controller UsersController --resource
Category Controller
Open app/Http/Controllers/CategoryController.php and update it as follows:
<?php namespace App\Http\Controllers; use App\Category; use App\Lib\Helper; use Illuminate\Http\Request; class CategoryController extends Controller { use Helper; public function __construct() { $this->middleware('auth:api')->only(['store', 'update', 'destroy']); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { if($request->input('all')) { $categories = Category::orderBy('id', 'DESC')->get(); } else { $categories = Category::paginate(10); } return response()->json(['data' => $categories], 200); } /** * 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) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $this->validate($request, [ 'title' => 'required' ]); $category = new Category(); $category->title = $request->input('title'); $category->slug = $this->slugify($category->title); $category->save(); return response()->json(['data' => $category, 'message' => 'Created successfully'], 201); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { $category = Category::findOrFail($id); return response()->json(['data' => $category], 200); } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $category = Category::findOrFail($id); $this->validate($request, [ 'title' => 'required' ]); $category->title = $request->input('title'); $category->slug = $this->slugify($category->title); $category->save(); return response()->json(['data' => $category, 'message' => 'Updated successfully'], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $category = Category::findOrFail($id); $category->delete(); return response()->json(['message' => 'Deleted successfully'], 200); } }
app/Lib/Helper.php
<?php namespace App\Lib; trait Helper { public function slugify($string) { return str_replace(array(" ", '_', '-', ',','#', '$', '&', '@', '*', '^', '"', "'"), '-', $string); } }
Â
Tags Controller
app/Http/Controllers/TagsController.php
<?php namespace App\Http\Controllers; use App\Tag; use Illuminate\Http\Request; class TagsController extends Controller { public function __construct() { $this->middleware('auth:api')->only(['store', 'update', 'destroy']); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { if($request->input('all')) { $tags = Tag::all(); } else { $tags = Tag::paginate(10); } return response()->json(['data' => $tags], 200); } /** * 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) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $this->validate($request, [ 'title' => 'required' ]); $tag = new Tag(); $tag->title = $request->input('title'); $tag->save(); return response()->json(['data' => $tag, 'message' => 'Created successfully'], 201); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { $tag = Tag::findOrFail($id); return response()->json(['data' => $tag], 200); } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $tag = Tag::findOrFail($id); $this->validate($request, [ 'title' => 'required' ]); $tag->title = $request->input('title'); $tag->save(); return response()->json(['data' => $tag, 'message' => 'Updated successfully'], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $tag = Tag::findOrFail($id); $tag->delete(); return response()->json(['message' => 'Deleted successfully'], 200); } }
Posts Controller
app/Http/Controllers/PostsController.php
<?php namespace App\Http\Controllers; use App\Lib\Helper; use App\Post; use Illuminate\Http\Request; class PostsController extends Controller { use Helper; public function __construct() { $this->middleware('auth:api')->only(['store', 'update', 'destroy']); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { if($request->input('recent')) { // in case of recent posts in website homepage $posts = Post::with('category', 'user', 'tags')->where('published', 1)->orderBy('id', 'DESC')->limit(7)->get(); } else if($request->input('category')) { // in case of posts per category page $posts = Post::with('category', 'user', 'tags')->whereHas('category', function ($query) use ($request) { $query->where('id', $request->input('category')); })->where('published', 1)->orderBy('id', 'DESC')->paginate(10); } else if($request->input('tag')) { // in case of posts per tag page $posts = Post::with('category', 'user', 'tags')->whereHas('tags', function ($query) use ($request) { $query->where('id', $request->input('tag')); })->where('published', 1)->orderBy('id', 'DESC')->paginate(10); } else { // the default case for the admin posts $posts = Post::with('category', 'user', 'tags')->orderBy('id', 'DESC')->paginate(10); } return response()->json(['data' => $posts], 200); } /** * 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) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $this->validate($request, [ 'title' => 'required', 'content' => 'required', 'image' => 'required', 'category_id' => 'required' ]); $post = new Post(); $post->title = $request->input('title'); $post->slug = $this->slugify($post->title); $post->content = $request->input('content'); $post->published = $request->input('published'); $post->category_id = $request->input('category_id'); $post->user_id = auth("api")->user()->id; if($request->hasFile('image')) { $file = $request->file('image'); $filename = time().'-'.uniqid().'.'.$file->getClientOriginalExtension(); $file->move(public_path('uploads'), $filename); $post->image = $filename; } $post->save(); // store tags if($request->has('tags')) { $post->tags()->sync($request->input('tags')); } $post = Post::with('tags')->find($post->id); return response()->json(['data' => $post, 'message' => 'Created successfully'], 201); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { $post = Post::with('category', 'user', 'tags', 'comments', 'approvedComments')->findOrFail($id); $post->prev_post = Post::where('id', '<', $id)->orderBy('id', 'desc')->first(); $post->next_post = Post::where('id', '>', $id)->first(); return response()->json(['data' => $post], 200); } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $post = Post::with('tags')->findOrFail($id); $rules = [ 'title' => 'required', 'content' => 'required', 'category_id' => 'required', 'published' => 'required' ]; if($post->image == "" || ($post->image != "" && !\File::exists('uploads/' . $post->image))) { $rules['image'] = 'required'; } $this->validate($request, $rules); $post->title = $request->input('title'); $post->slug = $this->slugify($post->title); $post->content = $request->input('content'); $post->published = $request->input('published'); $post->category_id = $request->input('category_id'); if($request->hasFile('image')) { // remove image $this->removeImage($post); $file = $request->file('image'); $filename = time().'-'.uniqid().'.'.$file->getClientOriginalExtension(); $file->move(public_path('uploads'), $filename); $post->image = $filename; } $post->save(); // remove tags foreach ($post->tags as $tag) { $post->tags()->detach($tag->id); } // store tags if($request->has('tags')) { $post->tags()->sync($request->input('tags')); } return response()->json(['data' => $post, 'message' => 'Updated successfully'], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $post = Post::findOrFail($id); // remove image $this->removeImage($post); $post->delete(); return response()->json(['message' => 'Deleted successfully'], 200); } private function removeImage($post) { if($post->image != "" && !\File::exists('uploads/' . $post->image)) { @unlink(public_path('uploads/' . $post->image)); } } }
In the above code the index method return all posts or posts for specific category. The store() and update() methods creates or updates specific post respectively. For the post tags i use laravel sync() method which used to save many to many relationships by accepting an array of ids in this case tags can be an array like this [1,2,3]. Also for uploading post photo make a writable uploads/ directory inside of public/ directory.
Comments Controller
app/Http/Controllers/CommentsController.php
<?php namespace App\Http\Controllers; use App\Comment; use App\Lib\Helper; use Illuminate\Http\Request; class CommentsController extends Controller { use Helper; public function __construct() { $this->middleware('auth:api')->only(['store', 'update', 'destroy']); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { if($request->input('post_id')) { $comments = Comment::with('user', 'post') ->where('approved', 1) ->where('post_id', $request->input('post_id')) ->paginate(10); } else { $comments = Comment::with('user', 'post')->orderBy('id', 'DESC')->paginate(10); } return response()->json(['data' => $comments], 200); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $this->validate($request, [ 'post_id' => 'required', 'comment' => 'required' ]); $comment = new Comment(); $comment->user_id = auth()->user()->id; $comment->post_id = $request->post_id; $comment->comment = $request->comment; $comment->save(); return response()->json(['data' => $comment, 'message' => 'Comment created successfully! we will review and publish it soon'], 201); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { $comment = Comment::with('user', 'post')->findOrFail($id); return response()->json(['data' => $comment], 200); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $comment = Comment::with('user', 'post')->findOrFail($id); if($request->has('comment')) { $this->validate($request, [ 'comment' => 'required' ]); } if($request->has('comment')) { $comment->comment = $request->comment; } if(isset($request->approved)) { $comment->approved = $request->approved; } $comment->save(); return response()->json(['data' => $comment, 'message' => 'Updated successfully'], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } Comment::findOrFail($id)->delete(); return response()->json(['message' => 'Deleted successfully'], 200); } }
The comments controller enable us to view and add comments to posts, so in the index() method i made a check if there is post_id parameter passed along with the request then we fetch the approved comments for that post otherwise we list all comments. The store, update and destroy methods are self explanatory.
Users Controller
app/Http/Controllers/UsersController.php
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; class UsersController extends Controller { public function __construct() { $this->middleware("auth:api"); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $users = User::paginate(10); return response()->json(['data' => $users], 200); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $this->validate($request, [ 'name' => 'required|unique:users', 'email' => 'required|email|unique:users', 'password' => 'required|min:6', ]); $user = new User(); $user->name = $request->name; $user->email = $request->email; $user->password = bcrypt($request->password); if($request->has('is_admin') && $request->is_admin == 1) { $user->is_admin = 1; } $user->save(); return response()->json(['data' => $user, 'message' => 'Created successfully'], 201); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $user = User::findOrFail($id); return response()->json(['data' => $user], 200); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } $user = User::findOrFail($id); $this->validate($request, [ 'name' => 'required|unique:users,name,'.$user->id, 'email' => 'required|email|unique:users,email,'.$user->id, 'password' => ($request->password!=''?'min:6':''), ]); $user->name = $request->name; $user->email = $request->email; if($request->has('password') && !empty($request->password)) { $user->password = bcrypt($request->password); } if($request->has('is_admin') && $request->is_admin == 1) { $user->is_admin = 1; } else { $user->is_admin = 0; } $user->save(); return response()->json(['data' => $user, 'message' => 'Updated successfully'], 200); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { if(!auth("api")->user()->is_admin) { return response()->json(['message' => 'Unauthorize'], 500); } User::find($id)->delete(); return response()->json(['message' => 'Deleted successfully'], 200); } /** * view user profile * * @return \Illuminate\Http\JsonResponse */ public function profile() { return response()->json(['data' => auth()->user()], 200); } }
In the above code the users controller is limited to admin only so i added a simple check to prevent unauthorized users to view or add users by checking for is_admin flag. The is_admin flag is added to users table in previous lesson of this tutorial. I have added a new method profile() which retrieves the profile data for the current authenticated user.
Updating Routes
Let’s open routes/api.php and update it with the following contents:
<?php use Illuminate\Http\Request; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); Route::post('login', 'Auth\\LoginController@login')->name('login'); Route::post('register', 'Auth\\RegisterController@register')->name('register'); Route::get('logout', 'Auth\\LoginController@logout')->name('logout'); Route::get('check-auth', 'Auth\\LoginController@checkAuth')->name('logout'); Route::resource('categories', 'CategoryController'); Route::resource('posts', 'PostsController'); Route::resource('tags', 'TagsController'); Route::resource('comments', 'CommentsController'); Route::get('profile', 'UsersController@profile'); Route::resource('users', 'UsersController');
Now you can experiment with these routes in any restful client, i prefer using postman client and try to register and login then add posts, comments , tags. In the next tutorial we will begin handling the client side using Reactjs.
Continue to part3: Begin Reactjs
Thanks for sharing information. keep sharing
Thanks