19

I have this (simplified) table structure:

users
- id
- type (institutions or agents)

institutions_profile
- id
- user_id
- name

agents_profile
- id
- user_id
- name

And I need to create a profile relationship on the Users model, but the following doesn't work:

class User extends Model
{
    public function profile()
    {
        if ($this->$type === 'agents')
            return $this->hasOne('AgentProfile');
        else
            return $this->hasOne('InstitutionProfile');
    }    
}

How could I achieve something like that?

Ju Nogueira
  • 8,435
  • 2
  • 29
  • 33

3 Answers3

33

Lets take a different approach in solving your problem. First lets setup relationship for the various models respectively.

class User extends Model
{
    public function agentProfile()
    {
        return $this->hasOne(AgentProfile::class);
    }    

    public function institutionProfile()
    {
        return $this->hasOne(InstitutionProfile::class);
    }

    public function schoolProfile()
    {
        return $this->hasOne(SchoolProfile::class);
    }

    public function academyProfile()
    {
        return $this->hasOne(AcademyProfile::class);
    }

    // create scope to select the profile that you want
    // you can even pass the type as a second argument to the 
    // scope if you want
    public function scopeProfile($query)
    {
        return $query
              ->when($this->type === 'agents',function($q){
                  return $q->with('agentProfile');
             })
             ->when($this->type === 'school',function($q){
                  return $q->with('schoolProfile');
             })
             ->when($this->type === 'academy',function($q){
                  return $q->with('academyProfile');
             },function($q){
                 return $q->with('institutionProfile');
             });
    }
}

Now you can access your profile like this

User::profile()->first();

This should give you the right profile. Hope it helps.

oseintow
  • 7,221
  • 3
  • 26
  • 31
6

you can do this by use another method please check this:

a blog Post and Video model could share a polymorphic relation to a Tag model. Using a many-to-many polymorphic relation allows you to have a single list of unique tags that are shared across blog posts and videos. First, let's examine the table structure:

https://laravel.com/docs/5.4/eloquent-relationships#many-to-many-polymorphic-relations

Mortada Jafar
  • 3,529
  • 1
  • 18
  • 33
0

Looks like that should be $this->type rather than $this->$type - since type is a property, not a variable.

Joel Hinz
  • 24,719
  • 6
  • 62
  • 75
  • I just can't believe I didn't see that! Thanks. But now I'm getting this error when trying to eager load the profile: `Fatal error: Call to a member function addEagerConstraints() on a non-object in /vendor/illuminate/database/Eloquent/Builder.php on line 667` Any ideas? – Ju Nogueira Apr 27 '17 at 21:58
  • Not sure exactly what might cause that - maybe check the names of the tables/models? I noticed they're called different things so they might need `$table` properties in their respective models. – Joel Hinz Apr 27 '17 at 21:59
  • Have just seen that message about `addEagerConstraints` - this is caused when your relationship function (e.g `profile()`) doesn't return anything - suspect a scope is the better way to go. – GuruBob Apr 18 '19 at 02:05