I'm trying to use Polymorphic Relationships from this docs https://laravel.com/docs/12.x/eloquent-relationships#polymorphic-relationships
I have model Balance
class Balance
{
public $subject;
public $subject_id;
public function subjectable(): MorphTo
{
return $this->morphTo(__FUNCTION__, 'subject', 'subject_id');
}
}
Also I have simple mapping in AppServiceProvider
Relation::morphMap([
'shop' => 'App\Models\Shop',
'merchant' => 'App\Models\Merchant',
]);
So if the field subject
contains 'shop' or 'merchant' - it works perfect.
But database is external resource, it's not strict like the code, and there might be some strings, that is not in my models and my app structure. And I can't control database and change it.
If subject
contains string 'abc' , I'm getting an error: Class "abc" not found.
So it's impossible to use ->morphTo()
in this case.
Is there a way to limit some "allowed list" of subjects (types), and return null
or empty collection, if this subject
not in my list?
UPD:
I can't make check $this->subject
inside relation function, because it's null.
public function subjectable() {
var_dump($this->subject);
if (in_array($this->subject, ['shop', 'merchant'])) {
return $this->morphTo(__FUNCTION__, 'subject', 'subject_id');
}
return null;
}
I'm trying:
$result = $query->with(['subjectable'])->get(); // $this->subject is null
// or
$result = $query->get();
$result->load(['subjectable']); // $this->subject is null
You can create a dummy model that will be used for all types of data for which you do not have models, let's call it DummyModel
.
You will need to extend Laravel's MorphTo
model with your own version of the createModelByType
method:
public function createModelByType($type)
{
$class = Arr::get(Relation::morphMap() ?: [], $type, DummyClass::class);
return tap(new $class, function ($instance) {
if (! $instance->getConnectionName()) {
$instance->setConnection($this->getConnection()->getName());
}
});
}
(The Laravel original version of this method has $class = Model::getActualClassNameForMorph($type);
, and there is no easy way to replace the static method on Model
.)
This will return your DummyClass
any time the morph map does not have a matching class.