Laravel 5.5. Many-to-Many. Receive the latest instance - laravel

I have such models (Many-to-Many)
class Driver
{
public function cars()
{
return $this->belongsToMany(Car::class);
}
}
class Car
{
public function drivers()
{
return $this->belongsToMany(Driver::class);
}
}
My Car has activated_at column, that can be null.
How can I retrieve the latest activated car per drivers in a specific parking?
Something like this
Parking::find(2)->drivers()->lastActivatedCars...?

You can just create a scope for the car.
// Car.php
public function scopeActivated($query)
{
return $query->whereNotNull('activated_at')->orderBy('activated_at', 'DESC');
}
And then in your Driver.php:
// Driver.php
public function latestActivatedCar()
{
return $this->cars()->activated()->first();
}
Then you can just:
$latest = $driver->latestActivatedCar();
Or you can create a relationship, so you can eager load.
// Driver.php
public function latestActivatedCar()
{
return $this->belongsToMany(Car::class)
->whereNotNull('activated_at')
->orderBy('activated_at', 'DESC')
->limit(1);
}
Then you can just:
$drivers = Parking::find(2)->drivers;
$drivers->load('latestActivatedCar');

I hope this would help:
Parking::with(['drivers' => function ($driverQuery) {
$driverQuery->with(['cars' => function ($carsQuery) {
$carsQuery->orderBy('activated', 'desc')
->limit(1);
}]);
}])->find(2);

Related

Laravel check hasMany of hasMany relationship if has IDs?

Hello I have the following relationship setup:
Product class:
public function attributes()
{
return $this->hasMany(ProductAttribute::class);
}
ProductAttribute class:
public function attribute()
{
return $this->belongsTo(Attribute::class);
}
public function values()
{
return $this->hasMany(ProductAttributeValue::class, 'product_attribute_id');
}
ProductAttributeValue class:
public function attributeValue()
{
return $this->belongsTo(AttributeValue::class, 'attribute_value_id');
}
How to check if Product has values with ids 5 and 15?
I am trying to make a query like this:
Product::whereHas('values', function($q) use ($product_values_ids) {
$q->whereIn('attribute_value_id', $product_values_ids);
})->get();
however it is not working. I cannot access directly $product->values.
Any suggestions on how to access directly the values of attributes from the Product?
Update:
I have just managed to make it work with a many to many trough relationship:
Product class:
public function values()
{
return $this->hasManyThrough(ProductAttributeValue::class, ProductAttribute::class);
}
is there a way to get only the results that have all the ids listed in the $product_values_ids array?
You have to add new relation to Product model:
public function values(): HasManyThrough
{
return $this->hasManyThrough(ProductAttributeValue::class, ProductAttribute::class);
}
and then:
$builder = Product::query();
foreach($product_values_ids as $id) {
$builder->whereHas('values', function($q) use ($id) {
$q->where('id', $id);
});
}
$product = $builder->get();

Eloquent query on tables with relationships and a condition in a pivot table

I've various tables with these relationships, described as models
Customers
class Customers extends Model
{
public function claims()
{
return $this->hasMany(Claims::class);
}
}
Claims
class Claims extends Model
{
public function refunds()
{
return $this->hasMany(Refunds::class);
}
public function customers()
{
return $this->belongsTo(Customers::class,'customers_id');
}
}
Refunds
class Refunds extends Model
{
public function services()
{
return $this->belongsToMany(Services::class)
->withPivot(['services_id','services_amount','services_status']);
}
public function claims()
{
return $this->belongsTo(Claims::class,'claims_id');
}
}
Services
class Services extends Model
{
public function refunds()
{
return $this->belongsToMany(Refunds::class);
}
}
I need to do a query that return all rows from Customers with a row count on the pivot table refunds_services where services_id = 1 for each Customers row.
How can I do this? Is it possible? or better i use query builder and sql with several joins
Thx
you can try :
Customers::select('cliente')
->addSelect([
'countRefundService' => Customers::withCount('claims.refunds.services', function($query) {
$query->where('id', 1);
})->get();
])
->whereHas('claims.refunds.services', function ($query) {
$query->where('id', 1);
} )
->get();

