Quảng cáo 1 và 2:Mô hình dữ liệu của bạn ổn. Việc sử dụng khóa ngoại là rất quan trọng ở đây. Một điều nữa mà bạn cần quan tâm là cơ sở dữ liệu phải đảm bảo có một bản ghi CHỦ ĐỀ cho mỗi BÀI ĐĂNG. Điều này được thực hiện bằng cách đặt POST.topic_id NOT NULL thuộc tính. Đây là cơ chế an toàn đầy đủ ở phía DB, vì nó đảm bảo rằng không có POST nào bị bỏ lại nếu không có TOPIC. Bất kể bạn làm gì bây giờ với BÀI ĐĂNG của mình, bạn có nghĩa vụ cung cấp CHỦ ĐỀ.
Quảng cáo 3:Bạn không nên sử dụng trình kích hoạt với quy trình được lưu trữ ở đây vì bạn có dữ liệu bổ sung trong bảng TOPIC của mình (IsSticky, IsLocked, v.v.), mà bạn có thể muốn cung cấp khi tạo bản ghi TOPIC. Ngoài ra, nếu một trình kích hoạt như vậy có thể áp dụng được, thì thiết kế cơ sở dữ liệu sẽ là đối tượng của sự không chuẩn hóa.
Quảng cáo 4:Về khía cạnh logic nghiệp vụ, giờ đây bạn có thể tự hỗ trợ mình bằng cách viết một cơ chế tự động để tạo bản ghi TOPIC mỗi khi bản ghi POST mới được tạo mà không có topic_id được chỉ định. Tôi khuyên bạn nên sử dụng một số ORM cho việc này hoặc tận dụng các mô hình dữ liệu có sẵn trong bất kỳ khuôn khổ MVC nào. Bản thiết kế cho các mô hình như vậy sẽ trông giống như sau:
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;
}
// ...
}
Lưu ý:là một thực hành tốt MVC, các mô hình đó phải là nơi duy nhất để hoạt động trực tiếp trên các hàng của bảng. Nếu không, bạn sẽ gặp phải lỗi SQL (nhưng mô hình dữ liệu sẽ vẫn mạch lạc, vì vậy bạn không phải lo lắng rằng điều gì đó sẽ bị hỏng).
Cuối cùng, hãy tận dụng các mô hình của bạn trong bộ điều khiển lớp:
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
}
}
}