Advertentie 1 en 2:Uw datamodel is in orde. Het gebruik van externe sleutels is hierbij cruciaal. Nog iets waar je voor moet zorgen, is dat de database ervoor moet zorgen dat er een TOPIC-record is voor elke POST. Dit wordt gedaan door POST.topic_id NIET NULL in te stellen attribuut. Dit is voldoende veiligheidsmechanisme aan de DB-kant, omdat het ervoor zorgt dat er geen POST wordt achtergelaten zonder TOPIC. Wat je nu ook doet met je POST, je bent verplicht een ONDERWERP op te geven.
Ad 3:Een trigger met opgeslagen procedure wordt hier niet aanbevolen, omdat u aanvullende gegevens in uw TOPIC-tabel heeft (IsSticky, IsLocked, enz.), die u mogelijk wilt opgeven bij het maken van een TOPIC-record. Als een dergelijke trigger van toepassing zou zijn, zou het ontwerp van de database ook onderhevig zijn aan denormalisatie.
Ad 4:Wat de bedrijfslogica betreft, kun je jezelf nu helpen door een geautomatiseerd mechanisme te schrijven om het TOPIC-record te creëren telkens wanneer een nieuw POST-record wordt gemaakt zonder gespecificeerde topic_id. Ik raad aan om hiervoor wat ORM te gebruiken of gebruik te maken van de datamodellen die beschikbaar zijn in elk MVC-framework. De blauwdruk voor dergelijke modellen ziet er als volgt uit:
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;
}
// ...
}
Opmerking:als een goede MVC-praktijk zouden die modellen de enige plaats moeten zijn om direct op de tafelrijen te werken. Anders krijg je uiteindelijk SQL-fouten (maar het datamodel blijft coherent, dus je hoeft je geen zorgen te maken dat er iets kapot gaat).
Profiteer ten slotte van uw modellen in de controller laag:
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
}
}
}