Building a Blog With Reactjs And Laravel Controllers

Building a Blog With Reactjs And Laravel Part2: Controllers

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

 

5 1 vote
Article Rating
Share this: