I'm trying to use a HasMany
relation in a HasOne
.
I have following Models:
class Auction extends Model
{
//...
public function bids(): HasMany
{
return $this->hasMany(Bid::class, 'auction_id');
}
public function approvedBids(): HasMany
{
return $this->bids()->approved();
}
public function topBids(): HasMany
{
return $this->approvedBids()->orderByDesc('price')->take(10);
}
public function topBid(): HasOne
{
//return $this->topBids()->firstOfMany(); // Not Working
//return $this->hasOne(Bid:class, 'auction_id)->ofMany('price','max')->approved(); // not working
//return $this->hasOne(Bid:class, 'auction_id)->approved()->ofMany('price','max'); // not working
//return $this->hasOne(Bid::class, 'auction_id')->ofMany('price', 'max'); // working but not as I expecting
}
}
class Bid extends Model
{
//...
public function scopeApproved(Builder $query): Builder
{
return $query->where('state', BidState::STATE_APPROVED);
}
//...
}
As you can see in the source, I'm looking for a way to make a relation that retrieve the Top Bid (ONE BID) from topBids()
relation, but I don't know how, and none of my approaches works:
$this->topBids()->firstOfMany(); // Not Working
$this->hasOne(Bid:class, 'auction_id')->ofMany('price','max')->approved(); // not working
$this->hasOne(Bid:class, 'auction_id')->approved()->ofMany('price','max'); // not working
CodePudding user response:
Unfortunately these shouldn't be a relationships
Real question is why are you trying to make these relationships?
Usually you should be using relationships on model to describe how they are correlating together within the database, the rest of the things you should be defining as a scope on a query or a model, or as an attribute.
So, what I'm trying to say is this:
- Keep
bids
as a relationship, as that is actually a relationship to theBid
model - Update
approvedBids
to be a scope (or an attribute) - Update
topBids
to be a scope (or an attribute)
Then, you will be able to find top bid easily by doing something like this:
$this->topBids->first()
-> if it is an attribute$this->topBids()->first()
-> if it is a scope
This is how you can create a scope: https://laravel.com/docs/9.x/eloquent#local-scopes
In the end, you can even create an attribute that will allow you to retrieve topBid
like this:
public function getTopBidAttribute(){
$this->bids()->approved()->orderByDesc('offered_token_price')->first();
}
Then later you can just do $this->topBid
.
CodePudding user response:
I think I've found the solution
public function topBid(): HasOne
{
return $this->hasOne(Bid::class, 'auction_id')
->approved()
->orderByDesc('price');
}
You see the problem was in ofMany()
function, which creates a huge SQL
and I don't know why!