Como el OP declaró en sus comentarios: El diseño de la base de datos ya está configurado y, por lo tanto, las Relaciones Polimórficas de Laravel no parecen ser una opción aquí.
Me gusta la respuesta de Chris Neal porque recientemente tuve que hacer algo similar (escribir mi propio controlador de base de datos para admitir Eloquent para archivos dbase / DBF) y obtuve mucha experiencia con los componentes internos de Eloquent ORM de Laravel.
Le agregué mi sabor personal para hacer que el código sea más dinámico y al mismo tiempo mantener una asignación explícita por modelo.
Funciones compatibles que probé rápidamente:
Animal::find(1)
funciona como se le preguntó en su pregunta
Animal::all()
funciona bien
Animal::where(['type' => 'dog'])->get()
devolverá AnimalDog
-objetos como una colección
- Mapeo dinámico de objetos por clase elocuente que usa este rasgo
- Vuelva a
Animal
utilizar el modelo en caso de que no haya una asignación configurada (o si aparece una nueva asignación en la base de datos)
Desventajas
- Está reescribiendo el modelo interno
newInstance()
y newFromBuilder()
completamente (copiar y pegar). Esto significa que si habrá alguna actualización del marco para las funciones de este miembro, deberá adoptar el código a mano.
Espero que ayude y estoy preparado para cualquier sugerencia, pregunta y casos de uso adicionales en su escenario. Aquí están los casos de uso y ejemplos para ello:
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 {}
Y este es un ejemplo de cómo se puede usar y debajo de los resultados respectivos:
$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);
que resulta lo siguiente:
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
Y en caso de que quiera usar, MorphTrait
aquí está, por supuesto, el código completo:
<?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);
}
}