Laravel Eloquent - Get results from parents that has only one child - php

I'm trying to get all results that match a certain child id, and that the parent has only on child. My initial idea its to do it by hand with nested foreachs, but is there any method that does this in a simpler way?
My parent is called Proyectos and then I have a pivot table called PaisBeneficiarioProyecto, and the other parent is PaisBeneficiario. It's a many-to-many relation.
$monto_pais = Proyecto::all()->where('pais_beneficiarios', $id)->sum('monto_aprobado');
The code explained above does what you expect, but it's not the result that I need.
Here are my models:
Proyectos:
public function pais_beneficiarios()
{
return $this->belongsToMany(\App\Models\PaisBeneficiario::class, 'pais_beneficiario_proyecto', 'id_proyecto', 'id_pais_beneficiario')
->withPivot('monto_beneficio');
}
PaisBeneficiario:
public function pais_beneficiario()
{
return $this->belongsTo(\App\Models\PaisBeneficiario::class, 'id_pais_beneficiario');
}
public function proyecto()
{
return $this->belongsTo(\App\Models\Proyecto::class, 'id_proyecto');
}
PaisBeneficiarioProyectos:
public function proyectos()
{
return $this->belongsToMany(\App\Models\Proyecto::class, 'pais_beneficiario_proyecto', 'id_pais_beneficiario', 'id_proyecto')
->withPivot('monto_beneficio');
}
The value that I'm trying to sum is called monto_aprobado which is on Proyectos

The below query gives you the sum of monto_aprobado field of Proyecto models that jus have one pais_beneficiarios_count.
Proyecto::withCount('pais_beneficiarios')
->having('pais_beneficiarios_count', 1)
->sum('monto_aprobado');

Related

Laravel 8: Can I make Eloquent scope but NOT against query builder but against related model?

