Laravel Eloquent getting all 'with' relationship without specifying one by one - laravel

My relationships is something like:
player
sub
something
sub-2
sub-3
something
foobar
sub-4
I can get player by id with its sub like this:
Player::with('sub.something','sub-2','sub-3.something.foobar','sub-4')->find($id);
However I had to specify each 'with' relationship manually.
Is it possible to just get everything on the child relationship (hasMany/hasOne) in one query?
Something like:
Player::with(everything())->find($id);

The short answer is no, relationships are expensive to get so you need to be explicit with what you need to load each time. You can however specify which relationships are always eager loaded on the model:
class Player extends Model {
protected $with = [ 'sub.something','sub-2','sub-3.something.foobar','sub-4' ];
// Rest of model
}
This way you won't need to specify ::with every time when loading a model.

Yes You can use Eager Loading to get the model with related data:
eager-loading

Try this:
Player::with(['sub'])->find($id);
it will return all subs of a player.

Related

How can I eager load a group of relations that was previously specified within model in Laravel?

I have multiple cards that belong to the user model. Like vendor, customer and admin and so on. I can eager load them typically like:
User::with(['admin', 'vendor', 'customer'])->get();
but this cards are changeable, there could be added some more. In that case I don't want to make that change everywhere where I used to eager load that group. Instead I want something like
User::withCards()->get();
And in model itself something like:
protected $cards = ['admin','vendor', 'customer'];
public function withCards(){
return $this->with($this->cards);
}
Well I tried that without luck. But I think with the example above you understand what I meaning. How could I accomplish something like that?
You are looking for local query scopes. You can achieve this using:
protected $cards = ['admin','vendor', 'customer'];
public function scopeWithCards($query){
return $query->with($this->cards);
}

Query hasMany relation with slug instead of id?

I'm trying to query a category and all of its channels based on a slug.
Works
\App\Category::find(1)->channels()->get();
Doesn't Work
\App\Category::where('slug','animals')->channels()->get()
BadMethodCallException with message 'Method Illuminate/Database/Query/Builder::channels does not exist.'
Relationship on Category Model
public function channels()
{
return $this->hasMany(Channel::class,'category_id');
}
Assuming that you correctly have your slug field set-up in migration and model attributes (It looks like so from the Exception message).
Doing
\App\Category::find(1)->channels()->get();
is under the hood equivalent to
\App\Category::where('category_id', 1)->first()->channels()->get();
So what you are requiring, is to get the categories to actually execute the query and then be able to retrieve the channels from the hydrated model.
\App\Category::where('slug', 'animals')->first()->channels()->get();
should work as well as
\App\Category::where('slug', 'animals')->first()->channels; // calling as attribute will perform the get() on the relationship
Also take note that you may take advantage of other methods like with() for eager loading the relationship, first() to perform a get and ensure you take only one instance, and calling the relationship as attribute as shown above. Refer to the docs
there are so many possible answer in your question .. be more specific .. but here's the list of sample queries that may help you ..
GETTING ALL THE CATEGORY WITH ITS CHANNELS WHERE CATEGORY SLUG = ANIMAL
Category::with(['channels'])->where('slug', 'animal')->get();
GETTING ALL THE CATEGORY WITH ITS CHANNELS WHERE HAS A CHANNEL SLUG = ANIMAL
Category::with(['channels'])->whereHas('channels'=>function($q){
$q->where('slug','animal');
})->get();
GETTING ALL THE CATEGORY WITH ONLY CHANNELS THAT HAS A SLUG = ANIMAL
Category::with(['channels'=>function($q){
$q->where('slug','animal');
}])->get();

Laravel eloquent with pivot table

I have this table relationship:
I already made all the relationships in my models properly, but i don't know how to get the name from worktypes table
when i do
dd($shift->shift_workers);
i get this:
but i want also somehow to get the name from worktype table for each worker...
This should be done somehow withPivot() function or what?
So i could have something like this:
$foreach ($shift->shift_workers as $w => $worker)
echo $worker->name;
but i don't know how to do this...anyone can help?
It is obvious and logically right that the pivot table should be skipped so the result is achieved by:
$worker->worktypes->first()->name; // to get the name of the first work type
$worker->worktypes->pluck('name'); // to get all names as an array
To achieve this result, follow Laravel's naming convention and set up model relationsips right.
Rename your worker_worktype_pivot table to worker_worktype
Set up the relationship in the Worker model:
`
class Worker extends Model {
...
public function workTypes()
{
return $this->belongsToMany(WorkType::class);
}
}

Reverse polymorphic relation in Laravel 5

Suppose we have following models: a Warrior, an Axe and a Sword
Is there a way to make the following behavior possible?
$warrior->weapon = $sword;
// ...
or
$warrior->weapon = $axe;
// ...
In other words, is it possible to treat separate models as if they had similar types with Eloquent?
P.S
Obviously, above is a simplified example of a problem only serving the purpose of conveying the gist of it.
Yes, you can make weapon a polymorphic relation. Add columns weapon_type and weapon_id to your table, which can be done in a migration file with the morphs type:
Schema::table('warriors', function ($table) {
$table->morphs('weapon');
});
Now you are ready to add your relationship to the Warrior model:
public function weapon() {
return $this->morphTo();
}
That's it! Now you can add the weapon and Eloquent will take care of the rest. The relation even supports eager loading. I suggest that all your weapons should implement an interface so you know what methods they have in common, but unfortunately there is no way for Eloquent to enforce that interface for you through the PHP type system.

Disable eager relations

In my project I have many Eloquent models that have eager relations configured in class like this:
protected $with = [ 'countries', 'roles' ];
But sometimes I need just old plain model without any relations. Can I somehow do:
Model::noRelations()->all()
Really don't wanna use query builder nor create another class just for few occasions.
If you have to set the $with property on your model rather than leaving it empty, you can manually override the relationships that need to be eager loaded like this:
Model::setEagerLoads([])->get();
Link to API for setEagerLoads
In addition to Thomas Kim answer.
If you anyway extend Eloquent\Model class and often need to strip off relations from model, this solution might suit you well.
Create scope in your default model class:
public function scopeNoEagerLoads($query){
return $query->setEagerLoads([]);
}
For any ORM, that extends that class you will be able to:
User::noEagerLoads()->all()
Just like the issues say
Model::without(['countries', 'roles' ])->all();

Resources