Thiết kế các lớp thuộc Controller (MVC-phân tích thiết kế)

em chào mọi người!
Em đang ptthiết kế 1 website theo mô hình MVC. (thiết kế hướng cấu trúc) Em làm như sau:

  • Model: mỗi bảng trong database đều là 1 lớp Model (có n bảng thì có n lớp); các phương thức them,sua,xoa,getdanhsach…
  • Controller: đầu tiên em cho mỗi nhóm chức năng là 1 lớp Controller, các chức năng mức lá là các phương thức của lớp controller đó. Mỗi method trong controller gọi đến chỉ 1 giao diện . Nhưng vấn đề là vd: mình vừa xem danh sách Mặt hàng, tìm kiếm, bình luận trên cùng 1 giao diện.=>Trong khi ở đây MatHangController có các phương thức timkiem(…), xemdanhsach(),binhluan(…) gọi đến 3 view khác nhau (mà lẽ ra 3 cái này nó phải gộp lại làm 1). Vậy nên em thấy mỗi nhóm chức năng là 1 lớp Controller thì không đúng.

Vậy trong điễn đàn ai chỉ cho em cách tìm/thiết kế các lớp Controller như nào ạ (dựa vào đâu để tìm ra được các lớp controller ạ). Đối với cả view nữa ạ (theo phương pháp pttk hướng đối tượng hoặc cấu trúc cũng được ạ.)

Em cảm ơn.

1. Về Model bạn đang đi khá đúng. chỉ cần bổ sung một chút.

  • Hãy tạo một class Model trong đó chưa các thương thức như get(), insert(), update(), delete() và các thuộc tính như table, primary_key
  • Tiếp đó hãy để những Model khác kế thức từ class Model này. Ví dụ mình ko biết bạn dùng ngôn ngữ nào nên cí dụ với PHP
// Model.php
class Model
{
	protected $table = '';
	protected $primaryKey = 'id';

	public function get($col = '*') {
		$sql = "SELECT $col FROM $this->table";
		// Thực thi câu query trên rồi trả về kết quả.
		// ...
	}

	// Tạo các method khác như `insert()`, `update()`, `delete()`

}
// User.php
class User extends Model
{
	protected $table = 'users';
	// protected $primaryKey = 'id'; // Nếu khóa chính của bảng users là id rồi thì không cần dòng này
	protected $primaryKey = 'user_id'; // Nếu kháo chính của bảng users KHÔNG phải là id thì define vào.
}

Như vậy từ User hay Post, Comment bạn có thể gọi đến những method cơ bản như get(), insert(), update(), delete() mà ko cần phải viết lại.
Bạn nên bổ sung namespace cho các class nữa.

2. Về controller. Phần này bạn đang khá sai.

  • Trước hết, không phải tất cả các method trong controller đều phải trả về view.
  • Bạn hãy tập trung vào resource. Chính là User, Product, Post đó cũng sẽ là tên của các controller như: UserController
    PHP có Laravel framework app dụng cái này rất tốt bạn có thể tham khảo bảng sau.

Như bạn thấy URI của một số request có thể giống nhau nhưng HTTP Method khác nhau thì sẽ gọi đến một hàm (method) trong class khác nhau.
Tất nhiên để làm được việc này bạn phải viết code để kiểm tra HTTP method là gì rồi gọi đúng hàm (method) chứ ngôn ngữ không thể tự động làm được
Những kiến thức bạn cần có ở đoạn này chủ yếu về HTTP request và cách ngôn ngữ bạn đang dùng xử lý request. Là kiến thức cơ bản như không dễ để áp dụng đâu :grin:

Quay lại vấn đề của bạn.

Mình khuyên bạn chuển tất cả lên class, method sang tiếng anh. Hãy giữ dìn sự trong sáng cho tiếng Việt :smiley:

mình vừa xem danh sách Mặt hàng, tìm kiếm, bình luận trên cùng 1 giao diện.=>Trong khi ở đây MatHangController có các phương thức timkiem(…), xemdanhsach(),binhluan(…) gọi đến 3 view khác nhau (mà lẽ ra 3 cái này nó phải gộp lại làm 1)

Phân tích đoạn trên của bạn nhé.

mình vừa xem danh sách Mặt hàng, tìm kiếm, bình luận trên cùng 1 giao diện.

OK đoạn này đã rõ.

Đến cái này.

Trong khi ở đây MatHangController có các phương thức timkiem(…), xemdanhsach(),binhluan(…)

