Lý do mà tôi nói rằng các giao dịch không thuộc về lớp mô hình về cơ bản là thế này:
Mô hình có thể gọi các phương thức trong các mô hình khác.
Nếu một mô hình cố gắng bắt đầu một giao dịch, nhưng nó không biết liệu người gọi của nó đã bắt đầu một giao dịch hay chưa, thì mô hình phải có điều kiện bắt đầu giao dịch, như được hiển thị trong ví dụ mã trong câu trả lời của @ Bubba . Các phương thức của mô hình phải chấp nhận một cờ để người gọi có thể cho nó biết liệu nó có được phép bắt đầu giao dịch của chính nó hay không. Hoặc nếu không, mô hình phải có khả năng truy vấn trạng thái "trong giao dịch" của người gọi.
public function setPrivacy($privacy, $caller){
if (! $caller->isInTransaction() ) $this->beginTransaction();
$this->privacy = $privacy;
// ...action code..
if (! $caller->isInTransaction() ) $this->commit();
}
Điều gì sẽ xảy ra nếu người gọi không phải là một đối tượng? Trong PHP, nó có thể là một phương thức tĩnh hoặc đơn giản là mã không hướng đối tượng. Điều này rất lộn xộn và dẫn đến nhiều mã lặp lại trong các mô hình.
Đây cũng là một ví dụ về Khớp nối điều khiển , được coi là không tốt vì người gọi phải biết điều gì đó về hoạt động bên trong của đối tượng được gọi. Ví dụ: some trong số các phương thức của Mô hình của bạn có thể có tham số $ transactional, nhưng các phương thức khác có thể không có tham số đó. Làm cách nào để người gọi biết khi nào thông số quan trọng?
// I need to override method's attempt to commit
$video->setPrivacy($privacy, false);
// But I have no idea if this method might attempt to commit
$video->setFormat($format);
Giải pháp khác mà tôi đã thấy được đề xuất (hoặc thậm chí được triển khai trong một số khung như Propel) là tạo beginTransaction()
và commit()
không cần thực hiện khi DBAL biết nó đã ở trong một giao dịch. Nhưng điều này có thể dẫn đến sự bất thường nếu mô hình của bạn cố gắng cam kết và nhận thấy rằng mô hình của nó không thực sự cam kết. Hoặc cố gắng khôi phục và yêu cầu đó bị bỏ qua. Tôi đã viết về những điều bất thường này trước đây.
Thỏa hiệp mà tôi đã đề xuất là Người mẫu không biết về giao dịch . Mô hình không biết liệu yêu cầu của nó đối với setPrivacy()
là thứ mà nó phải cam kết ngay lập tức hay nó là một phần của bức tranh lớn hơn, một loạt các thay đổi phức tạp hơn liên quan đến nhiều Mô hình và chỉ nên được cam kết nếu tất cả những thay đổi này thành công. Đó là điểm của giao dịch.
Vì vậy, nếu Người mẫu không biết liệu họ có thể hoặc nên bắt đầu và thực hiện giao dịch của riêng họ hay không, thì ai sẽ làm? GRASP bao gồm Mẫu bộ điều khiển là một lớp không phải giao diện người dùng cho một ca sử dụng và nó được giao trách nhiệm tạo và kiểm soát tất cả các phần để hoàn thành ca sử dụng đó. Người kiểm soát biết về các giao dịch bởi vì đó là nơi mà tất cả thông tin có thể truy cập được về việc liệu trường hợp sử dụng hoàn chỉnh có phức tạp hay không và yêu cầu thực hiện nhiều thay đổi trong Mô hình, trong một giao dịch (hoặc có thể trong một số giao dịch).
Ví dụ tôi đã viết trước đây, đó là bắt đầu một giao dịch trong beforeAction()
phương thức của Bộ điều khiển MVC và cam kết nó trong afterAction()
, là một sự đơn giản hóa . Bộ điều khiển phải được tự do bắt đầu và cam kết bao nhiêu giao dịch mà nó yêu cầu một cách hợp lý để hoàn thành hành động hiện tại. Hoặc đôi khi Người kiểm soát có thể không kiểm soát giao dịch rõ ràng và cho phép Mô hình tự động gửi từng thay đổi.
Nhưng vấn đề là thông tin về (các) lực kéo nào là cần thiết mà Mô hình không biết - chúng phải được thông báo (dưới dạng tham số $ giao dịch) hoặc nếu không, hãy truy vấn nó từ người gọi của họ, dù thế nào cũng sẽ phải ủy quyền toàn bộ câu hỏi cho hành động của Người kiểm soát.
Bạn cũng có thể tạo Lớp dịch vụ của các lớp mà mỗi lớp biết cách thực hiện các trường hợp sử dụng phức tạp như vậy và liệu có bao gồm tất cả các thay đổi trong một giao dịch duy nhất hay không. Bằng cách đó, bạn tránh được rất nhiều mã lặp lại. Nhưng các ứng dụng PHP không phổ biến bao gồm một Lớp dịch vụ riêng biệt; hành động của Bộ điều khiển thường trùng hợp với Lớp dịch vụ.