skip to Main Content

I’m developing an application where a User can be of type Admin, Client, Supplier or Manager. Each type (except Admin) has it’s own model with respective data, and related with a user_id. For example:

users
    - id
    - name
    - email
    - password
    - type

clients
    - id
    - user_id
    - segment
    - last_buy

suppliers
    - id
    - user_id
    - product_type
    - corporate_name

managers
    - id
    - user_id
    - managed_area

I want to have, in my User model, a profile attribute that loads user’s data from it’s other model (Client, Supplier or Manager), based on existing type attribute.

Before, I’ve used the $appends property and getProfileAttribute() method approach to achieve the result. But now, I’m trying to optimize my application using eager loading. So I’m trying to load the profile this way:

public function profile(){
    if($this->type == "client"){
        return $this->hasOne(Client::class);
    } else if($this->type == "supplier"){
        return $this->hasOne(Supplier::class);
    } else if($this->type == "manager"){
        return $this->hasOne(Manager::class);
    }
    return null;
}

But isn’t working. Every query ->with(["profile"]) returns the profile attribute with null value. I’ve dded the $this->type and noticed is always returning null too. I don’t understood why, but this is the cause why it can’t conditionally check User’s type.

So how can I achieve the expected result?

2

Answers


  1. You must specify a foreign key and local key for each hasOne because you are not using ‘conventional’ column names.

    e.g.:

    $this->hasOne(Client::class, 'id', 'user_id');
    
    Login or Signup to reply.
  2. As @mrhn commented above, the reason for your code not working is when queries are executed before model load. You can consider to apply One To One (Polymorphic) in your code: https://laravel.com/docs/10.x/eloquent-relationships#one-to-one-polymorphic-relations

    Your tables would be:

    users
        - id
        - name
        - email
        - password
        - profile_type
        - profile_id
    
    clients
        - id
        - segment
        - last_buy
    
    suppliers
        - id
        - product_type
        - corporate_name
    
    managers
        - id
        - managed_area
    

    Your migration:

    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->string('password');
        $table->morphs('profile');
        $table->timestamps();
    });
    

    Your relationship in user model:

    /**
     * Get the user's profile;.
     */
    public function profile()
    {
        return $this->morphTo();
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search