MVC ở đây chúng ta có thể hiểu WebClient của odoo chính là view là Python chính là M và C.
Nhưng chúng ta nên nghĩ về WebClient như một application riêng biệt cũng cần có kiến trúc MVC riêng của nó.
Các class base trong MVC
Mình bắt đầu phân tích Kiến trúc MVC trong Odoo WebClient bằng cách đi vào mã nguồn bên trong /odoo/addons/web/static/src/core/mvc.js.
Nhìn hình bên trên chúng ta có thể thấy, file js này định nghĩa 4 thành phần chính tạo nên MVC đó là Model, Render, Controller và Factory.
- Model kiểm soát trạng thái, nó sẽ gọi máy chủ thông qua RPC để tìm nạp dữ liệu, cập nhật và tạo nó. Model không extend Widget bởi model chỉ chịu trách nhiệm cập nhật, thể hện trạng thái của dữ liệu(😁không biết mình nói vậy có đúng không nữa)
- Renderer được extend từ Widget có nhiệm vụ hiển thị dữ liệu cho end user thông qua việc thêm mọi thứ vào DOM. Class này k có quyền truy cập trực tiếp đến Model mà phải thông qua Controller và khi có sự kiện như click chuột,… thì Render sẽ dispath chúng đến Controller
- Controller có thể coi là một người điều phối giữ Model và Controller
- Factory hay còn gọi là View, nhiệm vụ chính là từ route URL nhận được, sẽ khởi tạo Model, Controller. Sau khi Controller hoạt động thì Factory sẽ không còn hoạt động nữa
Từ 4 ý chính trên, bạn có thể vào code đọc từng phần để hiểu thêm nhé!
Các lớp trừu tượng của Kiến trúc MVC
Như trong file mvc.js thì trong addons/web/static/src/js/views cũng được chia thành 4 lớp trừu tượng tương ứng với 4 file js
- AbstractModel (abstractmodel.js)
- AbstractRenderer (abstractrenderer.js)
- AbstractController (abstractcontroller.js)
- AbstractView (abstractview.js)
Về bản chất 4 lớp trừu tượng này cũng là extend từ các class trong file mvc.js mà mình đã nói ở trên😁. Bây giờ cùng tìm hiểu từng AbtractClass xem chúng được viết thêm những gì nhé!
Nhìn có vẻ phức tạp nhỉ, ok chúng ta sẽ đi tới từng lớp trừu tượng một nhé!
Model
Cũng giống như Model trong mvc.js, ở đây nó cũng có nhiệm vụ là nạp dữ liệu thông qua rpc và xử lý kết quả nhận được
Ví dụ với BasicModel (được sử dụng trong Form/List Views)
BasicModel mở rộng AbstractModel và là một triển khai thực sự của lớp trừu tượng, để làm cho những gì chúng ta đã nói trước đó rõ ràng hơn một chút, chúng ta sẽ xem xét ví dụ sau
Bạn có thể theo đường dẫn addons/web/static/src/js/views/basic/basic_model.js, bạn sẽ thấy class BasicModel được extend từ AbstractModel
ở đây chúng ta có thể thấy hàm _load:
|
|
Tương ứng với hàm _fetchRecord thực hiện gọi RPC và update dữ liệu hiển thị ra màn hình
|
|
Từ 2 hàm trên chúng ta có thể thấy lớp trừu tượng model hoạt động như thế nào rồi phải không nhỉ?
Renderer
Như đã nói ở trên, Render nhằm mục đích hiển thị giao diện cho người dùng, cũng như tương tác với các sự kiện trên UI để chuyển về cho Controller
Trong odoo 14, có 2 cách để bạn có thể tạo ra Render là extends AbstractRender hoặc tạo OWL Render, chúng tnhéa cùng đi nhanh qua 2 cách này
- Legacy AbstractRenderer
Chúng ta sẽ có 1 main function đó là _render mà cụ thể hơn nó gọi là _renderView bên dưới chứa logic của việc tạo giao diện người dùng.
Như đây là đoạn code của BasicRender:
|
|
Khi Controller muốn update, Render sẽ thiết lập và trả lại trạng thái của mình với getLocalState và setLocalState, trước khi được gỡ khỏi DOM, Rendercũng phải reset state với hàm resetLocalState
- OWL Renderer
OwlRendererWrapper như một người đứng giữa Render và Controller
|
|
Theo như mình biết thì các hàm ở đây không làm gì cả, nếu bạn muốn chúng hoạt động được thì phải override lại nó
Ví dụ như class PivotRenderer override lại resetLocalState để đặt lại trạng thái OWL component. Bạn có thể vào code của core Odoo từ 14 trở lên tìm class PivotRenderer các bạn sẽ thấy như sau:
|
|
Controller
Controller thường quản lý giao tiếp giữa Render và Model. Nhưng nó cũng chịu trách nhiệm trả lời các sự kiện từ ControlPanel hoặc SearchPanel.
|
|
Khi phương thức được start, Render sẽ được thêm vào DOM thông qua $el
Bây giờ chúng ta sẽ điểm qua 2 chức năng chính của Controller:
- Là cầu nối trung gian để giao tiếp giữa Render và Model
Thực tế Render sẽ kích hoạt một số sự kiện tới Controller và để đáp lại,Render sẽ thực hiện một số hành động
Với sự trợ giúp của ActionsMixin, Controller có thể đăng ký một số custom-event mà Controller đang lắng nghe và xử lý
|
|
Controller cũng xử lý một số sự kiện khi chúng ta click vào các nút trên giao diện có sẵn của Odoo
|
|
- Truy cập vào Control Panel và Search Panel
|
|
View
Khởi tạo 1 view thường có 2 tham số:
|
|
Mục tiêu chính của quá trình khởi tạo là điền các đối tượng cấu hình sẽ được chuyển đến các sub_component để tạo chúng:
|
|
3 dòng đầu thể hiện rõ ứng với 3 phần là : Renderer, Controller và Model, còn ***this.loadParams = {};***LoadParams sẽ được sử dụng để tải dữ liệu ban đầu với _loadData và nó sẽ chứa thông tin nếu view đang được “mở” với group-bey, context, domain, limit
Mục tiêu đối với mình là hiểu cách thức JS View thực hiện khi chúng ta tạo ra và bắt đầu từ XML mà chúng ta thường code hằng ngày như thế nào?