Mohammad_Hosseini
Mohammad_Hosseini

Reputation: 2599

Conditionally append attribute to model in laravel

Is it possible to append an attribute to my model whenever a model scope is called?

For example in my controller I want to call a scope to append those dynamic attribute like :

$Media_query = OutDoorMedia::query();
$Media_query->orderby('created_at', 'desc');
$Media_query->PreviouslyOrdered();
$Media = $Media_query->get();

And in my model I want to do something like :

class OutDoorMedia extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'id',
        'user_id',
        'address',
        'location',
        'media_type',
    ];
}

class scopePreviouslyOrdered extends OutDoorMedia
{
public $appends = ['previously_ordered'];

public function getPreviouslyOrderedAttribute()
{
    if ($this->hasMany('App\Models\OutDoorMediaOrders', 'odm_id', 'id')->Where(function ($query) {
        $query->where('status', MEDIA_ORDER_CHECKOUT_STATUS)
            ->orWhere('status', STATUS_TO_PAY);
    })->exists()) {
        return true;
    } else {
        return false;
    }
}

}

But it's not working and I know it's wrong, How to achieve this?

Upvotes: 5

Views: 25473

Answers (3)

MUHINDO
MUHINDO

Reputation: 1213

Just in case you need to include in your response,

$data = FarmerQuestion::where([])->get();
$data->append(
    [
        'user_text',
        'user_photo',
        'district_text',
        'answers_count'
    ]
);

Upvotes: 0

apokryfos
apokryfos

Reputation: 40683

I think there's a misunderstanding on how scopes should work. A scope is basically like a shortcut query for a model. You are using it to test existance of a relationship but there's a better way to do that using whereHas

Here's how you would achieve this using a relationship:

class OutDoorMedia extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'id',
        'user_id',
        'address',
        'location',
        'media_type',
    ];

    public function previousOrders() {
         return $this->hasMany('App\Models\OutDoorMediaOrders', 'odm_id', 'id');
    }
    public function getPreviouslyOrderedAttribute() {
        return $this->previousOrders()->exists(); 
    }
}

Then you simply do:

$Media_query = OutDoorMedia::whereHas('previousOrders')
                ->orderby('created_at', 'desc');

If you what the dynamic attribute appended on the model automatically you can just add the following to the model:

 public $appends = [ 'previously_ordered' ];

I guess if you want the best from both worlds you can do:

class OutdoorMediaWithPreviouslyOrdered extends OutDoorMedia {
     public $appends = [ 'previously_ordered' ];         
 }

Then when you need the appending model you can use :

 $Media_query = OutdoorMediaWithPreviouslyOrdered ::orderby('created_at', 'desc');

Upvotes: 4

Mohammad_Hosseini
Mohammad_Hosseini

Reputation: 2599

I solved this problem with help of @apokryfos but with a bit tweak. hope this reduce wasting others time.

Instead of appending attributes on the model I have appended the said attribute to my model by the eloquent magic method :

$Media_query = OutDoorMedia::query();
$Media_query->orderby('created_at', 'desc');
$Media = $Media_query->get()->each(function ($items) {
          $items->append('previously_ordered');//add this attribute to all records which has the condition
         });    

In Model As apokryfos said I have put these two methods:

  public function PreviousOrders() {
      return $this->hasMany('App\Models\OutDoorMediaOrders', 'odm_id', 'id');
  }

  public function getPreviouslyOrderedAttribute() {
      return $this->PreviousOrders()->exists();
  }

But I don't need this method and I had to remove it from the model because if it exist in model it will automatically append to model:

public $appends = [ 'previously_ordered' ];

Upvotes: 6

Related Questions