mysql - Come posso implementare l'ereditarietà di una singola tabella usando l'eloquente di Laravel?



inheritance subclass (2)

Attualmente ho una classe modello chiamata Post .

class Post extends Eloquent {

    protected $table = 'posts';
    protected $fillable = array('user_id', 'title', 'description', 'views');

    /*
     * Relationships
     */

    public function user()
    {
        return $this->belongsTo('User');
    }

    public function tags()
    {
        return $this->belongsToMany('Tag', 'post_tags');
    }

    public function reactions()
    {
        return $this->hasMany('Reaction');
    }

    public function votes()
    {
        return $this->hasMany('PostVote');
    }

    //Scopes and functions...
}

Vorrei dividere i post in due tipi diversi; articles e questions . Pensavo che il modo migliore per farlo fosse l'ereditarietà, quindi Article e Question estenderebbero Post . Qual è il modo migliore per farlo e da dove cominciare?


Answer #1

da Laravel 5.2, Global Scope è disponibile:

class Article extends Post
{
    protected $table = 'posts';

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('article', function (Builder $builder) {
            $builder->where('type', 'article');
        });
    }
}

where type = 'article' viene aggiunto a tutte le query di Article come SoftDeletes .

>>> App\Article::where('id', 1)->toSql()
=> "select * from `posts` where `id` = ? and `type` = ?"

In realtà laravel fornisce il tratto di SoftDeletes utilizzando questa funzione.


Answer #2

Prima di scavare nell'ereditarietà di più tabelle, voglio perdere alcune parole sull'ereditarietà della tabella singola . L'ereditarietà di una tabella è il modo più semplice per l'ereditarietà con i modelli db.
Sono presenti più modelli associati alla stessa tabella e una colonna di type per distinguere tra le diverse classi del modello. Tuttavia, la ragione per cui normalmente si desidera implementare l'ereditarietà è perché i modelli hanno proprietà condivise, ma anche alcuni che sono unici per il modello.
Quando si utilizza l'ereditarietà di una tabella singola, la tabella sembra simile a quella ad un certo punto:

id   shared_column   question_column   article_column   question_column2   article_column2 etc...
1    Lorem           62                NULL             test               NULL
2    Ipsum           NULL              x                NULL               true

Finisci per avere molti valori NULL perché ci sono colonne non necessarie per un certo tipo di modello. E con molti record questo può influenzare la dimensione del database.

Tuttavia, in alcuni casi potrebbe essere ancora la soluzione migliore. Ecco un tutorial ben scritto che mostra come implementarlo in Laravel in un modo molto elegante.

Multi tabella di ereditarietà

Ora vediamo l'eredità multi tavolo. Con questo metodo dividi il tuo tavolo singolo in più di uno (beh, immagino che il nome abbia già dato quel tipo di via;)) Useremo una tecnica chiamata Polymorphism

Il nostro schema dell'esempio precedente sarebbe simile a questo:

posts table:

id   shared_column  postable_id  postable_type
1    Lorem          1            Question
2    Ipsum          1            Article


questions table:

id   question_column   question_column2
1    62                test


articles table:

id   article_column   article_column2
1    x                true

Molto più pulito se me lo chiedi ...

Le colonne interessanti qui sono postable_id e postable_type . Il tipo ci dice su quale tabella troveremo il nostro "riposo" del modello e l'id specifica la chiave primaria del record che gli appartiene. Nota che i nomi delle colonne potrebbero essere come vuoi, ma è convenzione chiamarlo "-able" .

Diamo un'occhiata ai modelli Eloquent ora.

Inviare

class Post extends Eloquent {
    // all your existing code

    public function postable(){
        return $this->morphTo();
    }
}

Domanda / Articolo / ogni altro tipo postabile

class Question extends Post {
    public function post(){
        return $this->morphOne('Post', 'postable');
    }
}

Si noti che in realtà non è necessario estendere da Post ma è possibile se si dispone anche di metodi che si desidera utilizzare. Ad ogni modo, la relazione polimorfica funzionerà con o senza di essa.

Ok questa è l'impostazione di base. Ecco come puoi utilizzare i tuoi nuovi modelli:

Recupera tutti i messaggi

$posts = Post::all();

Recupera tutte le domande

$questions = Question::all();

Ottieni le colonne delle domande da un post

$post = Post::find(1);
$question_column2 = $post->postable->question_column2;

Ottieni post proprietà dalla domanda

$question = Question::find(1);
$shared_column = $question->post->shared_column;

Controlla quale tipo è un post

$post = Post::find(1);
echo 'type: '.get_class($post->postable);
if($post->postable instanceof Question){
    // Looks like we got a question here
}

Crea una nuova domanda

Ora sopportami, creare un modello è un po 'più complicato. Se devi farlo in più punti della tua applicazione, ti suggerisco di scrivere una funzione riutilizzabile per questo.

// create a record in the questions and posts table

$question = new Question();
$question->question_column = 'test';
$question->save();

$post = new Post();
$post->shared_column = 'New Question Post';
$post->save();

// link them together

$question->post()->save($post);

Quindi, come puoi vedere, un database pulito viene fornito con il suo prezzo. Sarà un po 'più complesso gestire il tuo modello. Tuttavia puoi mettere tutta questa logica extra (ad esempio quella richiesta per creare un modello) in una funzione nella classe del tuo modello e non ti preoccupare troppo.

Inoltre, c'è un bel tutorial per l'ereditarietà multi tavolo con laravel. Forse aiuta;)





subclass