Dừng lại ở đây. Vì sao danh sách mặt hàng và tìm kiếm lại nằm ở 2 method khác nhau trong khi chúng chỉ là 1?

  • Đầu tiên hãy tạo 1 method để lấy danh sach mặt hàng. URL mình có được là localhost/products
  • Tiếp theo hãy chắc chắn rằng form tìm kiếm của bạn dùng method GET. Vậy nên khi bạn thực hiện tìm kiếm. URL mình có khi tìm kiếm sach là: localhost/products?search=sach

Như bạn thấy nó chỉ là URL của danh sách mặt hàng tuy nhiên có bổ sung query URL.

Code ví dụ:

// Product.php
class Product extends Model
{
    protected $table = 'products';

    // Tạo 1 function get list. Có thể dùng lại get() bên Model nhưng giờ làm như vậy cho nhanh
    
    public function getList($search = '') {
        // Câu này cho phần danh sách tất cả.
        $sql = "SELECT $col FROM $this->table ";

        // Nếu cần tìm kiếm
        if ($search) {
            $sql .= "WHERE name '%$search%'"
        }

        // Thực thi câu query trên và return thôi.
       // ...
   }
}
// ProductController.php
class ProductController
{
    // Mình tạo function index để lấy danh sách
    public function index() {
         $prdObj = new Product; // Cái này là Model nhé.

         $search = null;
         if (isset($_GET['search'])) {
              $search = $_GET['search'];
         }

         $products = $prdObj->getList($search);  // Đây là method get() mình đã tạo ở model phía trên nhé.

         // $products là danh sách sản phẩm. Có rồi thì trả về view thôi.
    }
}

Như bạn thấy danh sách và tìm kiếm là 1. chỉ cà cái có điều kiện cái không có thôi.

Tiếp theo method binhluan() của bạn. Mình không rõ đoạn này. bạn đang muốn bình luận ở trang tìm kiếm hay sao lại cùng view được?
Mình sẽ hiểu như là bạn muốn bình luận trong trang chi tiết sản phẩm.

Nói nhanh nó thế này.

  • ProductController::show() => Đây là method show view phần chi tiết, view này kèm form bình luận nhé. Có URL là localhost/products/1 method GET. 1 là ID của product nhé.

  • CommentController::store() => Đây là method thực hiện lưu comment. có URL là localhost/comments method POST

  • ProductController::show() bạn đã trả về view có form bình luận rồi, from bình luận này bạn để action là localhost/comments là xong.

  • CommentController::store() xử lý lưu comment xong thì redirect về lại localhost/products/1

Trên kia là những góp ý của mình về việc sử dụng MVC. Tất cả những ý kiến trên đều là từ mình không từ nguồn nào nên không được kiểm chứng là tốt và đúng nhé :sweat_smile:

  • Những sample code trên mình viết mà chưa test có thể sẽ có lỗi.
  • Đây không phải là tutorial nên bạn code code đó về không chạy được đâu.
  • Những kiến thức mình dùng ở đoạn phân thích trên gồm: PHP, OOP, MVC, HTTP request.
  • Có thể có lỗi chính tả ở đâu đó :grin:

Chúc bạn có thể hiểu và áp dùng MVC thanh công.

5 Likes

cám ơn letpet!
Còn vấn đề nữa, anh/chị có thể cho em biết làm sao để tìm ta tất cả các lớp của controller không ạ? (tức là dựa vào cơ sở nào/sơ đồ nào trong pttk để biết được các controller).

Ý bạn là một công thức để có được danh sách Controller từ các sơ đồ thiết kế của bạn? Theo mình biết là không.

Về cơ bản Controller sẽ hướng theo resource (tài nguyên). Như là User, Product, Category, Order. Vậy nên mỗi resource cần có Controller cho nó. Từ resource bạn có thể xác định cần bao Controller.

Dưới đây là phần tham khảo từ kinh nghiệm cá nhân, mình không đảm bảo tính đúng đắn nhé :sweat_smile:
Đôi khi, mình có dùng Controller như thế này (Khi làm với RESTful API): CategoryProductController. Rất lạ đúng không có nhắc đến 2 resource trong 1 controller.

Giả sử trong Database table categories quan hệ 1-n với products

Vẫn có 2 Controller cơ bản.

  • ProductController: Xử lý các tác vụ liên quan đến Product. list, show, create, update.
  • CategoryController: tương tự như trên.

Vậy CategoryProductController dùng để làm gì? CategoryProductController sinh ra để trả lời câu hỏi:
Nếu mình muốn tạo 1 method get list product theo category ID thì sẽ phải để trong Controller nào? Product hay Category?

Để rõ ràng trong từng resource. Product thì chỉ là product. Category thì chỉ là category. Vậy nên CategoryProductController sinh ra để xử lý các method có sự quan hệ.

Cách này không phải là tốt nhất nhưng nó giúp mình rõ ràng trong từng Controller. :ok_hand:

2 Likes

Category#products :smiley:

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?