Jak stwierdził OP w swoich komentarzach: Projekt bazy danych jest już ustawiony i dlatego relacje polimorficzne Laravela nie wydają się być tutaj opcją.
Podoba mi się odpowiedź Chrisa Neala, ponieważ ostatnio musiałem zrobić coś podobnego (napisanie własnego sterownika bazy danych do obsługi Eloquent dla plików dbase / DBF) i zdobyłem duże doświadczenie z elementami wewnętrznymi Eloquent ORM Laravela.
Dodałem do tego mój osobisty gust, aby kod był bardziej dynamiczny, a jednocześnie zachowywał wyraźne mapowanie dla poszczególnych modeli.
Obsługiwane funkcje, które szybko przetestowałem:
Animal::find(1)
działa zgodnie z pytaniem
Animal::all()
działa również
Animal::where(['type' => 'dog'])->get()
zwróci AnimalDog
-objects jako kolekcję
- Dynamiczne mapowanie obiektów dla elokwentnej klasy, która korzysta z tej cechy
- Powrót do
Animal
-model w przypadku, gdy nie skonfigurowano mapowania (lub nowe mapowanie pojawiło się w DB)
Niedogodności:
- Przepisuje wewnętrznie
newInstance()
i newFromBuilder()
całkowicie model (skopiuj i wklej). Oznacza to, że jeśli będzie jakaś aktualizacja z frameworka do tych funkcji członkowskich, będziesz musiał ręcznie zaadaptować kod.
Mam nadzieję, że to pomoże i jestem gotowy na wszelkie sugestie, pytania i dodatkowe przypadki użycia w twoim scenariuszu. Oto przykłady użycia i przykłady:
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 {}
A to jest przykład tego, jak można go użyć i poniżej odpowiednich wyników:
$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);
co daje następujące wyniki:
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
A jeśli chcesz użyć MorphTrait
tutaj, jest to oczywiście pełny kod:
<?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);
}
}