Ad 1 a 2:Váš datový model je v pořádku. Použití cizích klíčů je zde zásadní. Ještě jedna věc, o kterou se musíte postarat, je, že databáze by měla zajistit, že pro každý PŘÍSPĚVEK existuje záznam TÉMA. To se provádí nastavením POST.topic_id NOT NULL atribut. Toto je dostatečný bezpečnostní mechanismus na straně DB, protože zajišťuje, že žádný POST nezůstane bez TÉMATU. Bez ohledu na to, co nyní se svým PŘÍSPĚVKEM uděláte, jste povinni poskytnout TÉMA.
Ad 3:Spouštěč s uloženou procedurou se zde nedoporučuje, protože v tabulce TOPIC máte další data (IsSticky, IsLocked atd.), která možná budete chtít poskytnout při vytváření záznamu TOPIC. Také, pokud by byl takový spouštěč použitelný, návrh databáze by podléhal denormalizaci.
Ad 4:Na straně obchodní logiky si nyní můžete pomoci napsáním automatického mechanismu pro vytvoření záznamu TOPIC pokaždé, když je vytvořen nový POST záznam bez zadaného topic_id. Doporučuji k tomu použít nějaké ORM nebo využít datové modely dostupné v jakémkoli MVC frameworku. Návrh takových modelů by vypadal takto:
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;
}
// ...
}
Poznámka:podle správné praxe MVC by tyto modely měly být jediným místem, kde lze přímo pracovat s řádky tabulky. Jinak skončíte s chybami SQL (ale datový model zůstane koherentní, takže se nemusíte bát, že se něco pokazí).
Konečně využijte své modely v ovladači vrstva:
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
}
}
}