Count instances of many to many relationship : Laravel - php

I have a database setup where you have a lecturer having many groups and each group having many students and also a student can be in many groups. Therefore I have a one to many relationship between a lecturer and groups (respectively) and a many to many relationship between students and groups.
I want to show the lecturer how many students they have overall. For example if the lecturer has 5 groups with 5 students in each then I want to show 25. I tried this auth()->user()->userable->groups()->withCount('students') but I got this:
Call to a member function getRelationExistenceCountQuery() on null
Edited, Here are the relationships:
# user model
class User extends Authenticatable{
public function userable(){
return $this->morphTo();
}
}
# staff/lecturer model
Staff extends Model {
public function user(){
return $this->morphOne(User::class, 'userable');
}
public function groups(){
return $this->hasMany(Group::class);
}
}
#group model
class Group extends Model {
public function staff(){
return $this->belongsTo(Staff::class);
}
public function students(){
$this->belongsToMany(Student::class, 'groups_students', 'group_id');
}
}
# student model
class Student extends Model {
public function groups(){
return $this->belongsToMany(Group::class, 'groups_students', 'student_id');
}
}
What's the most efficient way to get my desired result?

Group::students() is missing the return statement:
public function students(){
return $this->belongsToMany(Student::class, 'groups_students', 'group_id');
^^^^^^
}
You can get the total of number of students like this:
$groups = auth()->user()->userable->groups()->withCount('students')->pluck('students_count');
$count = $groups->sum();

Related

Is it possible to relate a table on a pivot one with eloquent ORM?

