Laravel - Eloquent: Polymorphic relations with nam

2019-08-14 19:30发布

My situation is: a Calendar belongs to a Customer or Salesman

Because I also have classes like Event and File, I used the namespace App\Models for all my model classes.

so I set up the polymorphic relation:

in Calender.php

public function user() {
    return $this->morphTo();
}

in Customer.php and Salesman.php

public function calendars() {
    return $this->morphMany('App\Models\Calendar', 'user');
}

Now when i do

$calendar= Calendar::find(1); //calendar from a salesman
$calendar->user; //error here
...

I get this error message:

Symfony \ Component \ Debug \ Exception \ FatalErrorException
Class 'salesman' not found

I noticed that 'salesman' is low cased, maybe this is the problem?

and this is what I get from Laravels stacktrace

open: /var/www/cloudcube/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php

// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey))
{
    $foreignKey = snake_case($relation).'_id';
}

$instance = new $related; //HIGHLIGHTED

I had a similar error before on this line, when I was messing with the namespaces, so I guess it has something to do with that. Is there any way I can tell the morphTo() method to use the correct namespace?

Or is it something else causing this issue?

Also found this solution, but can't seem to get it working: Polymorphic Eloquent relationships with namespaces

1条回答
地球回转人心会变
2楼-- · 2019-08-14 19:51

I found a solution that worked for me.

I always define relationships with the correct namespace, for example in Calendar:

public function events() { return $this->hasMany('App\Models\Event'); }

My problem consisted out of 2 complications:

  1. $calendar->user() with the morphTo(...) function was not working because my models were in a namespace, and morphTo(...) had no way of giving this namespace.

  2. $salesman->calenders()->get() returned and empty list, although my relations in the database were there. I found out this is because of bindings with the query.

Solution for 1. : Writing a custom morphTo(...) function in Calendar to override the one of Laravel. I used the source of Laravels morphTo(...) as a base. The final statement of this function is return $this->belongsTo($class, $id); There $class must be the namespaced class name. I used basic string operations to pull that off.

Solution for 2. : Writing a custom morphMany(...) function in Salesman and letting it return a MyMorphMany(...) similar to what Polymorphic Eloquent relationships with namespaces described.

The problem here is that $query that is passed to the MyMorphMany constructor has the wrong (namespaced) binding. It will look for where user_type = "App\\Models\\Salesman".

To fix this I used a custom getResults() function in MyMorphMany which overrides the default Laravels implementation, there I changed the bindings to use the correct, un-namespaced lower cased, class name. Then I called this getResults() function in the get() function of the MyMorphMany class.

I used $query->getBindings() and $query->setBindings() to correct the bindings.

Hope this saves someone else a few days of work, like it would have saved me :)

查看更多
登录 后发表回答