Loop through relationships Laravel - laravel

Stackoverflow,
What I want to accomplish:
I want to Loop through the database to find all the (Heroes) with their related (Interview). I want to also pull each Interview with it's related (Story) and (Image). So far I can dd($heroes) and I can see the array correctly grab each hero with their interview and each interview has it's associated image and story. How do I loop through this correctly?
Error
Invalid argument supplied for foreach() (View: /Users/plastics1509moore/Desktop/elephant_gin/resources/views/administration/index.blade.php)
This is what I have done:
Controller:
$heroes = Hero::with('Interview', 'Interview.stories', 'Interview.images')->orderBy('position', 'asc')->get();
Model Relationships:
Hero:
public function Interview()
{
return $this->hasOne('App\Interview', 'heroInt_id');
}
Interview:
public function relationships()
{
return $this->belongsTo('App\Hero');
}
public function stories()
{
return $this->hasMany('App\InterviewStory');
}
public function images()
{
return $this->hasMany('App\InterviewImage');
}
InterviewImage:
public function relationships()
{
return $this->belongsTo('App\Interview');
}
InterviewStory
public function relationships()
{
return $this->belongsTo('App\Interview');
}
Html:
Loop:
#foreach($heroes as $hero)
#foreach($hero->Interview as $story)
<div>{{$story->id}}</div>
#endforeach
#endforeach

You can't loop on Interview because this a hasOne relationship. What you might want to do is
#foreach($heroes as $hero)
#foreach($hero->interview->stories as $story)
<div>{{$story->id}}</div>
#endforeach
#endforeach

I think your problem is because not following laravel "assumes". In documentation:
Additionally, Eloquent assumes that the foreign key should have a
value matching the id column of the parent. In other words, Eloquent
will look for the value of the user's id column in the user_id column
of the Phone record. If you would like the relationship to use a value
other than id, you may pass a third argument to the hasOne method
specifying your custom key:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
What is the id of Hero? If it's different than id, then you have to add the local_key name.

Related

Get the ID of the first parent

I have three models that are related: Article, ArticleBlock, ArticleBlockImage
ArticleBlock is related with Article and ArticleBlockImage is related with ArticleBlock
Here are the relations
Article
public function article_blocks()
{
return $this->hasMany('App\Models\ArticleBlock');
}
ArticleBlock
public function article()
{
return $this->belongsTo('App\Models\Article');
}
public function article_block_images()
{
return $this->hasMany('App\Models\ArticleBlockImage');
}
ArticleBlockImage
public function article_block()
{
return $this->belongsTo('App\Models\ArticleBlock');
}
Further in the ArticleBlockImage model I have one function with which I need to get the ID of the current Article in the form of type $article->id
I am trying to do something like this, but I get the error
$article = article_block_images()->article_block()->article()->get();
"message": "Call to undefined function App\Models\article_block_images()",
$article = articleBlockImages()->article_block()->article()->get();
when you load your relation this way you load the relation type class, not the database records, relation classes like (HasMany, HasOne ...)
to get article_id you can a function like this:
public function article_id()
{
return $this->article_block->article_id; // without brackets
}
You wrote that ArticleBlock is related to Article and to ArticleBlockImage. Then you have the related Article ID inside the ArticleBlock.
That means if you have the ArticleBlockImage $articleBlockImage then you can write:
$articleId = $articleBlockImage->article_block()->article_id;

get posts where relationship count is equel to post's attribute

I have a model "Post" which has a field "daily" in the database.
$table->integer('daily'); // could be anything
The Model "Post" has a relationship to the model "Comments".
public function comments() {
return $this->hasMany(Comment::class);
}
public function completed() {
return $this->hasMany(Comment::class)->completed();
}
Comments model
public function scopeCompleted($query) {
return $query->....?
}
I want to get all user's posts where it's comments count are equal to the post's 'daily' field. For example: if the post's daily field is '5' and there are 5 comments to this posts, I want to see this post in the returned lists, otherwise don't return it.
I know I can get all of them and do it with loop, but I wanna know if there is any way to do this with eloquent only.
Try this
$user=User::with('posts','posts.comments')
->whereHas('posts.comments',function ($query){
//if any additional filters
},'=',DB::raw('posts.daily'))
->get();
or if not needed additional query then
$user=User::with('posts','posts.comments')
->whereHas('posts.comments',null,'=',DB::raw('posts.daily'))
->get();
Got it working like this
public function scopeCompleted($query) {
return $query->has('comments', '=', DB::raw('posts.comments'));
}

How to display the name of the user instead of id. Laravel

