I'm trying to use Polymorphic Relationships from this docs .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
I'm trying to use Polymorphic Relationships from this docs https://laravel/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
Share
Improve this question
edited Mar 4 at 15:55
Levsha
asked Mar 4 at 11:12
LevshaLevsha
5364 silver badges19 bronze badges
3 Answers
Reset to default 2You 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.
So the answer is complicated.
Like @Moshe Katz offered I created DummyClass and changed createModelByType().
- All my models extend CommonModel class, like Balance
class Balance extends CommonModel
{
public $subject;
public $subject_id;
public function subjectable(): MorphTo
{
return $this->morphTo(__FUNCTION__, 'subject', 'subject_id');
}
}
- In CommonModel I have overwrite method newMorphTo with my class App\Models\Replace\MorphTo
<?php
namespace App\Models;
use App\Models\Replace\MorphTo;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class CommonModel extends Model
{
public function isDummy()
{
return false;
}
protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation)
{
return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation);
}
}
- I have created app\Models\Replace\MorphTo.php class which return DummyClass:
<?php
namespace App\Models\Replace;
use App\Models\DummyClass;
use Illuminate\Database\Eloquent\Relations\MorphTo as IlluminateMorphTo;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Arr;
class MorphTo extends IlluminateMorphTo
{
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());
}
});
}
}
- Next we need DummyClass, that uses fake database.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class DummyClass extends Model
{
protected $connection = 'sqlite_fake';
public function isDummy()
{
return true;
}
}
- Also we need to create that fake database in config/database.php
'connections' => [
'sqlite_fake' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
...
- And finnaly we need to create empty table in memory. I put this code in AppServiceProvider boot() method.
Schema::connection('sqlite_fake')->create('dummy_classes', function ($table) {
$table->id();
});
Can't you just do something like
public function subjectable(): ?MorphTo
{
if (in_array($this->subject, ['shop', 'merchant'])) {
return $this->morphTo(__FUNCTION__, 'subject', 'subject_id');
}
return null;
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745047841a4608203.html
评论列表(0条)