Home > front end >  Laravel 8.x realationship - Use HasMany in HasOne
Laravel 8.x realationship - Use HasMany in HasOne

Time:01-13

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 the Bid 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!

  • Related