These are my tables many-to-many:
products and suppliers, however I need to relate the pivot(product_supplier) to a table called payment_supplier.
Product model
public function suppliers(){
return $this->belongsToMany('App\Supplier');
}
Supplier model
public function products(){
return $this->belongsToMany('App\Product');
}
but I need to relate pivot product_supplier to payment_supplier table just like described on the diagram
In this case, you could use a pivot model.
# Product Model
public function suppliers() {
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
# Supplier Model
public function products(){
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
# ProductSupplier Pivot Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProductSupplier extends Pivot
{
public function payment_supplier()
{
return $this->hasMany(PaymentSupplier::class);
}
}
However, doing it like this has a big problem: You CANNOT eager load a pivot's relationships. Not without an override (or a package).
The other way to go about it is using hasManyThrough
# Product Model
public function suppliers()
{
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
# Supplier Model
public function products()
{
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
This gives you every PaymentSupplier for a single Supplier/Product, so you'll need to apply some kind of filtering.

Working with 3 tables in a Laravel relationship?

I have a season, and each clan has to have a valid season entry. The stage I'm currently stuck on is how can I have a relationship for clans in my Season class?
This would help me understand which clans a season currently holds, but without a complicated query, it seems impossible with relationships. Is there a 'good practice' way of doing this?
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Season extends Model
{
public function matches() {
return $this->hasMany('App\ClanMatch', 'season_id');
}
public function tournaments() {
return $this->hasMany('App\Tournament', 'season_id');
}
}
class SeasonEntry extends Model
{
public function season() {
return $this->belongsTo('App\Season', 'season_id');
}
public function clan() {
return $this->belongsTo('App\Clan', 'clan_id');
}
}
Think if simple.
One clan can participate in many seasons.
One seasons, there are many clans.
So I guess, this is Many-to-Many relationship. To deal with it in Laravel, commonly, you need to create a pivot table that defines the co-relation.
Schema::create('season_clan', function (Blueprint $table) {
$table->increments('id');
$table->integer('season_id')->unsigned();
$table->integer('clan_id')->unsigned();
});
And both models need to address the relationship as well.
class Season extends Model
{
public function clans()
{
return $this->belongsToMany(Clan::class);
}
}
class Clan extends Model
{
public function seasons()
{
return $this->belongsToMany(Seasons::class);
}
}
That's all I guess! You can try and it should work.

Tracking history of vehicles and drivers

I'm experimenting with relations in Laravel and I cannot figure this one out.
I have two tables users and vehicles. The users can drive a vehicle and the drivers are replaced often. To track these changes I created a history table. This table contains user_id, vehicle_id, start and end.
I want to get the vehicle that the current user is driving, through the History table.
class User extends model {
public function vehicle()
{
// return the current active vehicle for the user
// through the History model.
return $this->hasOne(History::class, 'user_id');
}
public function history()
{
// return all the vehicles that the user has used
// this currently returns the history rows, not the cars
return $this->hasMany(History::class, 'user_id');
}
}
class Vehicle extends model {
public function user()
{
// return the current active user
}
public function users()
{
// return all the users that used this vehicle
}
}
If I perform the following method in a controller.
public function showUser()
{
return User::findOrFail(1)->with('vehicle', 'history')->get()
}
I want the response formatted like the following:
[
0: {
first_name: 'John',
...
vehicle: {
model: 'BMW ...'
}
history: {
0: {
model: 'BMW ...'
}
1: {
model: 'Audi ...'
}
...
}
}
]
You could add a query scope to your history model to return the latest record.
public function scopeLatest($query)
{
return $query->orderBy('created_at', 'desc')->limit(1);
}
Then you can get that through your relationship
$user->history()->latest()->first()->vehicle;
This, of course, requires that you have the vehicle relationship defined in your history class.

Laravel selection from pivot table

I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
**Users**
id
username
password
**Items**
id
name
**User_items**
id
user_id
item_id
Models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id');
}
}
I need to select all items table, print it and highlight rows which belongs to specific user id=1.
Selection highlighted output:
What is the right way to do it (in laravel style)?
You can use it like this
public function user_items()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
Like this you can access values of third table.
Some useful links-
http://www.developed.be/2013/08/30/laravel-4-pivot-table-example-attach-and-detach/
http://vegibit.com/many-to-many-relationships-in-laravel/
http://laravel.com/docs/4.2/eloquent
You can do it like this way...
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id')->withPivot('id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
}
From controller..
$user_id = 2;
Item::with(['users'=>function($q) use ($user_id){$q->where('user_id',$user_id);}])->get();
In view at the time of listing a row you can highlight the row just use a condition as each item->users is blank or not.

Retrieving relationships of relationships using Eloquent in Laravel

I have a database with the following tables and relationships:
Advert 1-1 Car m-1 Model m-1 Brand
If I want to retrieve an Advert, I can simply use:
Advert::find(1);
If I want the details of the car, I could use:
Advert::find(1)->with('Car');
However, if I also want the detail of the Model (following the relationship with Car), what would the syntax be, the following doesn't work:
Advert::find(1)->with('Car')->with('Model');
Many thanks
It's in the official documentation under "Eager Loading"
Multiple relationships:
$books = Book::with('author', 'publisher')->get();
Nested relationships:
$books = Book::with('author.contacts')->get();
So for you:
Advert::with('Car.Model')->find(1);
First you need to create your relations,
<?php
class Advert extends Eloquent {
public function car()
{
return $this->belongsTo('Car');
}
}
class Car extends Eloquent {
public function model()
{
return $this->belongsTo('Model');
}
}
class Model extends Eloquent {
public function brand()
{
return $this->belongsTo('Brand');
}
public function cars()
{
return $this->hasMany('Car');
}
}
class Brand extends Eloquent {
public function models()
{
return $this->hasMany('Model');
}
}
Then you just have to access this way:
echo Advert::find(1)->car->model->brand->name;
But your table fields shoud be, because Laravel guess them that way:
id (for all tables)
car_id
model_id
brand_id
Or you'll have to specify them in the relationship.
Suppose you have 3 models region,city,hotels and to get all hotels with city and region then
Define relationship in them as follows:-
Hotel.php
class Hotel extends Model {
public function cities(){
return $this->hasMany(City::class);
}
public function city(){
return $this->belongsTo('App\City','city_id');
}
}
City.php
class City extends Model {
public function hotels(){
return $this->hasMany(Hotel::class);
}
public function regions(){
return $this->belongsTo('App\Region','region_id');
}
}
Region.php
class Region extends Model
{
public function cities(){
return $this->hasMany('App\City');
}
public function country(){
return $this->belongsTo('App\Country','country_id');
}
}
HotelController.php
public function getAllHotels(){
// get all hotes with city and region
$hotels = Hotel::with('city.regions')->get()->toArray();
}
will adding the relation function just ask for the relation needed
public function Car()
{
return $this->belongsTo(Car::class, 'car_id')->with('Model');
}
but if you want a nested relation just use the period in the with
Advert::with('Car.Model')->find(1);
but for multi-relation use the array
Advert::with('Car','Model')->find(1);

Categories