Hello as the title says I'm not sure why my code is not showing the "First Name" for a user but it shows the ID only I have tried to do a lot of different methods to solve this but I'm rather a beginner in laravel so I thought It would be best if I asked for help by now
To explain a little the field "recieverID" is a foreign key of the table Users that shows the ID of the users
So here is the model named "Remark"
class Remark extends Model
{
protected $guarded =[];
public function user(){
return $this->belongsTo(User::class);
}
}
This is the Remark Controller
public function index()
{
if(Auth::guard('admin')->check())
{
$users = User::all();
$remarks = Remark::latest()->get();
return view('admin.remark.index', compact('users'),compact('remarks'));
}
It has more code under it but I only need it for this part, I added the $users and compact users because I tried to add 2 foreach loops on the view to see how it looks but it didn't quite work as i thought it might
This is the view I want to show the Name instead of the ID
#foreach($remarks as $remark)
<tr>
<td>{{$remark->recieverID->user->first_name}}</td>
<td>{{$remark->title}}</td>
<td>{{$remark->subject}}</td>
<td>{{$remark->message}}</td>
<td>{{$remark->sender}}</td>
</tr>
#endforeach
Thank you for your time
First of all, you need to change your relationship as below. If you don't pass foreign key then it assumes that you have foreign key as(user_id) in the table. but you have recieverID in the table. So, you need to define it.
public function user(){
return $this->belongsTo(User::class,'recieverID','id');
}
Now you can add it blade file.
<td>{{$remark->user->first_name}}</td>

Laravel Relationships - Select rows with same column value in blade

Let's say I have a post with many comments and I properly defined $post->comments relation in my post model. Comments have a column named confirmed with the value of 0 or 1. How can I select confirmed (rows which have confirmed value of 1) rows in my blade template?
This can help you
In your Post model
public function comments()
{
return $this->hasMany(Comment:class);
}
public function confirmedComments()
{
return $this->comments()->whereConfirmed(1);
}
And from your controller
$comments = $post->confirmedComments;
If in blade, you want select confirmed comments, it's so easy to do it with
#if($comment->confirmed)
//confirmed comment
#else
//
#endif
Hope it'll be helpful !
There are many ways to do this.
If you already have the comments eager loaded, then you can use the where() method on the comments collection:
$confirmedComments = $post->comments->where('confirmed', 1);
This will go through all the comments in the collection and only return those that are confirmed.
If you don't have the existing collection, you can add the where clause to the relationship query. This way, you're only getting confirmed comments from the database, and you're not wasting resources retrieving and building models for comments you're not using
$confirmedComments = $post->comments()->where('confirmed', 1)->get();
And, another option, would be to create a new relationship for just confirmed comments, and that way you can eager load the new relationship:
public function comments()
{
return $this->hasMany(Comments::class);
}
public function confirmedComments()
{
return $this->comments()->where('confirmed', 1);
}
$confirmedComments = $post->confirmedComments;

Nested Eager loading relationships in Laravel

I am creating a forum software using Laravel and I'm trying to access the most recent posts made within a specific topic using latestPost as defined in my model below
public function latestPost() {
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
}
Here is how the nested relationships are defined in App\Post.php
public function author()
{
return $this->belongsTo('App\User', 'author_id');
}
public function thread()
{
return $this->belongsTo('App\Thread', 'thread_id');
}
public function topic() {
return $this->belongsTo('App\Topic');
}
I have been able to access posts of threads, authors etc no problem, and when I have {{ $topic->latestPost }} in my views, it will list the object including relationships successfully. But as soon as I try to display a specific part such as {{ $topic->latestPost->author->username }} I am getting the following error: Trying to get property of non-object
In this specific view, topics is yet another relationship pulled from Categories like so in the Controller and getting $topics using a #foreach on $categories->topics:
public function index() {
$categories = Category::orderBy('order', 'asc')->get();
return view('welcome', compact('categories'));
}
Here is a dump of $categories: http://dumptext.com/H8Nq16ea
Maybe you want to use nested eager loading.
Change: return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
To this: return $this->hasOne('App\Post')->with('thread.author')->latest();
Also i never heard about latest() and the end of your return statement. Maybe you can try it with orderBy as shown below.
`return $this->hasOne('App\Post')->with('thread.author')->orderBy('id')->first;`
I guess you can use the orderBy('id')->reverse() function if the result is not in the order you want. Let me know if it helped you out.
You should make sure you have author for latest post you want to display. Otherwise if you expect not to have one for each record, you should try:
{{ $topic->latestPost->author ? $topic->latestPost->author->username : 'No author' }}
In addition instead of:
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
you can use
return $this->hasOne('App\Post')->with('thread','author')->latest();

Resources