Laravel: Eloquent relationships with *where* on parent table instead of *find* - php

I have a table posts and posts_contents.
And I want to get a content from one post only if that post has display = 1.
(I need two separate tables because of language support)
posts:
id user_id display
1 2 0
2 2 1
3 2 0
4 2 1
posts_contents
id post_id lang_id name description
1 1 1 Hello World
2 2 1 Here Is What I wanna show!
3 3 1 Don't Show the others
4 4 1 Hey Display that one too
So in laravel I use eloquent relationships, but I just don't understand how to use it in that particular case. In the documentation I found only cases such as:
$p = App\Posts::find(1)->contents;
Which works great, however what I want is something like this:
$p = App\Posts::where('display',1)->contents;
But it doesn't work... So question is: what is the right way to do so?
Any help is appreciated, Thanks!
Update
I need to get multiple posts at once, not just one.

You want to use find() method like this:
$post = App\Posts::where('display', 1)->find($postId)->contents;
Then in a view for one-to-one relationship:
{{ $post->description }}
For one-to-many:
#foreach ($post->contents as $content)
{{ $content->description }}
#endforeach
If you want to load multiple posts with contents only for one language, use filtering by a language. Use with() to eager load contents:
$posts = App\Posts::where('display', 1)
->with(['contents' => function($q) use($langId) {
$q->where('lang_id', $langId);
}])
->get();
Then in a view for one-to-one:
#foreach ($posts as $post)
{{ $post->contents->description }}
#endforeach
For one-to-many:
#foreach ($posts as $post)
#foreach ($post->contents as $content)
{{ $content->description }}
#endforeach
#endforeach
You can read about the difference between find() and get() methods here.

App\Posts::where will return a collection. So if you only want 1 result you should use App\Posts::where('display',1)->first()->contents

You need to call the first method before you call any relationship:
$p = App\Posts::where('display', 1)->first()->contents;
Or, if you want to fetch a collection of posts, you can:
$posts = App\Posts::where('display', 1)->get();
$posts->each(function ($post) {
$post->contents;
});
Otherwise, you will just have a Query Builder object, without the actual results you want.

Related

create counter for blog categories in laravel

I´m traying to create one counter for my blog´s categories. This should appear to the right name side of my category . i´m using my model with variable appends, that after i will use in my blade for show my result in one span. But i don´t know very well how i can use count in my Model. I´m doing this in my model Blog.
my variable appends contain:
protected $appends = [
'custom_fields',
'has_media',
'restaurant',
'blog_category',
'viewer',
'postCounter',
];
i´m traying this:
return $this->blogs()->count();
i have a relation between blog and blog_category with:
public function blogCategory()
{
return $this->belongsTo(\App\Models\BlogCategory::class, 'blog_category_id', 'id');
}
i want to do in my view appear for example:
innovation (2)
in my view i´m doing this:
#foreach($categories as $category)
<li>{{ trans('web.blog_category_'.$category->name) }}<span>{{$category->postCounter}}</span></li>
#endforeach
but always returned me 0, and i have post with categories
updated
With laravel relationship withCount you can do this easily. If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
add withCount method to your query
$categories = Category::withCount('blogCategory')->get();
You can access the count in your foreach loop
// $category->blogCategory_count
#foreach($categories as $category)
<li>
<a href="{{ url('blogs/'.$category->name) }}">
{{trans('web.blog_category_'.$category->name) }}
</a>
<span>{{$category->blogCategory_count}}</span>
</li>
#endforeach

Laravel - Get additional column value from pivot table

I have Stores and Medicines tables with many to many relationship. Storing and updating work fine with attach and sync. The table structure is like below. I want to retrieve value of extra column (expired).
store_id | medicine_id | expired
1 2 1
1 3 0
Also I need to count total medicines which expired like this
Both models have withPivot('expired') model relation.
Controller
public function show($id)
{
$medicine = Medicine::findOrFail($id);
$stores = $medicine->findorfail($id)->stores()->get();
return view ('medicines', compact('medicine', 'stores'));
}
View
I can list medicines with this
#foreach ($stores as $store)
{{ $store->value('name') }}
{!! $store->pivot->expired == 1 ?
'Expired' : 'Not-Expired' !!}
View
#endforeach
I tried to count Cities like this:
#foreach($stores as $store)
{{ ($store->pivot->expired==1) }}
#endforeach
It gives 1 1. How can I count total cities with have expired Cetamols?
The following should work:
Sum on the relationship collection:
$stores->sum('pivot.expired');
Sum on the Query Builder:
Medicine::findOrFail($id)->stores()->sum('expired');
Also your controller code does not make much sense at the moment and could be simplified to this:
public function show($id)
{
$medicine = Medicine::findOrFail($id);
$stores = $medicine->stores;
return view('medicines', compact('medicine', 'stores'));
}
I removed the second call to findOrFail() and removed the get() since it is unnecessary.

Laravel Pass Comments with Posts

