Iklan 1 dan 2:Model data Anda baik-baik saja. Menggunakan kunci asing sangat penting di sini. Satu hal lagi yang perlu Anda perhatikan adalah database harus memastikan ada catatan TOPIK untuk setiap POST. Ini dilakukan dengan menyetel POST.topic_id NOT NULL atribut. Ini adalah mekanisme keamanan yang memadai di sisi DB, karena memastikan bahwa tidak ada POST yang dibiarkan tanpa TOPIC. Apa pun yang Anda lakukan sekarang dengan POST Anda, Anda wajib memberikan TOPIK.
Iklan 3:Pemicu dengan prosedur tersimpan tidak disarankan di sini karena Anda memiliki data tambahan di tabel TOPIC Anda (IsSticky, IsLocked, dll), yang mungkin ingin Anda berikan pada pembuatan catatan TOPIC. Selain itu, jika pemicu seperti itu dapat diterapkan, desain basis data akan mengalami denormalisasi.
Iklan 4:Di sisi logika bisnis, Anda sekarang dapat membantu diri Anda sendiri dengan menulis mekanisme otomatis untuk membuat catatan TOPIC setiap kali catatan POST baru dibuat tanpa topic_id yang ditentukan. Saya merekomendasikan menggunakan beberapa ORM untuk ini atau memanfaatkan model data yang tersedia dalam kerangka kerja MVC apa pun. Cetak biru untuk model tersebut akan terlihat seperti ini:
abstract class AModel // this class should be provided by ORM or framework
{
/**
* @var PDO
*/
protected $_db_driver;
public function getLastInsertId()
{
$stmt = $this->_db_driver->prepare('SELECT LAST_INSERT_ID() AS id');
$stmt->execute();
return $stmt->fetch(PDO::FETCH_OBJ)->id;
}
public abstract function getFieldList();
}
class ForumTopicModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO topic VALUES (:id, :forum_id, :person_id, :is_locked, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'forum_id', 'person_id', 'is_locked', /*...*/);
}
// ...
}
class ForumPostModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO post VALUES (:id, :topic_id, :person_id, :subject, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'topic_id', 'person_id', 'subject', /*...*/);
}
public function insertInitialTopicPost(array $form_data)
{
$this->_db_driver->beginTransaction();
$result = true;
if ( empty($form_data['topic_id']) ) {
// no topic_id provided, so create new one:
$topic = new ForumTopicModel();
$topic_data = array_intersect_key(
$form_data, array_flip($topic->getFieldList())
);
$result = $topic->insert($topic_data);
$form_data['topic_id'] = $topic->getLastInsertId();
}
if ( $result ) {
$forum_post_data = array_intersect_key(
$form_data, array_flip($this->getFieldList())
);
$result = $this->insert($forum_post_data);
}
if ( $result ) {
$this->_db_driver->commit();
}
else {
$this->_db_driver->rollBack();
}
return $result;
}
// ...
}
Catatan:sebagai praktik MVC yang baik, model tersebut harus menjadi satu-satunya tempat untuk langsung beroperasi pada baris tabel. Jika tidak, Anda akan mendapatkan kesalahan SQL (tetapi model data akan tetap koheren, jadi Anda tidak perlu khawatir ada yang rusak).
Terakhir, manfaatkan model Anda di pengontrol lapisan:
class ForumPostController extends AController
{
public function createInitialTopicPostAction()
{
$form_data = $this->getRequest()->getPost(); /* wrapper for getting
the $_POST array */
// (...) validate and filter $form_data here
$forumPost = new ForumPostModel();
$result = $forumPost->insertInitialTopicPost($form_data);
if ( $result ) {
// display success message
}
else {
// display failure message
}
}
}