Eloquent ORM object relashionship

89 views Asked by At

i have two tables. School and Student.

When i fetch all Students

Student::all()->toJson();

I get a response with

[
  {
    "id": 1,
    "school_id": 1,
    "name": "Jhon"
  }
]

But actually i would like to receive

[
  {
    "id": 1,
    "school": {
        "id": 1
    },
    "name": "Jhon"
  }
]

I know i could do

Student::with(['school']);

But then it do an extra query to school table, which is not necessary, as i only need the school id, and not all other attributes.

2

There are 2 answers

4
lukasgeiter On BEST ANSWER

You can override the toArray method in your model. The same thing also would be possible with toJson, but toArray gets called by toJson and in my opinion its nicer to do such stuff in toArray

class Student extends Eloquent {

    public function toArray($options = 0){
        $this->school = ['id' => $this->school_id];
        unset($this->school_id);

        return parent::toArray($options);
    }
}

Edit

To keep the model the same and only change to output (which is probably better)

public function toArray($options = 0){
    $array = parent::toArray($options);
    $array['school'] = ['id' => $array['school_id']];
    unset($array['school_id']);
    return $array;
}
2
rmobis On

You can use Illuminate\Support\Collection's transform method for a more automated solution:

$students = Student::all();

$students->transform(function($el) {
    $el = $el->toArray();

    foreach ($el as $k => $v) {
        if (substr($k, -3) === '_id') {
            $el[substr($k, 0, -3)]['id'] = $v;

            unset($el[$k]);
        }
    }

    return $el;
});


return $students;

If you're going to call this multiple times (which I assume you will), the best would be to extend Illuminate\Database\Eloquent\Collection and add a method to do that. Then edit the newCollection method on your base model to use your new extended class.