Annons 1 och 2:Din datamodell är bra. Att använda främmande nycklar är avgörande här. En sak till som du måste ta hand om är att databasen ska säkerställa att det finns en TOPIC-post för varje POST. Detta görs genom att ställa in POST.topic_id NOT NULL attribut. Detta är tillräcklig säkerhetsmekanism på DB-sidan, eftersom det säkerställer att ingen POST lämnas utan TOPIC. Oavsett vad du gör nu med din POST är du skyldig att tillhandahålla ett TOPIC.
Annons 3:En trigger med lagrad procedur rekommenderas inte här eftersom du har ytterligare data i din TOPIC-tabell (IsSticky, IsLocked, etc), som du kanske vill tillhandahålla när TOPIC-posten skapas. Dessutom, om en sådan trigger skulle vara tillämplig, skulle databasdesignen vara föremål för denormalisering.
Annons 4:På affärslogiksidan kan du nu hjälpa dig själv genom att skriva en automatiserad mekanism för att skapa TOPIC-posten varje gång en ny POST-post skapas utan specificerat topic_id. Jag rekommenderar att du använder lite ORM för detta eller drar fördel av datamodellerna som finns tillgängliga i alla MVC-ramverk. Ritningen för sådana modeller skulle se ut så här:
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;
}
// ...
}
Notera:som en god MVC-praxis bör dessa modeller vara det enda stället att direkt arbeta på tabellraderna. Annars kommer du att få SQL-fel (men datamodellen kommer att förbli sammanhängande, så du behöver inte oroa dig för att något ska gå sönder).
Äntligen dra nytta av dina modeller i kontrollen lager:
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
}
}
}