Custom accessors Eloquent Model

465 Views Asked by At

I have a Eloquent Model and I want to create a customized toArray method...

class Posts extends Model {

    public function scopeActives($query)
    {
        return $query->where('status', '=', '1');
    }

    public function toCustomJS()
    {
        $array = parent::ToArray();
        $array['location'] = someFunction($this->attributes->location);

        return $array;
    }
}

//In my controller:

Posts::actives()->get()->toArray(); //this is working
Posts::actives()->get()->toCustomJS(); //Call to undefined method Illuminate\Database\Eloquent\Collection::toCustomJS()

How can I override the toArray method or create another "export" method?

1

There are 1 best solutions below

2
On BEST ANSWER

get() actually returns a Collection object which contains 0, 1, or many models which you can iterate through so it's no wonder why adding these functions to your model are not working. What you will need to do to get this working is to create your custom Collection class, override the toArray() function, and also override the function in your model responsible for building that collection so it can return the custom Collection object.

CustomCollection class

class CustomCollection extends Illuminate\Database\Eloquent\Collection {

    protected $location;

    public function __construct(array $models = Array(), $location)
    {
        parent::__construct($models);
        $this->location = $location;
    }

    // Override the toArray method
    public function toArray($location = null)
    {
        $original_array = parent::toArray();

        if(!is_null($location)) {
            $original_array['location'] = someFunction($this->location);
        }

        return $original_array;
    }
}

Overriding the newCollection method on your models

And for the models you wish to return CustomCollection

class YourModel extends Eloquent {

    // Override the newCollection method
    public function newCollection(array $models = Array())
    {
        return new \CustomCollection($models, $this->attributes['location']);
    }

}

Please note this may not be what you are intending. Because a Collection is really just an array of models, it's not good to depend on the location attribute of a single model. Depending on your use-case, it's something that can change from model to model.

It might also be a good idea to drop this method into a trait and then just use that trait in each model you wish to implement this feature in.

Edit:

If you don't want to go through creating a custom Collection class, you can always just do it manually each time...

$some_array = Posts::actives()->get()->toArray();
$some_array['location'] = someFunction(Posts::first()->location);
return Response::json($some_array);