Héritage du modèle à Laravel

je travaille actuellement avec Laravel et je suis aux prises avec le fait que chaque modèle doit s'étendre de Eloquent et je ne suis pas sûr de savoir comment mettre en œuvre un hiérarchie des modèles (avec des tables différentes)

Par Exemple:

disons que j'ai un modèle abstrait Tool, puis un Modèle Hammer et Screwdriver qui s'étendent de L'outil.

maintenant, L'outil serait éloquent ... Mais, il N'y a pas de Table pour les outils, il y a une table pour les marteaux et une autre Table pour les tournevis, parce qu'ils ont des attributs différents.

comment spécifier que Hammer a une table et que Screwdriver a une table quand ils ont tous les deux étendre Outil? Et comment puis-je utiliser Eloquent pour appeler, par exemple, tous les outils?

Comme:

Tools::all()

cela devrait apporter tous les marteaux et tournevis parce qu'ils sont tous des outils

Est-ce possible en utilisant Eloquent?

16
demandé sur menjaraz 2014-05-31 23:09:35

4 réponses

même si j'aime l'approche des relations polymorphiques (PR) légèrement meilleure que l'héritage D'une seule Table ( STI), il ne semble toujours rien comme une véritable approche de l'héritage. Du point de vue du domaine (par exemple un diagramme de classe UML), c'est comme essayer d'utiliser une relation de composition au lieu d'un héritage.

du point de vue de la cohérence de la base de données, la relation polymorphe en elle-même est déjà une solution très étrange dans Laravel (IMHO). Comme il n'y ne peut pas être un seul champ qui est une clé étrangère à plusieurs tables, cela peut conduire à joindre des ID qui ne devraient pas être joints. Et inverser les relations qui ne sont pas obéies.

bien que je ne décrive pas réellement une solution au problème, je proposerais une approche différente Que PR et STI. Cette solution serait similaire à tableau D'hibernation par sous-classe approche. Je pense que Dauphe's extension to Eloquent va dans la même direction, sauf là semblent être quelques problèmes de mise en œuvre encore.

du point de vue de la base de données, un tableau par sous-classe signifierait aussi que la super-classe contient une colonne par sous-classe directe. Ensuite, vous pouvez mettre des contraintes de clé étrangère sur les id (non-null) et utiliser correctement les relations. Toutefois, il devrait toujours y avoir un peu de logique supplémentaire dans la classe Magic Eloquent de Laravel qui transforme l'objet demandé en le bon type.

Donc pour moi, fonctionnellement, l'Éloquent modèles hériter correctement du côté de PHP, tandis que la base de données peut encore utiliser les contraintes de clé étrangère.

10
répondu Joost 2015-02-22 13:07:34

Note: Vous ne pouvez pas utiliser une classe abstraite directement, elle doit être étendue par une classe enfant

Si votre Tool (abstract) modèle n'a pas tout table mappé à elle, alors vous n'avez pas besoin d'utiliser Tool::all et vous ne pouvez pas directement utiliser/instancier un abstract le modèle, mais vous pouvez utiliser un abstract modèle en tant que classe de base comme ceci:

abstract class Tool extends Eloquent {

    protected $validator = null;
    protected $errors = null;
    protected $rules = array();

    // Declare common methods here that
    // will be used by both child models, for example:

    public static function boot()
    {
        parent::boot();
        static::saving(function($model)
        {
            if(!$this->isvalid($model->toArray(), $this->rules) return false;
        });
    }

    protected function isvalid($inputs, $rules)
    {
        // return true/false
        $this->validator = Validator::make($inputs, $rules);
        if($this->validator->passes()) return true;
        else {
            $this->errors = $this->validator->errors();
            return false;
        }
    }

    public function getErrors()
    {
        return $this->errors;
    }

    public function hasErrors()
    {
        return count($this->errors);
    }

    // declare any abstract method (method header only)
    // that every child model needs to implement individually
}

class Hammer extends Tool {
    protected $table = 'hammers';
    protected $fillable = array(...);
    protected $rules = array(...); // Declare own rules

}

class Screwdriver extends Tool {
    protected $table = 'screwdrivers';
    protected $fillable = array(...);
    protected $rules = array(...); // Declare own rules
}

Utiliser Hammer et Screwdriver directement, mais jamais l' Tool modèle/classe parce que c'est un abstract classe, par exemple:

$hammers = Hammer:all();

or something like this:

$screwdriver = Screwdriver:create(Input::all());
if($screwdrivers->hasErrors()) {
    return Redirect::back()->withInput()->withErrors($screwdriver->getErrors());
}
return Redirect::route('Screwdriver.index');
7
répondu The Alpha 2014-05-31 20:38:56

j'ai trouvé un bug (fonctionnalité?) où Laravel 5 recherche la classe incorrecte si ParentClass et ChildClass ont la même chaîne $table. Ainsi, si vous appelez ParentClass:: all() dans certaines situations, il peut renvoyer des instances de ChildClass dans la collection!!

la réponse de L'Alpha m'a mené à une solution de contournement où vous créez la structure de classe suivante:

abstract class BaseClass extends BaseModel
{
    // ParentClass member variables and functions go here, to be shared between parent and child classes
}

class ParentClass extends BaseClass
{
    protected $table = 'your_table';

    // place no other member variables or functions in this class
}

class ChildClass extends BaseClass
{
    protected $table = 'your_table';

    // ChildClass member variables and functions go here
}

cela semble forcer Laravel à faire la recherche correcte lorsque vous appelez ParentClass:: all() ou ChildClass::all () puisque leur ancêtre commun n'a pas de table déclarée. Il suffit de traiter BaseObject comme ParentObject et de cette façon vous n'avez pas à salir votre concept d'héritage avec des détails de base de données qui ne devraient pas être pertinents. Je n'ai pas encore testé cela en profondeur, alors assurez-vous de noter la raison de l'existence de cette classe dans votre code pour les futures miettes de débogage.

1
répondu Zack Morris 2017-05-23 11:46:55

le seul ORM en PHP que je connaisse qui fait une table par hiérarchie de classe est Doctrine. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html. Et je crois qu'il peut cartographier ce genre de hiérarchie que vous prévoyez d'utiliser, une superclasse abstraite qui peut accéder à toutes les sous-classes.

pour intégrer la Doctrine à Laravel, je suggère d'utiliser le paquet laravel-doctrine que vous avez toutes les informations nécessaires dans ce site web http://www.laraveldoctrine.org/.

1
répondu Leandro Jacques 2017-03-17 13:48:48