I have a model - let's call it Parent.
Each Parent can have many children.
public function children(): HasMany
{
return $this->hasMany(Child::class, 'parent_id', 'id');
}
I want to make a scope for Parent called "active".
My requirement goes as follows:
Parent is active when it has at least 1 child.
I've done local scopes multiple times and I know that within Parent.php I can do something like:
public function scopeActive($query)
{
return $query->where(…);
}
But as you see, $query is a \Illuminate\Database\Eloquent\Builder which is not my case. I want to operate on related model somehow, not the DB query.
Can I do this in a clean way without fetching all parents with('child') and within ->filter() forgetting those that have no children? When there will be 1000 parents but only one will have children, it will simply waste DB resources (by fetching 999 redundant parents).
You can use the following query
public function scopeActive($query)
{
return $query->has('children');
}
One option is to use whereHas in scope:
public function scopeActive($query){
return $query->whereHas('children');
}
OR
public function scopeActive(){
return $this->whereHas('children');
}
And
Parent::active()->with('children')->get();
should give you all Parents who have children and along with respective children
Can you try something like:
public function getActiveAttribute() {
return $this->children()->count() > 1;
}
This can be used like,
$parent->active
And the query will only be made when you'll try to access the active property on the Parent model, not when you will be fetching all parents.
In Parent
public function getActiveAttribute() {
return $this-> children()->exists();
}
In code
$parent = new Parent;
if($parent->active){//true}
You can also use count
count($this->children); // 0 evaluates to false
a related thread here if you need:
Laravel Check If Related Model Exists

Get relationship of a queried relationship in Laravel?

I'm trying to get the clan members of the primary tournament, with only a season instance.
I fetch the primary tournament using a query on the tournaments relationship, I then call the clans relationship on the tournament model I just fetched.
Except.. it isn't a model anymore, I'm pretty sure its a query? Or a collection, sorry for my lack of understanding but in a simple explanation, I can no longer access relationships?
I need help in how I can do this with still being able to call clans after querying the tournament.
Here are my models.
class Season extends Model
{
public function clans() {
return $this->belongsToMany(Clan::class);
}
public function tournaments() {
return $this->hasMany('App\Tournament', 'season_id');
}
public function primaryTournament() {
return $this->tournaments->where('is_primary', '1');
}
}
class Tournament extends Model
{
public function clans() {
return $this->belongsToMany(Clan::class);
}
public function season() {
return $this->belongsTo('App\Season', 'season_id');
}
}
I'm trying to achieve this:
$season = Season::all()->last();
$tournament = $season->primaryTournament();
$teams = $tournament->clans; // this is what erorrs
What's stopping me?
Property [clans] does not exist on this collection instance.
try
$teams = $tournament->clans(); // with parenthesis
The problem is apparently in $tournament, which is a collection of Tournament class, and not an instance of a unique one (because it's obtained by ->where('is_primary', '1')),
you can select the first instance by ->first() methode
or loop through $tournament values and access clan property.
Try this $teams = $tournament->clans();
Clans is relation function on your model, you need to put parentheses. This should return a collection of the Clan class.

Laravel eloquent conditional relationship

I am trying to set up a conditional relationship in eloquent model based on the value of table column, but it does not works.
This is the code that I am using:
//RELATIONS
public function task_schedule()
{
if ($this->task_schedule_id === 0) {
return $this->belongsTo('TaskSchedule', 'hold_task_schedule_id', 'id');
} else {
return $this->belongsTo('TaskSchedule');
}
}
Basically I want to use different column to get my child model defined in belongs to relationship.
scopeProfile($query) would not work for me because I dont want to retrieve the child in every single query and also I am using Task->with('task_schedule') in a lot parts of code.

Make Laravel Accessor return query results

UPDATED:
I'm trying to add my own attribute with subquery results to the results of main query.
Now, I have Many-To-Many relation between three tables: Tournaments, Participants and Users.
Here is the defining of relation in Tournaments model:
public function users() {
return $this->belongsToMany('App\User', 'Participants', 'Id_tourn', 'Id_user')->withPivot('Rating');
}
The structure of tables is:
Users:
-Id
-Name
Participants:
-Id
-Id_user
-Id_tournament
-Final
-Final_place
Tournaments:
-Id
-Name
I need to have extra Winners attribute in my final query result where I'll have info of first three places.
Following the documentation, I've created an accessor and tried different variants:
That just freeze the system. Nothing happenes and in 30 second I get timeout error.
public function getWinnersAttribute() {
return Tournaments::where("Id","=",$this->attributes['Id'])->where("Finals","=",1)->limit(3)->orderBy("Final_place","asc")->get();
}
This returns an error that "finals" column is not fount in Tournaments table, so $this doesn't have relation:
public function getWinnersAttribute()
{
return $this->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This returns blank white page without anything:
public function getWinnersAttribute()
{
return $this->with('users')->where("Finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}
This return "Winners" attribute empty:
public function getWinnersAttribute()
{
return $this->with("users")->where("Finals","=",1)->limit(3)->orderBy("final_place","asc");
}
I've created $appends variable to apply the accessor: protected $appends = ['Winners'];
However, I've checked the accessor, it works. If I return just:
public function getWinnersAttribute()
{
return "123";
}
it works fine and I get "123" inside "winners" attribute of main query result.
The main query is:
Tournaments::with(['users'])->get();
The Finals column is in pivot table of Many-To-Many relation.
UPDATED:
When I try to return query to that Model without relation:
public function getWinnersAttribute($value)
{
return $this->where("Finals",'=',2);
}
I get nothing in winners attribute as well. Like the subquery is not executed.
And if I add get() in the end of return:
return $this->where("Finals",'=',2)->get();
I get blank white page.
How can I solve that problem?
Thanks a lot.
If the getWinnersAttribute is on the Tournament model that means you already have a Tournament model you are calling by doing for example Tournament::find(1)->winners In your attribute you are trying too find the model again, and that could make it a forever loop trying to find a new one already having one etc. try using $this instead
public function getWinnersAttribute()
{
return $this->where("finals","=",1)->limit(3)->orderBy("final_place","asc")->get();
}

Eloquent relationship to get grandparents, great grandparents, etc

I have a table "people" with these fields :
Name
mother_id
father_id
In mother_id and father_id, I stock other Poeple ID
I have two relationships to get the parents
public function father()
{
return $this->belongsTo(Poeple::class, 'father_id');
}
public function mother()
{
return $this->belongsTo(Poeple::class, 'mother_id');
}
Since I can pick up the parents directly, I wonder if it is possible with Eloquent and Laravel to recover the parents of the parents, the parents of the grandparents, etc.
Is there a relationship to do that? Or a tip?
I do not know if it's possible to do:
I look if the child has a parent.
If he has a parent, I look if his parent has a grandparents
And so on (maximum 4)
At the end, I create a collection with all that. It's possible ?
Nested set does not seem to work for me. I have two parents.
Thank you
There is a simple trick you can achieve this.
use $appends
protected $appends = ['father'];
public function father()
{
return $this->belongsTo(Poeple::class, 'father_id');
}
public function mother()
{
return $this->belongsTo(Poeple::class, 'mother_id');
}
Above code will give you the nested results with every collection.

Categories