Abozanona
Abozanona

Reputation: 2285

How to pass parameter to eloquent model class to get custom relation

I have the following model in Laravel

class Card extends Model
{
    public $forAgentId;

    protected $with = [
        'agent_special_price',
    ];

    public function agent_special_price()
    {
        if (Auth::user() && Auth::user()->hasRole('admin')) {
            if ($this->forAgentId) {
                // Get special price for agent with id=$forAgentId
                return $this->belongsTo(AgentSpecialPrice::class, 'id', 'card_id')->where('user_id', $this->attributes['forAgentId']);
            } else {
                // Get all special prices
                return $this->belongsTo(AgentSpecialPrice::class, 'id', 'card_id');
            }
        }
        // User is agent
        return $this->belongsTo(AgentSpecialPrice::class, 'id', 'card_id')->where('user_id', Auth::id());
    }
}

What I'm trying to achieve using this code is to get the agent special price from another table to a specific card.

I'm trying to get the agent special price based on different conditions. One of those conditions is to get the prices based on $forAgentId.

In my controller, I wrote the following code to get the agent special price for a specific $forAgentId:

<?php
public function getAllForAdminWithAgentData($agentId)
{
    $card = new Card();
    $card->forAgentId = $agentId;
    return response()->success(
        QueryBuilder::for(Card::setModel($card))
            ->allowedFilters(
                'name',
                AllowedFilter::trashed()
            )->orderBy('created_at', 'desc')->paginate(10)
    );
}

But the code above getAllForAdminWithAgentData doesn't work when I run it and I have the role admin. What I expect from the getAllForAdminWithAgentData method is to execute the relation and get all agent_special_price for agent with id=$agentId only, but the code gets the agent_special_price for all users.

How can I modify getAllForAdminWithAgentData method such that it will change the forAgentId variable in the Card class and execute the agent_special_price relation after that?

Upvotes: 1

Views: 508

Answers (1)

tanerkay
tanerkay

Reputation: 3930

setModel() does not do what you appear to want.

A new query builder instance is being created with the Card subject, and when you are looking for $this->forAgentId, it is looking for an attribute or database column named forAgentId, which does not exist.

I would remove the property forAgentId in the Card class, and just use:

        QueryBuilder::for(Card::class)
            ->allowedFilters(
                'name',
                AllowedFilter::trashed()
            )
            ->orderByDesc('created_at')
            ->paginate(10)

and then one option would be to update the eager loading definition,

            if ($this->forAgentId) {

changing $this->forAgentId to however you get the agent ID in the first place, e.g. from the request or the session.

Or constrain the relation in the builder:

        QueryBuilder::for(Card::class)
            ->with(['agent_special_price' => fn ($query) => $query->where(....)])
            ....

Upvotes: 1

Related Questions