ralphdns's avatar

am working on reply to comments to my posts in my blog. but its not woking out

when i submit reply, database is is updated, but i keep getting this error that doesnt allow my route view: "Undefined variable: post"

see my PostsController@reply


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;
use App\Comment;
use App\Reply;

class PostsController extends Controller
{

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth', ['except' => ['index', 'show']]);//for restrictions, mk sure u logout b4 testing this function 
    }                                   


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::orderBy('created_at', 'desc')->paginate(12);
        return view('posts.index')->with('posts', $posts);
        
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('posts.create');//returns the create form whose values are sent to the store mtd for validation and transfer to the database
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //validate inputs, b4 instantiating the DB
        $this->validate($request, [
            'title' => 'required',
            'body' => 'required'
        ]);
        //Create Post
        $post = new Post;//snc we are doing sometin new
        //getting the input fields
        $post->title = $request->input('title');
        $post->body = $request->input('body');
        //though nt frm the form, with auth, we can get any input from the users table
        $post->user_id = auth()->user()->id;
        //save to the DB, using the save function
        $post->save();

        //redirect to the posts-index view, with message(success)
        return redirect('/posts')->with('success', 'Post Created');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);
        return view('posts.show')->with('post', $post);
    }

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

        //check for correct user
        //if(auth()->user()->id !== $post->user_id) {
        //return redirect('/posts')->with('error', 'Unauthorized Page');
        //}
        return view('posts.edit')->with('post', $post);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
         //validate inputs, b4 instantiating the DB
         $this->validate($request, [
            'title' => 'required',
            'body' => 'required'
        ]);
        //Update Post
        $post = Post::find($id);//snc we are doing sometin new
        //getting the input fields
        $post->title = $request->input('title');
        $post->body = $request->input('body');
        //save to the DB, using the save function
        $post->save();

        //redirect to the posts-index view, with message(success)
        return redirect('/posts')->with('success', 'Post Updated');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $post = Post::find($id);
        $post->delete(); 

        return redirect('/posts')->with('success', 'Post Removed');
    }


    //COMMENT
    public function comment(Request $request, $post_id){
        //validate inputs, b4 instantiating the DB
        $this->validate($request, [
            'comment_name' => 'required|max:255',
            'comment_email' => 'required',
            'comment_content' => 'required|min:5|max:2000'
        ]);

        // findOrFail will throw an exception if it cannot find the post
        $post = Post::findOrFail($post_id);
        //Create Post   <--- no you're not, you got it from the DB

        $comment = new Comment;//snc we are doing sometin new
        //getting the input fields
        $comment->comment_name = $request->input('comment_name');
        $comment->comment_email = $request->input('comment_email');
        $comment->comment_content = $request->input('comment_content');
        $comment->post_id = $post->id;  //you can manually relate it to the $post
        $comment->approved = true;

        $comment->save();
        
        //so return to same page, with same id. recall to update the route(web.php) wit an id as well
        return redirect(route('posts.show',$comment->id))->with('success', 'Comment updated');
        
       }

       //REPLY
    public function reply(Request $request, $comment_id){
       
        $this->validate($request, [
            'reply_content' => 'required|max:255'
        ]);

        // findOrFail will throw an exception if it cannot find the post
        $comment = Comment::findOrFail($comment_id);

        $reply = new Reply;//snc we are doing sometin new
        //getting the input fields
        $reply->reply_content = $request->input('reply_content');
        $reply->comment_id = $comment->id;  //you can manually relate it to the $post

        $reply->save();
        
        //so return to same page, with same id. recall to update the route(web.php) wit an id as well
        return redirect(route('posts.show',$comment->id,$post->id))->with('success', 'Reply submitted');
        

    }
}

see my show view, where i built the reply form, and where i want the success message and replies to be viewed:


