Laravel - Get additional column value from pivot table - php

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.

Related

select few from one table and based on value fetch from another table

I have three tables:
Products
id
other values
Downloads
id
user_id
product_id
Users
id
name
I'd like to fetch last X Download table rows, get their product_id & user_id, product_id match Product table as user_id match User table, then make
foreach ($values as $value) {
<div class="product_title"> {{$product->name}} </div>
<div class="who_downloaded"> {{$user->name}} </div>
}
I can pass in my controller Download model, but it doesn't get me anywhere close
public function index() {
return view('nav/index', [
'trendings' => Template::orderBy('views', 'DESC')->where('is_active', 'yes')->take(8)->get(),
'latests_downloads' => Downloads::orderBy('id', 'DESC')->take(8)->get(),
]);
}
'latests_downloads' => Downloads::orderBy('id', 'DESC')->take(8)->get() function just gives me:
id
user_id
product_id
1
7
10
2
9
2
3
45
86
4
88
85
5
5
2
6
7
7
7
5
5
8
9
6
But how can I take these values and put in view?
Add the following methods to your Download model class (If they don't already exist.)
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
Change your controller.
'latests_downloads' => Downloads::orderBy('id', 'DESC')->take(8)->get(),
// replace with the following
'latests_downloads' => Downloads::with(['user', 'product'])->orderBy('id', 'DESC')->take(8)->get(),
Fetch it in your view file.
#foreach($latest_downloads as $latest_download)
User Id: {{ $latest_download->user->id }}
Product Id: {{ $latest_download->product->id }}
#endforeach
Yes for this type of scenario you need to use a relationship-based Eloquent model query of Laravel and it is very powerful for this type of scenario.
First You need to add two relationships in the Download model :
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
And rest of the things work well with this single query.
// user this query
$latest_downloads = Downloads::with(['user', 'product'])->latest()->take(8)->get();
instead of => getting two different queries in two different variables.
You only need to get a single collection of records in a minimum query and a minimum number of variables. You can do it with Eloquent easily.
And last you can use inside blade as like normal we use daily.
#foreach($latest_downloads as $key => $latest_download)
User ID: {{ $latest_download->user->id ?? '' }}
Product ID: {{ $latest_download->product->id ?? '' }}
#endforeach

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

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.

laravel5.1 retrieve nested relation using eloquent hasOne() (one to one relation)

My table design is:
users: | id |username | ... |
tickets: | id | supp_id | ... |
ticket_replies: | id | ticket_id | user_id |
My controllers look like:
user:
public function tickets()
{
return $this->hasMany('App\ticket');
}
ticket:
public function ticket_replie()
{
return $this->hasMany('App\ticket_replie');
}
public function supporter()
{
return $this->hasOne('App\User', 'id','supp_id');
}
My controller looks like this:
$tickets = Auth::user()->tickets()->orderBy('status', 'desc')->paginate(2);
return view('protected.ticketsList', [
'tickets' => $tickets,
]);
In my view I use:
supporter: {{ $ticket['supporter']->username }}
Any idea where I do wrong? I get all the time this error:
Trying to get property of non-object
In my point of view the relation between the tables itself is done correctly.
When I use for example {{ dd($ticket) }} in my view I get an object with all the items I need:
So first of all, trying to access the function public function supporter() on your Ticket model cannot be done using array syntax. Change:
{{ $ticket['supporter']->username }}
to:
{{ $ticket->supporter()->first()->username }}
If you don't want to use the ->first() you can do one of two things. Modify your existing query to include the ->with("supporter") syntax:
$tickets = Auth::user()
->tickets()
->with("supporter")
->orderBy('status', 'desc')
->paginate(2);
And access the supporter from the view like so:
{{ $ticket->supporter->username }}
// Notice how supporter is no longer a `method` ->supporter() but a `property` ->supporter
Or you can modify your relationship to include the closer ->first():
public function supporter(){
return $this->hasOne('App\User', 'id','supp_id')->first();
}
And then access it like so:
{{ $ticket->supporter()->username }}
// Notice you no longer need `->first()`
So, as you can see, there are multiple ways to access a Ticket's Supporter. Please note that you can't really combine these options; modifying the function to include ->first() and then trying to use ->with() will return an error, so pick one or the other.
Hope that helps!

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 }}

Laravel Getting only certrain data from pivot table

I'm using Laravel to query users that have a score ( row in eventscore table )
And i want to return all the users that have scores for the event with an ID of 3
Is it possible to only return the score of every user, found in the pivot table ( see results below )
This is the code i'm using
$persons = Person::whereHas('eventscore', function($q) {
$q->where('id', 3);
})->with('eventscore')->get();
return $persons;
Thank you!
Try this:
// Person model
// accessor for easy fetching the score from the pivot model
public function getScoreAttribute()
{
return ($this->pivot && $this->pivot->score)
? $this->pivot->score
: null;
}
// example usage for the event's page (I assume participants is the relation)
$event = Event::with('participants')->find(3);
// somewhere in the view template
#foreach ($event->participants as $participant)
{{ $participant->name }} - score: {{ $participant->score }}
#endforeach

Categories