Djave
Djave

Reputation: 9329

Laravel returning null for attribute, that shows up fine when returned

I have the following code in my controller:

public function results($module_id){
    $module = Module
        ::with(['userResult','userAnswers','questions.answers'])
        ->find($module_id);
    return $module;
}

During the return, I get the following back:

{
  "id": 2,
  "created_at": null,
  "updated_at": null,
  "title": "Module 2",
  "short_description": "Ratione explicabo dicta odio nulla officiis ex est. Aspernatur voluptates accusantium atque nulla explicabo.",
  "pass_mark": 0,
  "user_result": {
    "id": 2,
    "created_at": "2016-12-20 14:57:11",
    "updated_at": "2016-12-20 14:57:11",
    "module_id": 2,
    "user_id": 1,
    "score": 1
  },
  "user_answers": [
    {
      "id": 6,
      "created_at": "2016-12-20 14:57:11",
      "updated_at": "2016-12-20 14:57:11",
      "question_id": 6,
      "user_id": 1,
      "score": 0,
      ...

OK great. But when I do the following:

public function results($module_id){
    $module = Module
        ::with(['userResult','userAnswers','questions.answers'])
        ->find($module_id);
    return $module->user_result;
}

I get a blank page. If I dd($module->user_result) I get null.

What am I doing wrong?

If it helps, here are the relations inside of Module.php

public function questions(){
    return $this->hasMany("\App\Question")->orderBy('order');
}

public function userResult(){
    return $this->hasOne("\App\ModuleResult")->where('user_id', Auth::id());
}

public function userAnswers(){
    return $this->hasManyThrough('\App\QuestionResult', '\App\Question');
}

Upvotes: 0

Views: 3750

Answers (1)

Parziphal
Parziphal

Reputation: 6902

To get relations (like userResult) you have to get the property with exactly the same name as the method that defines the relation (in this case, $model->userResult). You're getting confused looking at the JSON ouput and trying to get properties in your model as you see them in their serialized JSON version (this is incorrect because the JSON representation of a model could be absolutely anything you want).

When you get $model->userResult, Laravel will realize that userResult is actually a relation (because you defined a relation as public function userResult()), and will return it. So if you try to get $model->user_result, which is a property that doesn't exist and neither is a relation, you simply get null.

Now, why does it appear as user_result in your JSON? As Devon said, Laravel converts relations to underscore when serializing them. Why is this? I can think of this: usually, database columns (in MySQL at least) are written in "snake_case", so to keep things with the same format, Laravel snake_cases relation names, which are expected to be written in camelCase, because PHP standards tell us to use camelCase for properties, variables and methods (and others).

If Laravel didn't snake_case relations, your JSON would look like this:

{
  "id": 2,
  "created_at": null,
  "pass_mark": 0,
  "userResult": {
    "id": 2,

I could keep writing things but I don't know if I'm doing any sense. If you have more questions, feel free to ask.

Upvotes: 2

Related Questions