How to add custom methods to eloquent model in a way we can chain them?

What I want is add methods to eloquent models so I can chain them, for example:
class MovieResolver
{
public function getMoviesFeaturingToday(array $args)
{
// Movie is an Eloquent model
$movie = (new Movie())
->getMoviesFeaturingTodayOnTheater($args['movieTheaterId'])
->getBySessionCategory($args['sessioncategory']);
// And keep doing some operations if necessary, like the code below.
// I cannot call the get() method unless I finish my operations.
return $movie->whereDate('debut', '<=', Carbon::today())
->orderBy('debut', 'desc')
->get();
}
}
But adding these methods to the model:
class Movie extends Model
{
public function getMoviesFeaturingTodayOnTheater($theaterId)
{
return $this->whereHas(
'sessions.entries.movieTheaterRoom',
function ($query) use ($theaterId) {
$query->where('movie_theater_id', $theaterId);
}
);
}
public function getBySessionCategory($sessionCategory)
{
return $this->whereHas(
);
}
}
Results in the following error:
Call to undefined method Illuminate\Database\Eloquent\Builder::getMoviesFeaturingTodayOnTheater()
But why? What I'm doing wrong?
This is done using Query Scopes. So try this in your model instead:
public function scopeMoviesFeaturingTodayOnTheater($query, $theaterId)
{
return $query->whereHas(
'sessions.entries.movieTheaterRoom',
function ($query) use ($theaterId) {
$query->where('movie_theater_id', $theaterId);
}
);
}
public function scopeBySessionCategory($query, $sessionCategory)
{
return $query->whereHas(
// ...
);
}
Then to use it you do:
Movie::moviesFeaturingTodayOnTheater($args['movieTheaterId'])
->bySessionCategory($args['sessioncategory']);;

Adding extra queries to whereHas

I am selecting all the broadcasts that belong to the same organization as the authenticated user, this works perfectly with ->whereHas() but what if i wanted to add a filter to display only the broadcasts where is_published is true.
public static function indexQuery(NovaRequest $request, $query)
{
if (Auth::user()->isAdmin()) {
return $query;
}else{
return $query->whereHas('organizations', function($q){
$q->where('organization_id', Auth::user()->organization_id);
});
}
}
models
public function organizations()
{
return $this->belongsToMany('App\Models\Organization');
}
public function broadcasts()
{
return $this->belongsToMany('App\Models\Broadcast');
}
You can add a query scope to your Broadcast model which will query only broadcasts where is_published is true (This is good for future queries in your application where you need published broadcasts):
Broadcast.php (or model file)
public scopePublished($query)
{
return $query->where('is_published', true);
}
Then in your code, and the ->published() scope to your query:
public static function indexQuery(NovaRequest $request, $query)
{
if (Auth::user()->isAdmin()) {
return $query;
} else {
return $query->published()
->whereHas('organizations', function($q){
$q->where('organization_id', Auth::user()->organization_id);
});
}
}

How to use wherePivot method in a scope?

I have two models with a pivot.
Domain
{
public function projects()
{
return $this->belongsToMany('Project')->withPivot('is_live');
}
}
Project
{
public function domains()
{
return $this->belongsToMany('Domain')->withPivot('is_live');
}
}
Then I try to create the scope "Domains which have Projects and is_live = true" like that Laravel Scope by pivot data values
public function scopeHasLiveProjects($query)
{
$pivotTable = $this->projects()->getTable();
return $query->whereHas('projects', function ($q) use ($pivotTable) {
$q->where($pivotTable . '.is_live', true);
});
}
But how I can use eloquent method wherePivot('is_live', '=', true) in the scope? Is it possible?!
public function scopeHasLiveProjects($query)
{
return $query->whereHas('projects', function ($q) {
$q->where('is_live', true);
});
}
should do the needed

Resources