@section('content')
    <ul class="list-group"> 
        <!--here we dont need to loop, snc we are only returning one post-->  
            <li class="list-group-item">
                    <div id="box_post">
                        <h1>{{$post->title}}</h1>
                        <p>{!!$post->body!!}</p>
                    <small>Created on {{$post->created_at}}, by {{$post->user->name}}</small>
                    
                    <hr>
                     <br>   

                   {{--   displaying the comments from the db --}}
                    <div class="row">
                        <div class="col-md-8 col-md-offset-2">
                            <h2>Comments</h2>
                            @foreach($post->comments as $comment)
                               Created: <strong>{{ $comment->created_at->diffForHumans() }}</strong>
                                <p class="panel"><strong>Name:</strong> {{$comment->comment_name}} {{-- by {{ $comment->post->user->name }} --}}</p>
                                <p class="panel"><strong>Comment:</strong> {{$comment->comment_content}}</p>
                                {{-- <a href="/posts/{{$post->id}}/edit" class="btn btn-success float-right">Replies</a><br> --}}
                                
                                <div class="reply_btn float-right btn btn-success">Replies</div>
                                    <div class="replies" style="display:none;">

                                        {{-- later, this will be wrapped in another foreach loop, so js control --}} 
                                        {{ Form::open(['action' => ['PostsController@reply', $comment->id], 'method' => 'POST']) }}
                                           
                                            {{ Form::textarea('reply_content', null, ['class' => 'form-control', 'rows' => '5', 'placeholder' => 'begin to reply here...']) }}
                                            
                                            {{ Form::submit('Submit', ['class' => 'btn btn-success btn-block']) }}
                                        {{ Form::close() }}
                                    </div>
                                <hr>
                               
                            @endforeach

                        </div>
                    </div>
                   {{--  Step 1 Comments form section  --}}  
                    <hr>
                        <div class="row">
                            <div id="comment-form" class="col-md-8 col-md-offset-2">
                                {{ Form::open(['action' => ['PostsController@comment', $post->id], 'method' => 'POST']) }}
                                    <div class="row">
                                        <div class="col-md-6">
                                            {{ Form::label('name', "Name") }}
                                            {{ Form::text('comment_name', null, ['class' => 'form-control']) }}
                                        </div>

                                        <div class="col-md-6">
                                            {{ Form::label('email', 'Email') }}
                                            {{ Form::text('comment_email', null, ['class' => 'form-control']) }}
                                        </div>

                                        <div class="col-md-12">
                                            {{ Form::label('comment', 'Comments...') }}
                                            {{ Form::textarea('comment_content', null, ['class' => 'form-control', 'rows' => '5']) }}

                                            {{ Form::submit('Add Comments', ['class' => 'btn btn-success btn-block']) }}
                                        </div>
                                    </div>
                                
                                {{ Form::close() }}
                        
                            </div>
                        </div>{{-- end of comment form --}}
                    </div>

                    

                    <hr>
                @if(!Auth::guest())
                    <a href="/posts/{{$post->id}}/edit" class="btn btn-danger">EDIT</a>
                    {!!Form::open(['action' => ['PostsController@destroy', $post->id], 'method' => 'POST', 'class' => 'float-right'])!!}
                        {{Form::hidden('_method', 'DELETE')}}
                        {{Form::submit('DELETE', ['class' => 'btn btn-primary confirm', 'data-confirm' => 'Are you sure you want to delete?'])}}
                    {!!Form::close()!!}
                @endif
            </li>
    </ul>
@endsection ```

see my route
```<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

/* Route::get('/', function () {
    return view('welcome');
}); */
Route::get('/', 'PagesController@index');
Route::resource('posts', 'PostsController');


// or any other url
Route::post('/comment/{id}', 'PostsController@comment');
Route::post('/reply/{id}', 'PostsController@reply');
//Route::get('/posts/{$id}', 'PostsController@comment');

Auth::routes();

Route::get('/dashboard', 'DashboardController@index');

Thanx alot

0 likes
8 replies
Thyrosis's avatar

Last line in your PostController:reply method

        return redirect(route('posts.show',$comment->id,$post->id))->with('success', 'Reply submitted');

You redirect to a route with a $post->id variable, but $post doesn't seem to be declared anywhere.

ralphdns's avatar

Thyrosis, should i remove the $post->id there, or how am i suppose to make 'posts' defined

Tray2's avatar
    public function reply(Request $request, $comment_id){
       
        $this->validate($request, [
            'reply_content' => 'required|max:255'
        ]);

        // findOrFail will throw an exception if it cannot find the post
        $comment = Comment::findOrFail($comment_id);

        $reply = new Reply;//snc we are doing sometin new
        //getting the input fields
        $reply->reply_content = $request->input('reply_content');
        $reply->comment_id = $comment->id;  //you can manually relate it to the $post

        $reply->save();
        
        //so return to same page, with same id. recall to update the route(web.php) wit an id as well
        return redirect(route('posts.show',$comment->id,$post->id))->with('success', 'Reply submitted');
        

    }

You never declare the $post yet you return it. You need to do this for your $post as well.

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

Another note is that you really should submit the $post_id and the $comment_id in your request instead of as an extra parameter.

Thyrosis's avatar

Afaik, the global route() function only accepts two parameters, the first one being the URL to redirect to and the second one any parameters that may be defined in the route.

The second parameter may be a single variable or an array. So if you actually need two parameters to the route, the redirect would look like this:

    return redirect(route('posts.show',['comment_id' => $comment->id, 'post_id' => $comment->post->id]))->with('success', 'Reply submitted');

I'm assuming there's a relationship between comment and post. If not, you could also replace $comment->post->id with $comment->post_id so that the ID is loaded from the comment object directly, instead of from the related post object.

// update: Also, as well as Tray2's recommendation to move the parameters to the request instead of the route, I'm wondering why you have these reply and comment methods stored in the PostController?

For simplicity's (and design patterns) sake, you're better off creating a dedicated CommentController and ReplyController. This way, you (and possibly other developers that will work on or take over your project) will always know which action is handled in which controller.

ralphdns's avatar

@Tray2 , so it means going over to my Reply migration model again, to add $post_id as a foriegn key? because even after I passed $post_id as a parameter, i get another error:"Too few arguments to function App\Http\Controllers\PostsController::reply(), 2 passed and exactly 3 expected"

Snapey's avatar
Snapey
Best Answer
Level 122

Post show is only set to need one parameter

    public function show($id)

but you are trying (unsuccessfully) to pass two

change the last line of reply to;

        return redirect(route('posts.show',$comment->post_id))->with('success', 'Reply submitted');
        

now you are returning to the post show route with the post ID which you got from the comment

ralphdns's avatar

thanks, @Snapey, i removed $post_id as a parameter in the method, then return redirect as u requested...now am happy! Moving forward, how can i work on reply to this reply, that is nested comments...pls hlep

Please or to participate in this conversation.