Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: Whenever I return a model always return a relationship with it

I have 2 tables:

User        |   Doctor
----------  |  ----------
id          |  id
email       |  user_id
name        |  signature
last_name   |  photo
password    |  description
date_birth  |

Every Doctor is related to a User, but every User may not be related to a Doctor. I did it this way because I didn't want to use Single Table Inheritance and end up with a bunch of NULL fields.

Is there a way to make, something like this?

// Instead of
$doctor = Doctor::with('User')->find(1);
$doctor->user->name;
// This
$doctor = Doctor::find(1);
$doctor->name;

P.S: Didn't know what to put in the title, what should I put instead so it is more relevant to the question?

like image 731
Mathius17 Avatar asked Sep 04 '14 20:09

Mathius17


People also ask

What is with () in Laravel?

with() function is used to eager load in Laravel. Unless of using 2 or more separate queries to fetch data from the database , we can use it with() method after the first command. It provides a better user experience as we do not have to wait for a longer period of time in fetching data from the database.

What is polymorphic relationship in Laravel?

A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one association. A typical example of this is featured images on a post and an avatar for a user. The only thing that changes however is how we get the associated model by using morphOne instead.

What is BelongsTo in Laravel?

BelongsTo is a inverse of HasOne. We can define the inverse of a hasOne relationship using the belongsTo method. Take simple example with User and Phone models. I'm giving hasOne relation from User to Phone. class User extends Model { /** * Get the phone record associated with the user.


2 Answers

You can specify default eager loaded relationships using the $with property on the model.

class Doctor extends Eloquent {

    protected $with = ['user'];

    // ...
}

(The property might need to be public, I forget. Laravel will yell at you if it does.)

You will still need to use $doctor->user->name, but the relationship will be automatically loaded without you needing to explicitly call it. If you really want to use the $doctor->name syntax, you could create Accessors for those column names, which would then fetch and pass the appropriate User relationship columns.

like image 62
Aken Roberts Avatar answered Oct 13 '22 05:10

Aken Roberts


I ended up using Accessors and $appends and it worked as intended. It even appears in the docs Appends + Accessors (at the end). Thanks to Cyrode, whom showed me the Accessors (didn't know they exised).

I could've not use the $appends array, but you need it if you're returning the model in JSON.

As Jarek Tkaczyk deczo suggested, you should use with property when you go with this approach, otherwise whenever you load multiple Doctor models and call anything User related, you end up with a db query (per each Doctor instance) -> n+1 issue

Doctor class ended up looking like this:

<?php

class Doctor extends Eloquent {

    protected $table = 'doctors';

    protected $with = ['user'];

    protected $appends = ['first_name','last_name','email','date_of_birth'];

    protected $hidden = ['signature','user'];

    public function user(){

        return $this->belongsTo('User');

    }

    public function getFirstNameAttribute() {

        return $this->user->first_name;

    }

    public function getLastNameAttribute() {

        return $this->user->last_name;

    }

  public function getEmailAttribute() {

      return $this->user->email;

  }

}

I had to put user inside the $hidden array or it would show up whenever I retireved Doctor (Besides I only needed some things of User, not everything)

like image 44
Mathius17 Avatar answered Oct 13 '22 06:10

Mathius17