Iftikhar uddin Iftikhar uddin - 3 months ago 7
PHP Question

Laravel Associate method is returning empty array in the view

I am working on a simple social network, i am working on the replies section now. I associated the post/status model with user as below, but when i tried to access in the view it returns empty array

[]
.

Reply function in Post Model

public function postReply(Request $request, $statusId){
$this->validate($request, [
"reply-{$statusId}" => 'required|max:1000',
],
[
'required' => 'The reply body is required'
]
);

$post = Post::notReply()->find($statusId);
if(!$post){
return redirect('/');
}

if(!Auth::user()->isFriendsWith($post->user) && Auth::user()->id !== $post->user->id){
return redirect('/');
}

$post = Post::create([
'body' => $request->input("reply-{$statusId}"),
]);
$post->user()->associate(Auth::user());
$post->replies()->save($post);


return redirect()->back();
}


Post Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
protected $table = 'posts';
protected $fillable = ['body'];
public function user(){
return $this->belongsTo('App\User');
}

public function likes(){
return $this->hasMany('App\Like');
}

public function scopeNotReply($query){
return $query->whereNull('parent_id');
}

public function replies(){
return $this->hasMany('App\Post', 'parent_id');
}
}


Posts Table

enter image description here

View Where i am accessing the Replies via $post->replies

<section class="row new-post">
<div class="col-md-6 col-md-offset-3">
<header><h3>What do you have to say?</h3></header>
<form action="{{ url('createpost') }}" method="post">
<div class="form-group">
<textarea class="form-control" name="body" id="new-post" rows="5" placeholder="Your Post"></textarea>
</div>
<button type="submit" class="btn btn-primary">Create Post</button>
<input type="hidden" value="{{ Session::token() }}" name="_token">
</form>
</div>
</section>
<section class="row posts">
<div class="col-md-6 col-md-offset-3">
<header><h3>What other people say...</h3></header>
@foreach($posts as $post)
<article class="post media" data-postid="{{ $post->id }}">
<a class="pull-left" href="{{ url('user', $post->user->username) }}">
<img class="media-object" alt="" src="{{ $post->user->getAvatarUrl() }}">
</a>
<div class="media-body">
<h4 class="media-heading"><a href="{{ url('user', $post->user->username) }}"> {{ $post->user->username }}</a></h4>
<p>{{ $post->body }}</p>
<ul class="list-inline">
<li>{{ $post->created_at->diffForHumans() }}</li>
<li><a href="#">Like</a></li>
<li>10 likes</li>
</ul>
{{ $post->replies }}

</div>

<form role="form" action="{{ url('createpost', $post->id )}}" method="post">
<div class="form-group{{ $errors->has("reply-{$post->id}") ? ' has-error': '' }}">
<textarea name="reply-{{ $post->id }}" class="form-control" rows="2" placeholder="Reply to this status"></textarea>
@if($errors->has("reply-{$post->id}"))
<span class="help-block">{{ $errors->first("reply-{$post->id}") }} </span>
@endif
</div>
<input type="submit" value="Reply" class="btn btn-default btn-sm">
<input type="hidden" name="_token" value="{{ Session::token() }}">
</form>

</article>

@endforeach

</div>

</section>


PS : I am using one table for the relationship i.e posts and in posts table there is a column name
parent_id
via which i am linking the relationship to the table with itself.

{{ $post->replies }}
returns empty array. By logic it should return the replies of comment related to the replies .

If any thing else is needed, just mention i will share.

UPDATE : Note that the all the replies the user comment is stored in the database table posts with unique id i.e
parent_id
The only thing is that when i try to access it it returns empty array.

Answer

It seems like your are not attaching the replies to your $post variable while passing it to your view.
We have to use with() method to join these two tables.
Try, the following :

if(Auth::check()){ 
            $posts = Post::notReply()
                    ->where(function($query){ 
                        return $query->where('user_id', Auth::user()->id)
                                ->orWhereIn('user_id', Auth::user()->friends()->lists('id'));
                    })
                    ->with('replies')//Here we are joining the replies to the post
                    ->orderBy('created_at', 'desc')
                    ->get();
                    return view('timeline.index', compact('posts')); 
                }

Now, in your View you would need to use 2 foreach loop like below:

@foreach($posts as $post)
    {{--Your Code --}}
    @foreach($post->replies as $reply)
        {{--Your Code --}}
    @endforeach
    {{--Your Code --}}
@endforeach

Update:

Problem is with the postReply() method. In old code you were overriding the $post variable, due to which the reply was getting parent_id as its own id.
So, replace your old code with using $reply variable.
old:

$post= Post::create([
   'body' => $request->input("reply-{$statusId}"),
]);
$post->user()->associate(Auth::user());
$post->replies()->save($post);

new:

$reply = Post::create([
   'body' => $request->input("reply-{$statusId}"),
]);
$post->user()->associate(Auth::user());
$post->replies()->save($reply);