I have a One to Many relationship set up for my "announcements" having many "comments".
Currently, when my user loads up the app page, I have it send the 30 most recent announcements like such:
Route::get('/app', function () {
$posts = Announcement::take(30)->orderBy('id', 'desc')->get();
return View::make('app')->with([
//posts
'posts' => $posts,
//orders
'orders' => $orders
]);
}
When I echo out the announcements in blade using a foreach loop through the $posts object, I want to also echo out the comments for each post under the respective post.
Is it possible to pass the comments for a post as part of the actual post object? For example, it would be nice if I could do this:
#foreach ($posts as $post)
//echo out the post
{{$post->content}}
//echo out the comments relating to this post
{{$post->comments}}
#endforeach
#Amr Aly gave you the right answer, and I would like to add on top of it.
When you loop through your comments as he showed you (and you should), it will make a different query for each comment. SO if you have 50 comments, that's 50 more queries.
You can mitigate that by using eager loading
$posts = Announcement::with('comments')
->take(30)->orderBy('id', 'desc')
->get();
Then just loop the way he showed you. THis will limit the queries to 2 only. You can read more from the docs here: https://laravel.com/docs/5.4/eloquent-relationships#eager-loading
You can add another foreach for your comment like this:
#foreach ($posts as $post)
//echo out the post
#if($post->comments->count())
#foreach ($post->comments as $comment)
// {{ $comment }}
#endforeach
#endif
#endforeach

Laravel 5 - Count the number of posts that are assigned to each category in a blog

I was wondering what the cleanest way was to count the number of posts that are connected to a category in my blog.
Here is how the table relationship is set up.
What I have is a hasMany relationship from the Category to the Post models like this:
In Categories Model
public function blog_posts()
{
return $this->hasMany('App\Http\Models\Blog_Post', 'category_id');
}
And in the Blog_Post Model
public function blog_categories()
{
return $this->belongsTo('App\Http\Models\BlogCategories', 'category_id');
}
In effect all I want to do is be able to return to my view the total number of posts that each category has as shown below. Where x is the number of posts within each category.
cat1 (x)
cat2 (x)
cat3 (x)
It's not hard to count I know however as I only want a count I do not want to also retrieve the records as they are not required and I also do not want to create more queries than is necessary.
I have not completed the view as yet but probably a start would be to pass through the categories in a loop to display each and add the count at the same time?
#foreach ($categories as $category)
{!! $category->name !!} - {!! Count of posts here !!}
#endforeach
Hopefully that is clear(ish)!
Eager load the relation in your controller:
public function index()
{
$categories = Category::with('blog_posts')->get();
return view('categories.index', compact('categories'));
}
You can then use the count() method on the blog_posts relation when looping over categories in your view:
#foreach ($categories as $category)
<li>{{ $category->name }} ({{ $category->blog_posts->count() }})</li>
#endforeach
EDIT: Since Laravel 5.3, you can use withCount() to load counts of relations, i.e.
$categories = Category::withCount('blog_posts')->get();
This will make the count available via a property:
foreach ($categories as $category) {
$blog_posts_count = $category->blog_posts_count;
}
The nicest way to do it with eager loading support I know is to create a separate relation with the post count. Check this out:
public function blog_posts_count() {
return $this->hasOne('App\Http\Models\Blog_Post', 'category_id')
->selectRaw('category_id, count(*) as aggregate')
->groupBy('category_id');
}
public function getBlogPostsCountAttribute() {
if(!array_key_exists('blog_posts_count', $this->relations))
$this->load('blog_posts_count');
$related = $this->getRelation('blog_posts_count');
return $related ? (int) $related->aggregate : 0;
}
Usage is simple:
{{ $category->blog_posts_count }}

Sorting database results by category

I have a table in my database with the fields 'Category' and 'Title'. I have multiple records with the same category but other titles. What I'd like to do is print the category once on my page then show the all the titles with the same category.
So Something like this:
Category 1
Title 3(=newest)
Title 2
Title 1(=olddest)
Category 2
Title 1
Category 3
Title 3(=newest)
Title 2
Title 1(=olddest)
Im using the Laravel 4 framework with Eloquent. So I'm getting the result back as an JSON object.
What I have at the moment:
view
#foreach($photos as $photo)
{{$photo->Category}}
#foreach($photo as $category)
{{ $photo->Title }}
#endforeach
#endforeach
Controller
$photos = Photo::orderBy('Date')->get(); // Sort by so that newest photos come first per category
return View::make('myView')->with('photos', $photos);
When looking a bit further I came on to array_add helper but I'm not sure if I can use it and how I really should use it.
Can someone help me achieve the result I need?
You can do something like:
$photos = Photo::orderBy('category')->orderBy('created_at', 'desc')->get();
return View::make('myView')->with('photos', $photos);
Then
<?php $category = ''; ?>
#foreach($photos as $photo)
#if($category != $photo->Category)
{{$photo->Category}}
<?php $category = $photo->Category; ?>
#endif
{{ $photo->Title }}
#endforeach

Categories