I metodi di creazione e aggiornamento nel mio modello base passano attraverso alcuni passaggi: pre_save
, udpate_database
, post_save
. Il pre-salvataggio e il post-salvataggio sono specificatamente progettati per aiutare con la mancata corrispondenza dell'impedenza relazionale dell'oggetto. L'idea è che qualsiasi operazione di database che non è un semplice "valore di salvataggio X per la colonna Y nella tabella" viene gestita in pre_save
o post_save
. Quindi ad esempio potresti immaginare qualcosa di simile (esempio forzato per chiarezza):
$book_data = [
'isbn' => '1-2',
'name' => 'a cool book',
'chapters' => [
[ 'id' => 1, 'A Cool Chapter' ],
[ 'id' => 2, 'The Coolest Chapter' ]
]
];
$book = new book();
$book->create( $book_data );
In questo esempio chapters
è dati per una tabella figlio in una relazione uno-a-molti. pre_save
e post_save
sono responsabili per assicurarsi che le informazioni in chapters
arrivino alla tabella corretta, mentre update_database
aggiorna effettivamente la tabella books
con isbn e name. Ho trovato questa organizzazione generale molto efficace, ma mi sono imbattuto in un problema occasionale con esso.
pre_save
e post_save
hanno le proprie attività incorporate nella base del modello e devono sempre essere eseguite. Inoltre, sono previsti per essere estesi per aggiungere più funzionalità in base alle esigenze. Quindi, nel caso precedente, il mio post-salvataggio potrebbe sembrare qualcosa del tipo:
class book extends model_base {
protected function post_save( ... ) {
// necessary so the model base can do its thing
parent::post_save( ... );
// then our custom code
if ( isset( $input['chapters'] ) ) {
$this->set_chapters( $input['chapters'] );
}
}
}
Il problema che ho incontrato è che talvolta mi dimentico di chiamare il metodo genitore, che causa bug sottili. Di solito lo capisco abbastanza velocemente. Tuttavia, anche gli altri sviluppatori della mia squadra dimenticano di chiamare il genitore e tendono a capirlo meno rapidamente. Quindi sto pensando a un piccolo refactoring in modo che non ci sia bisogno di chiamare un genitore. La mia base di modello cambierebbe in modo efficace in qualcosa del genere:
class model_base {
public function create( $data ) {
// ... normal create stuff here
// now call $this->do_post_save instead of $this->post_save()
$this->do_post_save( ... );
}
protected function do_post_save( ... ) {
// ... do the stuff that needs to always happen here
// then call the old post_save
$this->post_save( ... );
}
protected function post_save( ... ) {
// this does nothing by default
}
}
In pratica sto aggiungendo un metodo aggiuntivo che funge da intermediario tra i metodi create e post_save. In questo modo non è più necessario chiamare il metodo genitore dall'interno di post_save, quindi non dovrai più preoccuparti di dimenticarti di farlo. Sto lasciando invariato il nome corrente, l'uso e la sequenza di chiamate di post_save
, quindi nessun codice dovrebbe interrompersi (ovviamente i nostri test saranno la misura finale di ciò). L'unico problema potenziale è che sto rendendo il modello base un po 'meno diretto, e chiunque veda questi due metodi con lo stesso nome potrebbe essere confuso a prima vista (inserirò commenti per aiutare chi guarda, ovviamente).
Tuttavia, dal punto di vista architettonico, questo ulteriore livello di separazione è un passo avanti o indietro? Soprattutto perché questa è la base del modello, voglio assicurarmi che ogni cambiamento abbia un senso.