Seperti yang dinyatakan OP dalam komentarnya: Desain basis data sudah ditetapkan dan oleh karena itu Hubungan Polimorfik Laravel tampaknya tidak menjadi pilihan di sini.
Saya suka jawaban dari Chris Neal karena saya harus melakukan sesuatu yang serupa baru-baru ini (menulis Driver Database saya sendiri untuk mendukung Eloquent untuk file dbase / DBF) dan mendapatkan banyak pengalaman dengan internal Laravel's Eloquent ORM.
Saya telah menambahkan cita rasa pribadi saya untuk membuatnya agar kode lebih dinamis dengan tetap menjaga pemetaan eksplisit per model.
Fitur yang didukung yang saya uji dengan cepat:
Animal::find(1)
berfungsi seperti yang ditanyakan dalam pertanyaan Anda
Animal::all()
berfungsi juga
Animal::where(['type' => 'dog'])->get()
akan mengembalikan AnimalDog
-objek sebagai koleksi
- Pemetaan objek dinamis per kelas fasih yang menggunakan sifat ini
- Fallback ke
Animal
-model jika tidak ada pemetaan yang dikonfigurasi (atau pemetaan baru muncul di DB)
Kekurangan:
- Ini menulis ulang model internal
newInstance()
dan newFromBuilder()
seluruhnya (salin dan tempel). Ini berarti jika akan ada pembaruan dari kerangka kerja ke fungsi anggota ini Anda harus mengadopsi kode dengan tangan.
Saya harap ini membantu dan saya siap untuk saran, pertanyaan, dan kasus penggunaan tambahan dalam skenario Anda. Berikut adalah kasus penggunaan dan contoh untuk itu:
class Animal extends Model
{
use MorphTrait; // You'll find the trait in the very end of this answer
protected $morphKey = 'type'; // This is your column inside the database
protected $morphMap = [ // This is the value-to-class mapping
'dog' => AnimalDog::class,
'cat' => AnimalCat::class,
];
}
class AnimalCat extends Animal {}
class AnimalDog extends Animal {}
Dan ini adalah contoh bagaimana itu dapat digunakan dan di bawah hasil masing-masing untuk itu:
$cat = Animal::find(1);
$dog = Animal::find(2);
$new = Animal::find(3);
$all = Animal::all();
echo sprintf('ID: %s - Type: %s - Class: %s - Data: %s', $cat->id, $cat->type, get_class($cat), $cat, json_encode($cat->toArray())) . PHP_EOL;
echo sprintf('ID: %s - Type: %s - Class: %s - Data: %s', $dog->id, $dog->type, get_class($dog), $dog, json_encode($dog->toArray())) . PHP_EOL;
echo sprintf('ID: %s - Type: %s - Class: %s - Data: %s', $new->id, $new->type, get_class($new), $new, json_encode($new->toArray())) . PHP_EOL;
dd($all);
yang menghasilkan sebagai berikut:
ID: 1 - Type: cat - Class: App\AnimalCat - Data: {"id":1,"type":"cat"}
ID: 2 - Type: dog - Class: App\AnimalDog - Data: {"id":2,"type":"dog"}
ID: 3 - Type: new-animal - Class: App\Animal - Data: {"id":3,"type":"new-animal"}
// Illuminate\Database\Eloquent\Collection {#1418
// #items: array:2 [
// 0 => App\AnimalCat {#1419
// 1 => App\AnimalDog {#1422
// 2 => App\Animal {#1425
Dan jika Anda ingin Anda menggunakan di MorphTrait
sini tentu saja kode lengkap untuk itu:
<?php namespace App;
trait MorphTrait
{
public function newInstance($attributes = [], $exists = false)
{
// This method just provides a convenient way for us to generate fresh model
// instances of this current model. It is particularly useful during the
// hydration of new objects via the Eloquent query builder instances.
if (isset($attributes['force_class_morph'])) {
$class = $attributes['force_class_morph'];
$model = new $class((array)$attributes);
} else {
$model = new static((array)$attributes);
}
$model->exists = $exists;
$model->setConnection(
$this->getConnectionName()
);
$model->setTable($this->getTable());
return $model;
}
/**
* Create a new model instance that is existing.
*
* @param array $attributes
* @param string|null $connection
* @return static
*/
public function newFromBuilder($attributes = [], $connection = null)
{
$newInstance = [];
if ($this->isValidMorphConfiguration($attributes)) {
$newInstance = [
'force_class_morph' => $this->morphMap[$attributes->{$this->morphKey}],
];
}
$model = $this->newInstance($newInstance, true);
$model->setRawAttributes((array)$attributes, true);
$model->setConnection($connection ?: $this->getConnectionName());
$model->fireModelEvent('retrieved', false);
return $model;
}
private function isValidMorphConfiguration($attributes): bool
{
if (!isset($this->morphKey) || empty($this->morphMap)) {
return false;
}
if (!array_key_exists($this->morphKey, (array)$attributes)) {
return false;
}
return array_key_exists($attributes->{$this->morphKey}, $this->morphMap);
}
}