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
2
Answers
I think I've found the solution
You see the problem was in
ofMany()
function, which creates a hugeSQL
and I don't know why!I've returned a
HasOne
object here, which supports all kinds of query manipulations. BasicallyHasOne
class, tells the main query, to:So if we use
orderBy
it only provides an order forHasOne
's query. and the main query will take cares of the rest and selects the first record.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:
bids
as a relationship, as that is actually a relationship to theBid
modelapprovedBids
to be a scope (or an attribute)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 scopeThis 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:Then later you can just do
$this->topBid
.