In Eloquent, you can do this:
public function children() {
return $this->hasMany('page');
}
And in Ardent, you can do this:
public static $relationsData = [
'children' => [self::HAS_MANY, 'Page'],
];
In Eloquent, you can also do this:
public function children() {
return $this->hasMany('page')->orderBy('sort_order', 'desc');
}
Is there any way to do that, or get the same effect as that in Ardent?
I really like the short Ardent notation, but don't want to have to call $page->children->ordered() with a scope just to order them, as they'll need to be ordered every single time it's called anyway.
As it turns out, it's just not possible. You need the full definition if you want to do anything more than the basic relation functionality.
Related
I Want To Use Relation Methods In Scopes But It Gives an Error.
Error:
Call to undefined method Illuminate\Database\Eloquent\Builder::members()
Controller:
$members = $book->MembersLoanedCurrentBook()->paginate(8);
Scope:
public function scopeMembersLoanedCurrentBook(Builder $query): Builder
{
return $query->members()->orderBy('return_date')->where('book_member.returned',false);
}
Assuming your models are something akin to User hasMany BookMember and Book has an attribute called returned, you can use Laravel's with` query scope:
Users::with(['member_books', function ($q) => {
$q->returned
})->get();
#geertjanknapen was right that this is a possible duplicate. You can achieve the same result using the methods from this question.
What you are doing is defining a scope and in that scope querying a relationship for a specific property or value.
public function scopeMembersLoanedCurrentBook(Builder $query): Builder
{
return $query->members()
->orderBy('return_date')
->whereHas(['book', function ($q) => {
$q->returned == false;
});
});
}
Without knowing the model structure and relationships, it's hard to write out an exact solution, but something along these lines should work.
You can't work with relations in scope, because your work with Builder $query.
public function scopeMembersLoanedCurrentBook(Builder $query): Builder
{
return $query->orderBy('return_date')
->where('returned',false);
}
And
$members = $book->members()->MembersLoanedCurrentBook()->paginate(8);
I need to make the orderBy parameter dynamic (not "name" as it is now)
public function children()
{
return $this->hasMany(self::class,'parent_id','id')
->orderBy('name')
->with(['children' => fn($q) => $q->orderBy('name')]);
}
The best way for me is when you call the relationship on the method with() and add the function as you did on the model, then you be able to pass the parameter on the fly instead since you defined the relationship.
e.g.
Relationship on model
public function children()
{
return $this->hasMany(self::class,'parent_id','id');
}
Call the relationship
$data = Model::with('children' => function($query) use($parameter) {
$query->orderBy($parameter);
});
Try with this solution, I'm not sure if that works, but I did something similar to apply a where conditional on the relationship
I am cleaning up a quite messy php laravel 8 project right now.
Currently my ressource looks like this:
class MyModelSimpleResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'my_calculated_attribute' => MyModel::whereRaw('fk_id = ? AND model_type = "xyz"', [$this->id])->count(),
];
}
}
My problem is that on calling the API endpoint, for every record of MyModel it creates a separate query to calculate my_calculated_attribute.
I know that you can define foreign key constrains in the model like and query like this:
MyModel::with('myFkModel')->get()
This works great for foreign keys. But how can I avoid n queries when I need this my_calculated_attribute.
Thanks a lot!
PS: I know that raw queries are a bad idea and I know that the resource is supposed to transform data and not query it. 😅
Ok, I figured it out. I don't only can define foreign keys in my model! I just defined a new relationship:
public function myFkModels(): HasMany
{
return $this->hasMany(MyFkModel::class);
}
public function myFkWithCondition(): HasMany
{
return $this->myFkModels()->where('model_type ', 'xyz');
}
This I can put in my with statement like this:
MyModel::with('myFkModels', 'myFkWithCondition')->get()
I created a relationship in my 'Event' model called 'Type'.
public function type()
{
return $this->belongsTo('Types');
}
In my 'Types' database, I have several elements. My relationship returns them all, and I would like to know if it was not possible, directly in the relation, to indicate that I only want the types with the column "parent_id" 1.
Thank you very much
If I understand you correctly, you want to add a where clause to your relationship. You can do this right in the definition. I guess this isn't very clear in the laravel 5.5 docs.
Another note, if your model is called "Type" as you stated in the question, then your relationship should use this name as well:
public function type()
{
return $this->belongsTo('App\Type')->where('types.parent_id', 1);
}
... or with a namespace...
use App\Type;
...
public function type()
{
return $this->belongsTo(Type::class)->where('types.parent_id', 1);
}
I have a simple mutator:
public function getFullnameAttribute($value)
{
return $this->first_name. ' ' .$this->last_name;
}
But I also have a method that returns a list of specific users for use in a select input:
static function getDeliveryManagers()
{
return User::IsDeliveryManager()->lists('first_name', 'id');
}
I need that array returned to be ['First Name Last Name', 'id']
But the mutator doesn't work, e.g.
return User::IsDeliveryManager()->lists('Fullname', 'id');
I found this: https://github.com/laravel/framework/issues/668
Which Taylor marks as being done but I cant get it working. Using Laravel 4.2.
Any help?
You need to call the lists() on Eloquent Collection. So make sure IsDeliveryManager() is returning correct values. Its better if you can share the code of IsDeliveryManager(). If its is query scope you need to call get() before lists().
return User::IsDeliveryManager()->get()->lists('fullname', 'id');
The mutator, even if it is in camelcase, should be called in lowercase.
So you should be calling it as such:
return User::IsDeliveryManager()->lists('fullname', 'id');