text:
Trước khi bắt đầu
Bài viết này dành cho các nhà phá triển ứng dụng Web nghiên cứu công nghệ xử lý biểu mẫu XForms. Bài viết này là phần thứ ba của loạt bài viết sáu phần phát triển một bộ công cụ thanh toán cho một nghiệp vụ. Bài viết ngay trước đây đã giới thiệu một vài tính năng cơ bản của XForms có trong các khái niệm biểu mẫu HTML truyền thống.
Về bài viết này
Hầu như tất cả các nghiệp vụ có lợi nhuận đều cài đặt một mặt nào đó của quản lý thanh toán. Nghiệp vụ trong ví dụ làm rõ chức năng đó cho bài viết này (ta sẽ tạo một công cụ ngân sách cho X-Trapolate) tiến hành với giả thiết là khách hàng đưa ra đơn hàng chứa các món tách riêng và mỗi món đến từ một gian hàng riêng biệt. Mỗi đơn hàng đến từ một hoá đơn duy nhất và tiền lời từ mỗi món của một gian hàng trực tiếp góp phần vào lợi nhuận của gian hàng đó. Mỗi gian hàng cũng mua các thiết bị mà góp phần vào phí tổn của gian hàng đó. Quá trình lập ngân sách cho phép nhà quản lý tạo và huỷ các gian hàng, gian hàng con để thay đổi lợi nhuận dự trù, phí tổn dự trù của mỗi gian hàng hay để so sánh lợi nhuận và phí tổn dự trù đối với tổng hiện tại được xác định từ các đơn hàng và phí tổn đã ghi chép lại.
Công cụ thanh toán, cũng sẽ được tạo ra trong bài viết này, với mục đích là một cơ cấu cho phép nhân viên thanh toán phát sinh ra hoá đơn cho các tài khoản của khách hàng, in biên lai, hay gửi tài khoản vào các tập hợp. Cơ sở dữ liệu của các giao dịch đầu tiên được nhắc đến trong bài viết trước của loạt bài viết này, sau khi nâng cấp, chứa thông tin đầy đủ để thanh toán và có thể được truy vấn cho thông tin đó. Ngoài ra, số nhận dạng liên kết các tài khoản với từng đơn hàng với số tiền phải trả.
Về loạt bài viết này
Mục đích của loạt bài viết này là giải thích cách sử dụng XForms trong quá trình phát triển các ứng dụng Web thực tế và để hướng dẫn người đọc các sử dụng XForms.
- Phần 1 là sự giới thiệu tới toàn bộ loạt bài viết tổng quan hoá tất cả các bộ phận của kết quả cuối cùng và những khía cạnh nào có trong mỗi phần trong đặc tả XForms.
- Phần 2 trình bày về đăng nhập và quản lý tài khoản.
- Phần 3 trình bày việc phát triển những biểu mẫu gắn liền với việc quản lý tài khoản.
- Phần 4 tiếp tục trình bày về việc quản lý tài khoản và việc báo cáo những khía cạnh tính toán khác nhau của một nghiệp vụ.
- Phần 5 trình bày việc quản lý nợ và những cải tiến.
- Phần 6 kết thúc loạt bài viết với bản tóm tắt các công cụ phát triển, và một vài đề nghị để cải tiến và tiếp tục làm việc với bộ công cụ.
Các điều kiện tiên quyết
Bài viết này sử dụng cơ sở dữ liệu MySQL để lưu trữ và tham chiếu. Các lệnh SQL cần thiết xuất hiện trong suốt bài viết, nhưng cũng đòi hỏi kinh nghiệm làm việc với MySQL. PHPMyAdmin cung cấp truy cập tương đương cho phép cấu hình cơ sở dữ liệu MySQL và xem các mục từ một giao diện thực đơn đồ hoạ.
Mặc dù mục đích của loạt bài viết là để rèn luyện người đọc về các ứng dụng của XForms, một vài kiến thức nền tảng là cần thiết. Có một vài bài viết và loạt bài giới thiệu rất tốt về XForms có từ developerWorks (xem Tài nguyên). XForms được xây dựng trên XML, và, do đó, một kiến thức căn bản về XML cũng phải được trang bị trước.
Các công nghệ và khái niệm khác cũng có thể tham gia, nhưng chúng sẽ có phạm vi hạn chế hơn và sẽ không ảnh hưởng tới khả năng nắm bắt chủ đề của người đọc. Một vài phần mềm cũng sẽ được đòi hỏi:
- Một trình duyệt có khả năng hiển thị XForms, như là Firefox 2.0.1.
- Một máy chủ Web với PHP được kích hoạt, như là WAMP
- Một máy chủ SQL, MySQL, cũng là một phần của gói WAMP trong trường hợp này.
Tạo biểu mẫu ngân sách
Công cụ ngân sách có ý định đưa ra một giao diện người dùng để một người quản lý có thể hiểu và phát triển một kế hoạch ngân sách cho nghiệp vụ như một mục đích lâu dài. Phần này trình bày cho bạn cách thức để tạo một công cụ ngân sách sử dụng XForms với sự giúp đỡ của MySQL và PHP.
Khái quát
Khi người sử dụng lần đầu tiên nhìn thấy biểu mẫu ngân sách, nó hiện ra như ở Hình 1.
Hình 1. Trạng thái đầu tiên của biểu mẫu ngân sách
Một vài tính năng của XForms mà bài viết này chưa được nhắc đến xuất hiện trong hình này. Hộp ngày tháng là một tính năng mới, nó đóng vai trò giống như một hộp xổ xuống (drop-down box), nhưng người dùng có thể thay vào đó chọn một ngày trong bảng lịch hiện ra, như được thể hiện trong Hình 2.
Hình 2. Bảng lịch XForms để lựa chọn ngày
Tiếp đó, bạn sẽ thấy các để viết mã kiểu dữ liệu ngày tháng và lựa chọn lịch.
Kiểu dữ liệu ngày tháng và lựa chọn lịch
Như đã vừa được đề cập, XForms cung cấp sự độc lập của mô hình dữ liệu đối với sự thể hiện như là một tính năng then chốt. Trình duyệt thực tế sẽ chọn một cách thể thiện mà có ý nghĩa đối với trình duyệt đó. Nó có thể cho rằng rằng định nghĩa đầu vào của ngày tháng có thể chứa một vài widget mới và riêng biệt cho phép nó thể hiện như một hộp chọn ngày tháng. Ví dụ 1 thể hiện đoạn mã cho các hộp ngày tháng.
Ví dụ 1. Định nghĩa hộp lựa chọn ngày tháng
<xforms:input ref="instance('acctToolBdgtInst')/startDate"> <xforms:label>Start Date</xforms:label> </xforms:input>
Chú ý rằng sự lựa chọn ngày tháng giống hệt như định nghĩa tên người sử dụng trong Phần 2. Trình duyệt nhận các thông tin để xử lý hộp này khác so với ở vị trí khác. Cơ chế để tạo hộp lựa chọn ngày tháng xuất hiện trong một khai báo bind tại khai báo mô hình XForms. Khai báo bind đang được nói đến nằm trong Ví dụ 2.
Ví dụ 2. định nghĩa một kiểu dữ liệu ngày tháng
<xforms:bind nodeset="instance('acctToolBdgtInst')/startDate" type="xsd:date"/>
Thuộc
tính kiểu áp dụng cho nút
startDate trong
trường hợp (instance) của
acctToolBdgtInst
sử dụng khai báo. Khai báo của nút
startDate như một
xsd:date cho
phép nó hiển thị như một hộp lựa chọn lịch. Trình duyệt thực hiện chức
năng quyết định cách thức để hiển thị mục nhập thông tin, nhưng kiểu
của nó sẽ chi phối quyết định này. Rất ít kiểu dữ liệu thay đổi sự kết
xuất của các điều khiển biểu mẫu trên trình duyệt, nhưng một số kiểu
dữ liệu có áp dụng. Khi công nghệ XForms phổ biến và trở lên hoàn
thiện, các trình duyệt có thể thích nghi để đối xử đặc biệt với nhiều
kiểu dữ liệu hơn. Trình duyệt đòi hỏi một mẩu thông tin then chốt khác
cho phép thuộc tính kiểu mang bất kì ý nghĩa nào. Điểm này có thể
khiến người sử dụng mới của XForms thất vọng. Đoạn mã đặt trong Ví dụ
3 định nghĩa các không gian tên được sử dụng trong một tài liệu XHTML.
Sau một vài phép thử cho tới khi đúng, sự kết hợp riêng biệt này của
khai báo không gian tên
xsd và
xsd:date cho phép Firefox tạo ra một mục bảng
lịch.
Ví dụ 3. định nghĩa một kiểu dữ liệu ngày tháng

Tiếp đó, bạn sẽ khởi tạo một dữ liệu cá thể của biểu mẫu (form).
Khởi tạo dữ liệu cá thể cho XForms
Một tính năng ít rõ ràng hơn
được thể hiện trong Hình 2 là thực thể hộp ngày
tháng xuất hiện với ngày hiện tại trong nó. Cho dù tồn tại một vài lựa
chọn để đặt giá trị vào các nút XML, hầu hết các lựa chọn đều không áp
dụng tốt cho hành vi mong muốn trong trường hợp này, nghĩa là tải ngày
hiện tại vào trong nút. Phần 2 giải thích một vài phương pháp như là đặt trực tiếp
một giá trị vào khai báo XML của cấu trúc dữ liệu. Điều đó, cho thấy
cấu hình nút đó thành một giá trị cố định khi khởi động và, khi ứng
dụng bắt đầu ngày hôm sau, ngày tháng đó sẽ không còn là ngày hiện
tại. Gắn và sử dụng thuộc tính
calculate
cho phép lập trình viên có thể chỉ thị trình duyệt đặt một giá trị cho
nút; nhưng trong trường hợp này, gắn nút với
now() sẽ sinh ra một điều khiển mà người dùng thực hiện
một phép tính, người dùng ứng dụng chắc chắn không hiểu được điều
này.
Sử dụng sự kiện XForms-ready
Nút chỉ cần một giá trị chứa trong nó
tại thời điểm tải trang chứ sau đó thì không, trừ khi người dùng đặt
giá trị. Đoạn mã trong Ví dụ 4 thể hiện mã XForms thực hiện hoạt động
đó. Phần 2 giới thiệu một sự kiện gắn cho một trigger. Sự kiện
DOMActivate xuất hiện bên trong khai
báo của trigger trong biểu mẫu đăng nhập Ngân sách sử dụng một sự kiện
khác khai báo ở vị trí khác. Sự kiện
xforms-ready xảy ra khi trình duyệt đã tải hoàn thành cấu
trúc XForms, nhưng trước khi quyền điều khiển được chuyển cho người
dùng. Một thành tố khác trong xử lý XForms, thành tố setvalue sẽ hiện
ra ở
đây.
Ví dụ 4. Đặt giá trị ngày tháng tại sự kiện XForms-ready
<xforms:action ev:event="xforms-ready"> <xforms:setvalue ref="instance('acctToolBdgtInst')/startDate" value="now()"/> <xforms:setvalue ref="instance('acctToolBdgtInst')/endDate" value="now()"/> </xforms:action> </xforms:model>
Thành
tố setvalue định giá trị thuộc tính và áp đặt giá trị đó vào nút chỉ
ra bởi thuộc tính ref. Một hiện diện khác của setvalue tồn tại, nhưng
với khả năng đặc biệt cho phép ứng dụng của XPath tính giá trị hàm
now(), hàm sẽ trả về ngày tháng hiện
tại. Đoạn mã nhỏ sau đây được trình bày trong Ví dụ 5 trích từ biểu
mẫu thanh toán và giải thích ứng dụng của hàm XPath
substring để cắt kết quả của
now chỉ giữ lại
ngày.
Ví dụ 5. Cắt now chỉ giữ lại ngày
<xforms:setvalue ref="instance('acctToolBillInst')/endDate" value="substring(now(),1,10)"/>
Kiểm tra tình hợp lệ của dữ liệu và các kiểu dữ liệu XML Schema
Lý do biểu mẫu thanh
toán đòi hỏi kết quả đã chỉnh sửa từ
now
đến từ kiểu dữ liệu đã định nghĩa cho trường. Kiểu dữ liệu XML Schema
date thực hiện nhiệm vụ như một ràng
buộc XML Schema cho dữ liệu trong trường đó. Firefox ước lượng tính
hợp lệ của dữ liệu khi một sự kiện submit (gửi đơn) xảy ra. Bằng cách
giữ nguyên kết quả không chỉnh sửa của
now
trong hộp ngày tháng, quá trình gửi đơn không phàn nàn về việc không
thể hợp lệ hoá dữ liệu. Không may, khi điều đó xảy ra, đôi khi trình
duyệt trả lời với một thông báo "Not able to validate," nhưng những
lúc khác trình duyệt hoàn toàn không trả lời, để mặc người dùng nhấn
nút lại nhiều lần và thắc mắc điều gì có thể đang xảy ra.
Biểu
mẫu ngân sách không đặc biệt đòi hỏi ngày tháng được cắt bởi vì nó
không sử dụng cá thể với ngày tháng trong nó để gửi đơn. Thực tế này
được thể hiện trong Ví dụ 6. Nâng cấp câu truy vấn để sử dụng ngày
tháng như các ràng buộc cho truy vấn đòi hỏi cá thể dữ liệu như một
đối số, và do đó, đòi hỏi tính hợp lệ của XML Schema cho ngày bắt đầu
và ngày kết thúc, đã được khai báo là
xsd:date. Đối số hiện tại cho phương thức gửi đơn
load_budget là một cá thể
departmentsInst. Nút đối số,
acctToolBdgtInst, chứa startDate và endDate, cả hai đều bị
ràng buộc bởi xsd:date, đòi hỏi cắt giờ khỏi kết quả của
now() trước khi phương thức gửi đơn được thực
hiện.
Ví dụ 6. Tránh kiểm tra tính hợp lệ của XML Schema
<xforms:instance id="acctToolBdgtInst"> <formui xmlns=""> <startDate/> <endDate/> ... </xforms:instance> ... <xforms:submission id="load_budget" action="get_budget.php" method="get" replace="instance" instance="departmentsInst" ref="instance('departmentsInst')" /> ...
Tiếp theo, bạn sẽ thấy được biểu mẫu ngân sách sẽ trông như thế nào.
Cái nhìn đầu tiên tại các gian hàng
Khi người dùng kích hoạt nút Refresh, một hiển thị giống hoặc gần giống Hình 3 sẽ hiện ra. Mã XForm của nút Refresh chứa một trigger, kích hoạt cơ chế gửi đơn. Cài đặt này, về chức năng giống hệt một thành tố submit thông thường, thể hiện một biểu mẫu có thể có và sử dụng thành tố gửi đơn có hay không có một thành tố submit.
Hình 3. Lập ngân sách sau khi refresh
Sự khác nhau nhỏ giữa cài đặt submit và trigger nằm ở chỗ Firefox đạt các thành tố submit trên một dòng mới trừ khi được chỉ dẫn, còn đặt các thành tố trigger trên cùng dòng. Ví dụ 7 trình bày mã trigger.
Ví dụ 7. Tạo ra sự gửi đơn mà không cần thành tố submit
<xforms:trigger ref="instance('acctToolBdgtInst')/loadBudget"> <xforms:label>Refresh</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:dispatch name="xforms-submit" target="load_budget"/> </xforms:action> </xforms:trigger>
Tiếp theo bạn sẽ thấy bạn có thể sử dụng các thành tố action và dispatch trong XForm như thế nào.
Sử dụng action và dispatch trong XForms
Biểu
mẫu ngân sách có thể thực thi tốt với một thành tố XForm submit, nhưng
sử dụng trigger đem đến một lựa chọn thú vị. Thành tố action trong
XForms thực hiện các thành tố chứa bên trong nó liên tiếp. Sử dụng cơ
cấu này, một nút bấm duy nhất có thể chi phối nhiều cơ chế gửi đơn hay
thực hiện nhiều thao tác. Thành tố dispatch phục vụ như một người điều
khiển một sự kiện. Bằng cách sử dụng dispatch, một biểu mẫu XForm có
thể thực hiện gần như mọi hành động. Trường hợp này, thể hiện trong Ví dụ 7, đã sử dụng sự kiện
xforms-submit, khi được chỉ đến đích
load_budget khiến cho phương thức gửi đơn của
load_budget thực thi. Thành tố gửi đơn
load_budget được thể hiện trong Ví dụ
6.
Tiếp đến, bạn sẽ quan sát một số dữ liệu cá thể XML cho biểu mẫu ngân sách.
Cấu trúc dữ liệu XML của biểu mẫu ngân sách
Tới đây, giới thiệu cấu trúc giữ liệu cho các gian hàng là cần thiết. Ví dụ này sử dụng một cấu trúc dữ liệu phả hệ của các gian hàng trong XML. Ví dụ 8 trình bày một ví dụ ngắn gọn cách thức XML được cấu trúc. Cấu trúc phả hệ này cho phép quá trình tính toán thích hợp với từng gian hàng và gian hàng con của nó. Những cài đặt thay thế đặt tất cả các nút XML cùng một cấp nhưng bổ xung các nút thông tin để tạo khái niệm của phả hệ. Quá trình tính toán trở nên phức tạp tới mức bất khả thi đối với phương pháp đó.
Ví dụ 8. Phả hệ XML department
<?xml version="1.0" encoding="UTF-8"?> <budgetForm xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <departments> <maxid/> <hidden>0</hidden> <department id="9"> <name>United Cabinetry And Millwork</name> <department id="3"> <name>Boxgoods</name> <department id="4"> <name>Blanket Chests</name>
Phương
pháp phả hệ có một số sự khó khăn đáng quan tâm. Sự khó khăn chính đến
từ điều có thể làm gần như xong. Đoạn mã thể hiện trong Ví dụ 10 tạo ra hiển thị trong Hình 3. Ví dụ 9 trình bày một phiên bản lặp lại đơn giản hơn
nhiều, phiên bản mà cuối cùng không làm việc được bởi vì các thành tố
lặp lại coi nodelist như một cấu trúc thẳng, song song mà có thể được
chọn với một chỉ số nguyên cho các thao tác như là chèn (insert). Mã
nguồn Ví dụ 9 sử dụng biểu thức XPath
// để
tìm kiếm theo phả hệ tất cả các nút dưới các gian hàng tên là
department và sử dụng chúng như tập nodeset. Cuối cùng, Ví dụ 10 cung cấp một mô hình làm việc nơi mà
mỗi tập nút lặp lại sử dụng tất cả các nút gian hàng tại một cấp duy
nhất mà không sử dụng nút nào bên dưới. Phương pháp này cho phép quá
trình chèn một nút mới vào cây
department.
Ví dụ 9. Hiển thị phả hệ có chiều sâu động department
<xforms:repeat id="budgetRpt" nodeset="instance('departmentsInst')/departments//department" incremental="true">
Các thành tố lặp lại lồng nhau
Ví dụ 10 thể hiện cách thức sử dụng một cáu trúc lặp lại lồng nhau trong XForms như thế nào. Ví dụ này sử dụng một bộ lồng nhau 3 cấp. Mỗi lần lặp có nhiều thành tố XForms khác và chứa một thuộc tính ID. Thuộc tính ID cung cấp truy cập tới chỉ số của cấu trúc lặp cụ thể. Lặp của XForms chạy rất giống các điều khiển biểu mẫu (form) dựa trên tương tác người dùng trực tiếp hơn khác. Một hành vi quan trọng để hiểu về lặp là dòng cuối cùng người dùng nhấn lên được lưu nhớ lại cho lặp đó và có thể lấy được bằng một hàm. Sau đó chỉ số này có thể được sử dụng để trình bày chức năng chèn (insert).
Ví dụ 10. Hiển thị department có chiều sâu mã cố định
<xforms:repeat id="budgetRpt" nodeset="instance('departmentsInst')/departments/department" incremental="true">

  > 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 <xforms:repeat id="budgetRpt2" nodeset="department" incremental="true">

  —> 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 <xforms:repeat id="budgetRpt3" nodeset="department" incremental="true">

  ——> 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 </xforms:repeat> </xforms:repeat> </xforms:repeat>
Một
tính năng quan trọng nữa của cấu trúc lặp là sự tái định nghĩa của ngữ
cảnh hiện tại cho các truy vấn XPath. Cấu trúc lặp kép (two-repeat)
thứ 2 sử dụng tập nút department. Mặc dù chúng ám chỉ cùng một văn
bản, nhưng mỗi cái chọn một tập các nút khác nhau. Lý do cho điều này
là sự tái định nghĩa tăng dần của ngữ cảnh vị trí hiện tại. Bởi vì các
biểu thức XPath không chứa lời gọi tới
instance() hoặc một tiếp đầu tố
/ hay một vài thành phần bổ nghĩa khác, chúng được tham
chiếu tới ngữ cảnh hiện tại, chính là một trong các nút được chọn bởi
biểu thức XPath trong thuộc tính nodeset của thành tố
repeat.
Điều khiển biểu mẫu Textarea
Một điều khiển hiển thị biểu mẫu mới của XForms được thể hiện trong Ví dụ 10. Điểu khiển textarea cho phép người sử dụng nhập nhiều dòng dữ liệu. Nhấn Enter trong một điều khiển biểu mẫu textarea nhảy tới dòng văn bản tiếp theo chứ không phải để phát sinh một hành động. Trong trường hợp này, thành tố input có vẻ là giải pháp thích hợp hơn. Tuy nhiên, như Hình 4 trình bày, kết quả của việc thay thế các thành tố textarea với các thành tố input cho một hình ảnh không đẹp lắm. Chú ý rằng sự gióng hàng của tên các gian hàng trở nên xiên lệch và các con số gióng sang trái trong input và gióng phải nếu là các giá trị.
Hình 4. Sử dụng input thay thế cho textarea
Cũng phải nhớ rằng textarea được điểu khiển bằng cách sử dụng CSS sau, như đã được thể hiện trong Ví dụ 11.
Ví dụ 11. Điều khiển diện mạo của các hộp nhập dữ liệu textarea
 <xforms:model id="acctToolBillModel" > ...
Đoạn CSS trên làm cho các hộp textarea gióng thẳng nhau gọn gàng, như bạn đã thấy trong Hình 3.
Tiếp theo, bạn sẽ thấy cách thức để chèn thêm các thành tố department mới.
Chèn thêm các gian hàng mới
Hàm chèn (insert) trên biểu mẫu ngân sách thực thi như được thể thiện trong Hình 5. Thành tố chèn (insert) thực hiện thao tác tạo một nút dữ liệu trong cấu trúc dữ liệu XML. XForms tái xử lý cấu trúc dữ liệu và cập nhật nội dung hiển thị để phản ánh nút dữ liệu mới. Thành tố chèn (insert) đòi hỏi hai nút, một nodeset, và một chỉ số để chèn thành tố mới. Sự cảnh báo của chèn (insert) đến từ thực thế rằng nút mới mà chèn (insert) tạo ra được tạo bởi nhân bản nút cuối cùng trong tập nút. Hai khó khăn tiềm tàng nảy sinh từ cách thức xử lý này. Khó khăn đầu tiên đến từ dữ liệu có thể đã hoặc chưa nằm trong nút được nhân bản. Trong trường hợp ngân sách, một gian hàng cấp thứ hai có thể có hoặc không một gian hàng cấp thứ ba dưới nó.
Hình 5. Chèn một gian hàng
Khó khăn thứ hai hiện ra như là một kết quả của vấn đề đầu tiên. Nếu không có nút nào để bắt đầu, không có gì có thể được tạo ra bởi vì không có gì để nhân bản. Những các xử lý này tạo ra một vài thử thách đáng quan tâm trong phát triển ứng dụng XForms với XForms 1.0, nhưng trong trường hợp này nếu người dùng muốn một gian hàng cấp ba, câu trả lời là phải chèn một gian hàng cấp 2 khác, mà sẽ có một gian cấp 3 gắn vào nó miễn phí, đáng khen cho một nút bù nhìn được sử dụng cho mục đích đặc biệt. Mã chèn (insert) cấp thứ ba được trình bày trong Ví dụ 12.
Ví dụ 12. Third-level chèn (insert)
<xforms:trigger ref="instance('acctToolBdgtInst')/newDept3rd"> <xforms:label>Add New 3rd Level Department</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:insert nodeset="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department" at="index('budgetRpt3')" position="after"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department[index ('budgetRpt')] /department[index('budgetRpt2')]/ department[index('budgetRpt3')+1]/@id" value="instance('departmentsInst')//departments/maxid"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/name" value="'Enter new department name'"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/planPro" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/planExp" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/ordersTotal" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/expensesTotal" value="0"/> </xforms:action> </xforms:trigger>
Các bộ lọc XPath, chỉ số lặp, và đặt-giá-trị (setvalue)
Ví dụ 12 chứa rất nhiều mã; dù sao, sự kiểm
tra kĩ hơn cho thấy rằng phần lớn mã thực hiện các chứ năng giống hệt
nhau, để lại hai điều cần bàn là chèn (insert) và nhiều thuộc tính
setvalue. Thành tố chèn (insert) thực hiện như đoạn trước đã đề cập
đến; nó sao chép một nút và đặt bản sao mới vào cấu trúc dữ liệu. Chèn
(insert) cần một nodeset, và một vị trí hay chỉ số. Biểu thức nodeset,
một biểu thức XPath, chiếm hầu hết kí tự trắng trong Ví dụ 12, trông như một con yêu quái. Tuy
nhiên, biểu thức chỉ đơn thuần phục vụ để đánh chỉ số xuống tới nút
cấp ba sử dụng chỉ số từ các thành tố repeat đã được bàn trước đó. Một
nút nên được tạo có toán tử
[] trong một
biểu thức XPath không thực hiện điều mà một toán tử
[] điển hình của hầu hết ngôn ngữ làm. Trong
XPath, toán tử
[] phục vụ như một bộ lọc.
Trong trường hợp này, một số đơn được đặt vào bộ lọc để chọn chỉ số
đó; dù sao, rất nhiều thứ có thể được đặt vào bộ lọc.
Các dòng setvalue phục vụ để khởi tạo dữ liệu. Như đã đề cập ở trước, vì dữ liệu là một bản sao, nó có thể có những phần thông tin mà hoặc là không được áp dụng, hay thậm chí có thể gây rắc rối. Ở đây, một trong các khó khăn là duy trì các ID duy nhất của gian hàng. Điều đó được giải quyết bằng cách sử dụng giá trị maxId trong nút cao nhất của các gian hàng. Nó lần lượt được gắn với một hàm XPath để trở thành maxId (cộng thêm một) trong toàn bộ tập nút.
Tiếp đó, bạn sẽ cài đặt mã để bỏ đi các nút cấp 2 đã tồn tại.
Bỏ đi các nút
Ví dụ 13 thể hiện đoạn mã cho các nút bấm bỏ nút đi. Đơn giản hơn rất nhiều so với tính năng chèn (insert), bỏ nút sử dụng chỉ số lặp. Thành tố delete xoá cấu trúc dữ liệu XML được chỉ ra và, do đó, dữ liệu được hiển thị liên kết với thành tố đó sẽ bị xoá bỏ.
Ví dụ 13. Bỏ đi các nút cấp 2
<xforms:trigger ref="instance ('acctToolBdgtInst')/remove"> <xforms:label>Remove 2nd Level Department</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:delete nodeset="instance ('departmentsInst')/departments/department[index ('budgetRpt')]/department" at="index('budgetRpt2')"/> </xforms:action> </xforms:trigger>
Ẩn và hiện các nút
Biểu mẫu ngân sách sử dụng thuộc tính thích hợp để ẩn và hiện các gian hàng. Tính năng này hoạt động không được tốt trong trường hợp này bởi vì phần thụt lề thể hiện cấp của gian hàng. Một thành tố setvalue thực hiện chức năng này rất giống hàm khởi tạo trong một thủ tục chèn (insert). Bởi vì thuộc tính thích hợp đã được gắn với tất cả các nút hiển thị, ẩn các nút đi trở thành vấn đề thiết đặt các nút ẩn thành giá trị 1 và ngược lại đối với các nút hiện, như được thể hiện trong Ví dụ 14.
Ví dụ 14. Ẩn và hiện các nút
<xforms:trigger ref="instance('acctToolBdgtInst')/show2nd"> <xforms:label>Show 2nd and 3rd Level Children</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="instance ('departmentsInst')//departments/department[index ('budgetRpt')]/hidden" value="0"/> </xforms:action> </xforms:trigger> 	  <xforms:trigger ref="instance ('acctToolBdgtInst')/hide2nd"> <xforms:label>Hide 2nd and 3rd Level Children</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="instance ('departmentsInst')//departments/department[index ('budgetRpt')]/hidden" value="1"/> </xforms:action> </xforms:trigger>
Tiếp theo, bạn sẽ thấy cách thức để tạo một số kỹ thuật với các nút lá gian hàng như thế nào.
Bằng cách nào các gian hàng với các ngân sách gian hàng con là chỉ chứa thuộc tính đọc (read-only)
Với mục đích lập ngân sách, ngân sách của gian hàng được xác định bởi tổng của các ngân sách của các gian hàng dưới nó. Manh mối trực quan dẫn tới bản chất read-only của gian hàng cha là số liệu không thể thay đổi được. Mỗi một giá trị, lợi nhuận, phí tổn của ngân sách, có hai điều khiển biểu mẫu (form). Bằng cách kích hoạt (enable) điểu khiển biểu mẫu textarea, giá trị trở thành read-write và manh mối trực quan là gian hàng là một nút lá được tạo. Ngược lại, kích hoạt (enable) điểu khiển biểu mẫu đầu ra tạo một hiển thị read-only, chỉ ra rằng gian hàng có các gian hàng con. Quá trình chuyển đổi giữa read-only và read-write và hành vi tính toán số liệu xảy ra như một kết quả của sự gắn kết tới dữ liệu thích hợp và tính toán. Ví dụ 15 thể hiện đoạn mã cho sự gắn kết.
Ví dụ 15. Các phép tính và sự tương thích
<xforms:bind nodeset="instance ('departmentsInst')//department/planPro" relevant="../department/@id=false()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planExp" relevant="../department/@id=false()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/leafPlanExp" relevant="../department/@id=false()" calculate="../planExp"/> <xforms:bind nodeset="instance ('departmentsInst')//department/leafPlanPro" relevant="../department/@id=false()" calculate="../planPro"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planProDisplay" calculate="sum(..//leafPlanPro)" relevant="../department/@id=true()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planExpDisplay" calculate="sum(..//leafPlanExp)" relevant="../department/@id=true()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/curPro" calculate="round(sum(..//ordersTotal))"/> <xforms:bind nodeset="instance ('departmentsInst')//department/curExp" calculate="round(sum(..//expensesTotal))"/> <xforms:bind nodeset="instance ('departmentsInst')//departments/maxid" calculate="max(//department/@id)+1"/>
Biểu
thức XPath tất cả đều sử dụng toán tử
// để
chọn tất cả các nút department. Các nút sau đó tiếp tục được khử tham
chiếu cho đến khi tất cả các trường của planPro trong tất cả các nút
department đều có kết nối thích hợp đặt cho chúng. Nhắc lại từ bài viết trước là kí tự
@ chỉ ra
một thuộc tính. ID là một thuộc tính, và do đó, được tham chiếu với kí
tự
@ trong biểu thức XPath. Sự so sánh là
cho
true() hay
false(). Hai hàm XPath đặc biệt đó định các giá trị logic
(Boolean) đúng và sai. Được sử dụng theo cách được trình bày trong Ví dụ 15, sự so sánh trả về true nếu nút
được tham chiếu tồn tại. Cũng phải chú ý ứng dụng của các hàm làm tròn
(round) và tính tổng (sum) của XPath. Cũng cần xem hàm lấy giá trị lớn
nhất (max) trong áp dụng bên trên khi thành tố //departments/maxid
được đặt. Thành tố maxid được sử dụng để đặt ID cho các hàng mới được
thêm vào, đảm bảo các ID riêng biệt với nhau.
Tiếp theo bạn sẽ tìm hiểu một chút về cách thức để sinh dữ liệu cá thể cho biểu mẫu sử dụng DOM của PHP.
Đề cập ngắn gọn về sinh dữ liệu biểu mẫu ngân sách sử dụng PHP
Vì XForms đòi hỏi toàn bộ cấu trúc cơ bản của dữ liệu XML, cấu trúc dữ liệu phải được tạo từ đầu bởi kịch bản PHP. Kịch bản PHP cố gắng thực hiện với ít hàm nhất có thể; dù sao, dữ liệu này cũng đòi hỏi một cấu trúc phả hệ từ một bảng cơ sở dữ liệu SQL, lại là một cấu trúc thẳng. Kịch bản PHP get_budget thực hiện một chức năng đơn: nó thu thập tất cả các gian hàng từ bảng department trong cơ sở dữ liệu SQL, và xây dựng lại phả hệ dựa trên ID của mỗi nút và ID được lưu trữ của nút cha. Giá trị 0 được cho là nút gốc.
Các truy vấn SQL cho nhiệm vụ này không đáng để quan tâm nhiều. Cơ sở dữ liệu SQL là cần thiết để sử dụng PHP, như đã thể hiện trong Ví dụ 16. Giải thuật được sử dụng là tìm kiếm theo chiều sâu (depth-first traversal), một nút được rút ra khỏi một hàng đợi (queue) và được tham chiếu như một nút cha trong mỗi vòng lặp. ID của nút đó sẽ được truy vấn như một nút cha, trả về tất cả các nút con của gian hàng đó.
Ví dụ 16. Truy vấn SQL cho gian hàng
$query = sprintf('SELECT * FROM `departments` WHERE Parent=%s AND NOT(department_id=%s);',$parentId, $parentId); $queryData = mysql_query($query, $sqldb); if (!$queryData) die ('Could not execute acct db query: '.$query.' because: ' . mysql_error()); while ($row = mysql_fetch_assoc($queryData)) {
Tài liệu XML khởi tạo một chuỗi tĩnh (static string), như đã thể hiện trong Ví dụ 17. Sử dụng nó như một cơ sở, các nút mới sẽ được tạo ra và thêm vào lặp lại, tiến dần xuống dưới cây theo phương pháp tìm kiếm sâu. Quá trình thêm các nút mới và sử dụng cấu trúc danh sách liên kết của DomNodes trong PHP được thể hiện trong Ví dụ 17.
Ví dụ 17. Xây dựng cây XML DOMNode và khởi tạo DomDocument
$doc = new DomDocument('1.0'); $doc->loadXml('<?xml version="1.0" encoding="UTF-8"?> <budgetForm xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <departments> <maxid/> <hidden>0</hidden> </departments> </budgetForm>'); ... do { ... if($curParent->previousSibling && $curParent- >previousSibling->nodeName == 'department') $curParent = $curParent->previousSibling; else $curParent = $curParent->childNodes->item($curParent- >childNodes->length-1); $parentId = $curParent->getAttribute('id'); } while ($parentId);
Chú ý cẩn thận khi xử lý các nút để không thực sự coi danh sách nút là một hàng đợi mà sử dụng hàm remove, bởi vì nút thực sự sẽ mất đi và XML thì không chứa bất cứ nút nào dưới kết quả cuối cùng.
Đó là vỏ bọc cho biểu mẫu ngân sách! Chú ý rằng không phải tất cả mọi thứ trong đó đều được bao quát, nhưng bạn có thể xem mã đầy đủ cho biểu mẫu (form), bao gồm dữ hỗ trợ PHP và SQL khởi tạo cho cơ sở dữ liệu của bạn, trong phần tải về đã được cung cấp.
Biểu mẫu thanh toán (Billing)
Biểu mẫu thanh toán sử dụng nhiều khái niệm tương tự như biểu mẫu ngân sách với một vài bổ xung mới. Biểu mẫu XForms thanh toán giới thiệu thủ tục để mở một cửa sổ mới hiển thị thông tin thích hợp để in một hoá đơn. Phần này cài đặt biểu mẫu này, trạng thái ban đầu được thể hiện trong Hình 6.
Hình 6. Trạng thái ban đầu của biểu mẫu thanh toán
Hiển thị bảng
Mặc dù bảng HTML không hỗ trợ XForms và Firefox chưa cài đặt thuộc tính repeat của XForms, vẫn có thể lặp lại toàn bộ cấu trúc bảng. Biểu mẫu XForms thanh toán sử dụng cơ cấu đó để hiển thị dữ liệu thanh toán. Hiển thị có được từ cấu trúc lặp đơn cấp như được thể hiện trong Ví dụ 18. Hình 7 thể hiện biểu mẫu sau khi nhấn nút Refresh/Load Accounts.
Hình 7. Biểu mẫu thanh toán đã được làm mới
Ví dụ 18. Các điều khiển XForms trực quan cho biểu mẫu thanh toán
<xforms:repeat id="acctRpt" nodeset="instance ('accts')//account">

  <xforms:output ref="acctId"/> 	  <xforms:output ref="creationDate"/> 	  <xforms:output ref="totalDue"/> 	  <xforms:output ref="accountState"/> 	  <xforms:trigger style="display: inline" ref="submitCollection"> <xforms:label>COLLECT!</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeDelURI" value="concat('doBillingAction.php? action=delinquent&acct=',../../acctId,'&amount=',../../payment Amt,'&bal=',../../totalDue)"/> <xforms:load ref="@makeDelURI" show="new"/> </xforms:action> </xforms:trigger> </xforms:trigger> <xforms:trigger ref="submitCredit"> <xforms:label>Issue Credit</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeCreURI" value="concat('doBillingAction.php? action=credit&acct=',../../acctId,'&amount=',../../totalDue)"/> <xforms:load ref="@makeCreURI" show="new"/> </xforms:action> </xforms:trigger> 	  <xforms:textarea ref="paymentAmt"/> 	  <xforms:trigger ref="pay"> <xforms:label>Record</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeRctURI" value="concat ('doBillingAction.php? action=makepayment&acct=',../../acctId,'&amount=',../../paymen tAmt,'&bal=', ../../totalDue - ../../paymentAmt)"/> <xforms:insert nodeset="../payment" at="count (../payment)" position="after"/> <xforms:setvalue ref="../payment[count (../payment)]/paymentDate" value="substring(now(),1,10)"/> <xforms:setvalue ref="../payment[count (../payment)]/amount" value="../../paymentAmt"/> <xforms:setvalue ref="../payment[count (../payment)]/acctId" value="../../acctId"/> <xforms:load ref="@makeRctURI" show="new"/> <xforms:setvalue ref="../paymentAmt" value="0"/> </xforms:action> </xforms:trigger> 	  <xforms:trigger ref="bill"> <xforms:label>Bill</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeBilURI" value="concat('doBillingAction.php? action=createbill&acct=',../../acctId,'&amount=',../../payment Amt,'&bal=',../../totalDue)"/> <xforms:load ref="@makeBilURI" show="new"/> </xforms:action> </xforms:trigger>

 </xforms:repeat> <xforms:bind nodeset="instance('accts')//bill" relevant="../accountState != 'Paid' and ../accountState != 'Current' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//pay" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//paymentAmt" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//submitCollection" relevant="../accountState = 'Delinquent'"/> <xforms:bind nodeset="instance('accts')//submitCredit" relevant="../accountState = 'Credit'"/> <xforms:bind nodeset="instance('accts')//accountState" calculate=" if(number(../totalDue)>0, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 30, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 90, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 180, 'Delinquent', 'Pastdue'), 'Due'), 'Current'), if(number(../totalDue) = 0,'Paid','Credit'))"/>
Tiếp theo bạn sẽ tìm hiểu về lưu trữ số tiền thanh toán cho các tài khoản.
Lưu trữ số tiền thanh toán
Quá trình lưu trữ đỏi hỏi một giấy biên lai và chỗ chứa dữ liệu. Công cụ thanh toán giải quyết tình huống này bằng cách mở một cửa sổ mới nơi dữ liệu yêu cầu hiển thị trong một định dạng thích hợp cho in ấn và gửi thư. Cũng với sự thuận tiện như vậy, khách hàng có thể nhận được e-mail hoặc bất cứ một trong số các tiến trình thủ tục nào đó. Các nút bấm Record, Bill, và Collections thực thi tương tự bằng cách định dạng bằng tay một hoạt động gửi đơn GET và sử dụng kết quả đó như một đối số cho load với thuộc tính xuất hiện đầu tiên trong loạt bài viết tại thời điểm này. Thuộc tính show=new chỉ cho trình duyệt tạo một cấu trúc thể hiện mới. Hình 8 cho thấy kể quả khi kích hoạt nút bấm COLLECT!.
Hình 8. Hiển thị thu tiền
Hình 9 cho thấy kết quả khi kích hoạt nút bấm Record.
Hình 9. Hiển thị biên lai
Kích hoạt nút bấm Bill cho kết quả thể hiện trong Hình 10.
Hình 10. Hiển thị hoá đơn
Chọn nút bấm Issue Credit cho kết quả thể hiện trong Hình 11.
Hình 11. Hiển thị tín dụng
Tiếp đó, bạn sẽ thấy cách thức để đặt rất nhiều trạng thái khác nhau của một tài khoản dựa trên ngày tháng của lần trả tiền cuối cùng.
Tính toán các trạng thái có thể cho mỗi tài khoản
Ba trạng thái khác nhau xuất hiện trong Hình 7. Mỗi trạng thái tạo ra các điều kiện khác nhau cho hiển thị. Các tài khoản có quyết toán lớn hơn không và chưa trả tiền quá 180 ngày có hiển thị nút bấm COLLECT!, trong khi các tài khoản có quyết toán nhỏ hơn hoặc bằng 0 không có nút bấm nào cả, tuy vậy một quyết toán âm cuối cũng sẽ cần một nút Credit. Ví dụ 19 chứa các khai báo xác đáng và các khai báo tính toán tạo ra hiệu ứng này.
Ví dụ 19. Tính toán trạng thái tài khoản
<xforms:bind nodeset="instance('accts')//bill" relevant="../accountState != 'Paid' and ../accountState != 'Current' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//pay" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//paymentAmt" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//submitCollection" relevant="../accountState = 'Delinquent'"/> <xforms:bind nodeset="instance('accts')//submitCredit" relevant="../accountState = 'Credit'"/> <xforms:bind nodeset="instance('accts')//accountState" calculate=" if(number(../totalDue)>0, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate)) > 30, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate)) > 90, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate))>180, 'Delinquent', 'Pastdue'), 'Due'), 'Current'), if(number(../totalDue) = 0,'Paid','Credit'))"/>
Một
hàm XPath mới xuất hiện trong đoạn mã này, hàm
days-from-date, biến đổi giá trị ngày trở thành một giá
trị nguyên tính từ đầu kỷ nguyên. Hàm đó cho phép các tính toán như
thế này xảy ra. Như Ví dụ 19 thể hiện, sự gia
tăng xuất phát từ một tài khoản Paid tới một tài khoản Delinquent dựa
trên một quyết toán dương và vượt qua 30, 90, rồi 180 ngày, và nếu
không tồn tại lần nộp tiền nào (nghĩa là không tồn tại ngày nộp tiền
nào), thì ngày tạo được sử dụng để so sánh. Một tính năng đáng quan
tâm của Ví dụ 19 là toán tử và (and).
Nút bấm Bill áp dụng cho các tài khoản đến hoặc quá hạn trả. Bằng các
thực hiện hai phép so sánh logic, sự ảnh hưởng đó đã đạt được. Toán tử
logic và (and) là nguyên văn từ and, không phải kí hiệu
& hay && như rất nhiều lập trình viên đã quen
thuộc.
Các con số được xử lý như thế nào
Một cách âm thầm, XForms thực hiện một lượng lớn xử lý số học. Cấu trúc dữ liệu cơ bản bao gồm có một nút tài khoản với một tập các nút có tên order và một tập các nút có tên payment. Bằng cách tính tổng/số lượng đơn đặt hàng trong tập nút, tổng lượng tiền khác hàng đã đồng ý trả cho hãng đã sẵn dùng. Đầu tiên, dù thế nào, cơ cấu XForm cũng phải tính số lượng của mỗi đơn đặt hàng. Tổng của mỗi đơn hàng được tính toán bởi phương trình trong Ví dụ 20.
Ví dụ 20. Số lượng đơn hàng và tổng giá tiền
<xforms:bind nodeset="instance('accts')//order/amount" calculate="../quantity * ../unitPrice * (1-../discount)"/> <xforms:bind nodeset="instance('accts')//totalDue" calculate="sum(..//order/amount) - sum(..//payment/amount)"/>
Ví dụ 20 giải thích một khả năng nội tại của bộ xử lý XForms đã cung cấp một số sự trợ giúp cho lập trình viên. Trình duyệt xử lý mã XForms giải quyết sự phụ thuộc trong các trật tự thích hợp. Trong trường hợp này, đơn hàng/số lượng các nút cần thiết để được giải quyết trước nút totalDue. Thuộc tính relevant trong Ví dụ 19 giải thích một hành vi tương tự với sự phụ thuộc vào relevant khi tính toán trạng thái các tài khoản.
Phép tính trạng thái tài khoản đòi hỏi ngày tháng. Một
vài lựa chọn để cung cấp thông tin tồn tại đó. Một lựa chọn là sử dụng
PHP để trích ngày đòi hỏi, và một lựa chọn khác là cho dữ liệu được
sắp xếp. XForms 1.0, đáng tiếc, không cung cấp hàm tính giá trị nhỏ
nhất
min có thể giải quyết ngày tháng chính
xác. Đoạn mã trong Ví dụ 21, dù sao, giải thích một cách tiếp cận mạnh
hơn để tìm ra ngày nhỏ nhất trong danh sách. Tiến trình bao gồm cả cắt
mỗi trường ngày tháng ra thành từng phần cấu tạo cho phép so sánh rồi
ráp kết quả lại trở thành một ngày
tháng.
Ví dụ 21. Tìm ngày đặt hàng (ngày tạo) nhỏ nhất và ngày trả (ngày trả cuối) lớn nhất
<xforms:bind nodeset="instance('accts')//order/yearCreate" calculate="substring(../orderDate, 1, 4)"/> <xforms:bind nodeset="instance('accts')//minYearCreate" calculate="min(..//yearCreate)"/> <xforms:bind nodeset="instance('accts')//order/monthCreate" calculate="if(../yearCreate = ../../minYearCreate, number(substring(../orderDate, 6, 2)), 13)"/> <xforms:bind nodeset="instance('accts')//minMonthCreate" calculate="min(..//order/monthCreate)"/> <xforms:bind nodeset="instance('accts')//order/dayCreate" calculate="if(../monthCreate = ../../minMonthCreate, number(substring(../orderDate, 9, 2)), 32)"/> <xforms:bind nodeset="instance('accts')//minDayCreate" calculate="min(..//order/dayCreate)"/> <xforms:bind nodeset="instance('accts')//creationDate" calculate="concat(../minYearCreate, '-', if(../minMonthCreate < 10, concat('0',../minMonthCreate), ../minMonthCreate), '-', if(../minDayCreate < 10, concat('0',../minDayCreate), ../minDayCreate))"/> <xforms:bind nodeset="instance('accts')//payment/yearPaid" calculate="substring(../paymentDate, 1, 4)"/> <xforms:bind nodeset="instance('accts')//maxYearPaid" calculate="max(..//yearPaid)"/> <xforms:bind nodeset="instance('accts')//payment/monthPaid" calculate="if(../yearPaid = ../../maxYearPaid, number(substring(../paymentDate, 6, 2)), 0)"/> <xforms:bind nodeset="instance('accts')//maxMonthPaid" calculate="max(..//payment/monthPaid)"/> <xforms:bind nodeset="instance('accts')//payment/dayPaid" calculate="if(../monthPaid = ../../maxMonthPaid, number(substring(../paymentDate, 9, 2)), 0)"/> <xforms:bind nodeset="instance('accts')//maxDayPaid" calculate="max(..//payment/dayPaid)"/> <xforms:bind nodeset="instance('accts')//lastPaymentDate" calculate="concat(../maxYearPaid, '-', if(../maxMonthPaid < 10, concat('0',../maxMonthPaid), ../maxMonthPaid), '-', if(../maxDayPaid < 10, concat('0',../maxDayPaid), ../maxDayPaid))"/>
Tiếp đó, bạn sẽ thu được một vài quan điểm về cách thức cải thiện thời gian tải XForm của bạn cho một lượng lớn dữ liệu cá thể.
Cập nhập số liệu mà không phải chờ
Một sự cải thiện rõ ràng cho biểu mẫu XForms thanh toán hiện tại là sự bổ sung của giới hạn số lượng các tài khoản được hiển thị một lúc, do đó trình duyệt không phải duy trì cấu trúc dữ liệu của toàn bộ cơ sở dữ liệu. Cho toàn bộ cơ sở dữ liệu trong cấu trúc dữ liệu tập trung vào một việc quan trọng, dẫu vậy. Cần một lượng đáng kể thời gian để truy vấn, xây dựng và tải cấu trúc dữ liệu và quá trình đó rất quý giá đối với sự kiên nhẫn của người dùng. Biểu mẫu này cài đặt một phím tắt để tăng khả năng nhận điều khiển của biểu mẫu (form). Hành động lưu trữ chứa một khối chèn (insert) giống như phần chèn (insert) đã miêu tả trong biểu mẫu ngân sách. Đoạn mã được nói đến xuất hiện trong Ví dụ 18.
Đoạn mã chèn (insert) tạo một nút payment mới và lưu dữ liệu thích hợp vào nút đó. Thay đổi cấu trúc dữ liệu nội tại không thay đổi cơ sở dữ liệu; dù sao, kịch bản PHP sinh ra biên lại có thể dễ dàng truy cập cơ sở dữ liệu đưa ra một đáp trả nhanh hơn rất nhiều so với gửi một kho chứa toàn bộ tập nút của tài khoản, hay thậm chí chỉ một nút đơn lẻ, có thể đòi hỏi tải lại toàn bộ cấu trúc dữ liệu. Do tính toán các phương trình trong Ví dụ 20, quyết toán cho tài khoản đó ngay lập tức phản ánh thông tin mới.
Bạn sắp hoàn thành rồi! Trong phần cuối cùng của đoạn này bạn sẽ học cách PHP trợ giúp biểu mẫu thanh toán
PHP làm được gì cho biểu mẫu XForms thanh toán
PHP phục vụ như một giao diện tới cơ sở dữ liệu SQL trong suốt loạt bài viết này với hấu hết công việc được thực hiện bởi bộ xử lý XForms. Một giới hạn của XForms, dù thế nào, là sự đòi hỏi một nút phải tồn tại. XForms không thể dễ dàng tạo một nút mới và nó đòi hỏi một khuôn mẫu khi một nút mới được tạo. Hầu hết dữ liệu sau XForm thanh toán là dữ liệu đã được tính toán và lưu trữ dữ liệu đã tính toán ngốn không gian đĩa quý giá. PHP tạo một tập nút tài khoản và lồng đơn đặt hàng với các nút payment bên dưới nó, bổ sung thêm các nút vào các nút đơn hàng để tổng hợp và đồng thời cũng vào tài khoản để tính toán. Đoạn mã để thực hiện chức năng này rất giống với đoạn mã đã thể hiện để tính toán các nút ngân sách chỉ khác là cấu trúc dữ liệu kết quả có ít cấp phả hệ hơn.
Tốt lắm! Bạn đã hoàn thành bài viết này. Bây giờ hãy xem lại bài tóm tắt để tìm hiểu thêm về các vấn đề sắp tới, trong Phần 4.
Tóm tắt
Bài viết này giới thiệu một vài khái niệm với XForms. Bài viết bao gồm mở cửa sổ trình duyệt mới và các lặp lồng nhau, đồng thời cũng giải quyết cơ cấu chèn. Biểu mẫu ngân sách giới thiệu quá trình bỏ các nút đi và các đòi hỏi nội tại của cấu trúc dữ liệu để cho phép hiển thị. Các phép tính toán chi tiết, chuỗi phụ thuộc, và nhiều hàm XPath mới xuất hiện trong cả biểu mẫu ngân sách và thanh toán.
Các phần tiếp theo của loạt bài viết này tinh chế cả cài đặt XForms khi cần thiết và các kĩ năng tham gia vào cái đặt XForms. Tiếp theo, Phần 4 cài đặt quản lý tài sản và một vài công cụ hành chính.
Tải về
Tài nguyên
Học tập
- Tìm hiểu những yếu tố cần thiết để tạo ra thế hệ tiếp theo của các biểu mẫu trong bài viết sau đây: Căn bản XForms (developerWorks, Tháng 9 năm 2006).
- Để mở rộng kiếm thức về XForms của bạn hãy xem các loạt bài viết về XForms sau: Introduction to XForms, Part 1: The new Web standard for forms, Introduction to XForms, Part 2: Forms, models, controls, and submission actions, và Introduction to XForms, Part 3: Using actions and events (developerWorks, Tháng 9 năm 2006).
- Tải về The PHP Manual.
- Tìm hiểu thêm về các sự kiện gửi đơn của XForms trong XForms tip: Using form submission events (developerWorks, Tháng 11 năm 2006).
- Tìm hiểu cách để nhận dữ liệu XForms trong Java (developerWorks, Tháng 10 năm 2006), Perl (developerWorks, Tháng 10 năm 2006), và PHP (developerWorks, Tháng 10 năm 2006).
- IBM XML certification: Tìm hiểu cách để trở thành một nhà phát triển XML và các công nghệ liên quan được chứng nhận bởi IBM.
- XML technical library: Xem sét the developerWorks XML Zone để có rất nhiều các bài viết và lời khuyên chuyên môn, bài hướng dẫn, các chuẩn và IBM Redbooks.
- developerWorks technical events and webcasts: Theo kịp với công nghệ trong những bài này.
- Tìm hiểu tất cả về XML và thêm về XForms trong IBM developerWorks XML zone.
Lấy sản phẩm và công nghệ
- Tài liệu XForms Recommendation được duy trì bởi W3C.
- Tải MozzIE, một điều khiển nguồn mở cho phép bạn kết xuất XForms trong Internet Explorer.
Thảo luận
- developerWorks blogs: Trở thành một phần trong cộng đồng developerWorks.
Bình luận
-
Vùng dữ liệu trên developerWorks
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
-
Vùng mã nguồn mở trên developerWorks
Xem các bài viết về HTML, CSS, JavaScript,...
-
Điện toán đám mây
Tìm hiểu về điện toán đám mây

markdown:
## Trước khi bắt đầu
Bài viết này dành cho các nhà phá triển ứng dụng Web nghiên cứu công nghệ xử lý biểu mẫu XForms. Bài viết này là phần thứ ba của loạt bài viết sáu phần phát triển một bộ công cụ thanh toán cho một nghiệp vụ. Bài viết ngay trước đây đã giới thiệu một vài tính năng cơ bản của XForms có trong các khái niệm biểu mẫu HTML truyền thống.
### Về bài viết này
Hầu như tất cả các nghiệp vụ có lợi nhuận đều cài đặt một mặt nào đó của quản lý thanh toán. Nghiệp vụ trong ví dụ làm rõ chức năng đó cho bài viết này (ta sẽ tạo một công cụ ngân sách cho X-Trapolate) tiến hành với giả thiết là khách hàng đưa ra đơn hàng chứa các món tách riêng và mỗi món đến từ một gian hàng riêng biệt. Mỗi đơn hàng đến từ một hoá đơn duy nhất và tiền lời từ mỗi món của một gian hàng trực tiếp góp phần vào lợi nhuận của gian hàng đó. Mỗi gian hàng cũng mua các thiết bị mà góp phần vào phí tổn của gian hàng đó. Quá trình lập ngân sách cho phép nhà quản lý tạo và huỷ các gian hàng, gian hàng con để thay đổi lợi nhuận dự trù, phí tổn dự trù của mỗi gian hàng hay để so sánh lợi nhuận và phí tổn dự trù đối với tổng hiện tại được xác định từ các đơn hàng và phí tổn đã ghi chép lại.
Công cụ thanh toán, cũng sẽ được tạo ra trong bài viết này, với mục đích là một cơ cấu cho phép nhân viên thanh toán phát sinh ra hoá đơn cho các tài khoản của khách hàng, in biên lai, hay gửi tài khoản vào các tập hợp. Cơ sở dữ liệu của các giao dịch đầu tiên được nhắc đến trong bài viết trước của loạt bài viết này, sau khi nâng cấp, chứa thông tin đầy đủ để thanh toán và có thể được truy vấn cho thông tin đó. Ngoài ra, số nhận dạng liên kết các tài khoản với từng đơn hàng với số tiền phải trả.
### Về loạt bài viết này
Mục đích của loạt bài viết này là giải thích cách sử dụng XForms trong quá trình phát triển các ứng dụng Web thực tế và để hướng dẫn người đọc các sử dụng XForms.
[Phần 1](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool1/)là sự giới thiệu tới toàn bộ loạt bài viết tổng quan hoá tất cả các bộ phận của kết quả cuối cùng và những khía cạnh nào có trong mỗi phần trong đặc tả XForms. [Phần 2](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool2/)trình bày về đăng nhập và quản lý tài khoản.
- Phần 3 trình bày việc phát triển những biểu mẫu gắn liền với việc quản lý tài khoản.
- Phần 4 tiếp tục trình bày về việc quản lý tài khoản và việc báo cáo những khía cạnh tính toán khác nhau của một nghiệp vụ.
- Phần 5 trình bày việc quản lý nợ và những cải tiến.
- Phần 6 kết thúc loạt bài viết với bản tóm tắt các công cụ phát triển, và một vài đề nghị để cải tiến và tiếp tục làm việc với bộ công cụ.
### Các điều kiện tiên quyết
Bài viết này sử dụng cơ sở dữ liệu MySQL để lưu trữ và tham chiếu. Các lệnh SQL cần thiết xuất hiện trong suốt bài viết, nhưng cũng đòi hỏi kinh nghiệm làm việc với MySQL. PHPMyAdmin cung cấp truy cập tương đương cho phép cấu hình cơ sở dữ liệu MySQL và xem các mục từ một giao diện thực đơn đồ hoạ.
Mặc dù mục đích của loạt bài viết là để rèn luyện người đọc về các ứng
dụng của XForms, một vài kiến thức nền tảng là cần thiết. Có một vài
bài viết và loạt bài giới thiệu rất tốt về XForms có từ developerWorks
(xem
[Tài nguyên](#resources)). XForms được xây dựng
trên XML, và, do đó, một kiến thức căn bản về XML cũng phải được trang
bị trước.
Các công nghệ và khái niệm khác cũng có thể tham gia, nhưng chúng sẽ có phạm vi hạn chế hơn và sẽ không ảnh hưởng tới khả năng nắm bắt chủ đề của người đọc. Một vài phần mềm cũng sẽ được đòi hỏi:
- Một trình duyệt có khả năng hiển thị XForms, như là Firefox 2.0.1.
- Một máy chủ Web với PHP được kích hoạt, như là
[WAMP](http://www.wampserver.com/en/)
- Một máy chủ SQL, MySQL, cũng là một phần của gói WAMP trong trường hợp này.
## Tạo biểu mẫu ngân sách
Công cụ ngân sách có ý định đưa ra một giao diện người dùng để một người quản lý có thể hiểu và phát triển một kế hoạch ngân sách cho nghiệp vụ như một mục đích lâu dài. Phần này trình bày cho bạn cách thức để tạo một công cụ ngân sách sử dụng XForms với sự giúp đỡ của MySQL và PHP.
### Khái quát
Khi người sử dụng lần đầu tiên nhìn thấy biểu mẫu ngân sách, nó hiện ra như ở Hình 1.
##### Hình 1. Trạng thái đầu tiên của biểu mẫu ngân sách
![ Trạng thái đầu tiên của biểu mẫu ngân sách](fig01.jpg)
Một vài tính năng của XForms mà bài viết này chưa được nhắc đến xuất hiện trong hình này. Hộp ngày tháng là một tính năng mới, nó đóng vai trò giống như một hộp xổ xuống (drop-down box), nhưng người dùng có thể thay vào đó chọn một ngày trong bảng lịch hiện ra, như được thể hiện trong Hình 2.
##### Hình 2. Bảng lịch XForms để lựa chọn ngày
![ Bảng lịch XForms để lựa chọn ngày](fig02.jpg)
Tiếp đó, bạn sẽ thấy các để viết mã kiểu dữ liệu ngày tháng và lựa chọn lịch.
### Kiểu dữ liệu ngày tháng và lựa chọn lịch
Như đã vừa được đề cập, XForms cung cấp sự độc lập của mô hình dữ liệu đối với sự thể hiện như là một tính năng then chốt. Trình duyệt thực tế sẽ chọn một cách thể thiện mà có ý nghĩa đối với trình duyệt đó. Nó có thể cho rằng rằng định nghĩa đầu vào của ngày tháng có thể chứa một vài widget mới và riêng biệt cho phép nó thể hiện như một hộp chọn ngày tháng. Ví dụ 1 thể hiện đoạn mã cho các hộp ngày tháng.
##### Ví dụ 1. Định nghĩa hộp lựa chọn ngày tháng
<xforms:input ref="instance('acctToolBdgtInst')/startDate"> <xforms:label>Start Date</xforms:label> </xforms:input>
Chú
ý rằng sự lựa chọn ngày tháng giống hệt như định nghĩa tên người sử
dụng trong
[Phần 2](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool2/). Trình duyệt nhận các thông tin để xử lý hộp này khác
so với ở vị trí khác. Cơ chế để tạo hộp lựa chọn ngày tháng xuất hiện
trong một khai báo bind tại khai báo mô hình XForms. Khai báo bind
đang được nói đến nằm trong Ví dụ
2.
##### Ví dụ 2. định nghĩa một kiểu dữ liệu ngày tháng
<xforms:bind nodeset="instance('acctToolBdgtInst')/startDate" type="xsd:date"/>
Thuộc
tính kiểu áp dụng cho nút
startDate trong
trường hợp (instance) của
acctToolBdgtInst
sử dụng khai báo. Khai báo của nút
startDate như một
xsd:date cho
phép nó hiển thị như một hộp lựa chọn lịch. Trình duyệt thực hiện chức
năng quyết định cách thức để hiển thị mục nhập thông tin, nhưng kiểu
của nó sẽ chi phối quyết định này. Rất ít kiểu dữ liệu thay đổi sự kết
xuất của các điều khiển biểu mẫu trên trình duyệt, nhưng một số kiểu
dữ liệu có áp dụng. Khi công nghệ XForms phổ biến và trở lên hoàn
thiện, các trình duyệt có thể thích nghi để đối xử đặc biệt với nhiều
kiểu dữ liệu hơn. Trình duyệt đòi hỏi một mẩu thông tin then chốt khác
cho phép thuộc tính kiểu mang bất kì ý nghĩa nào. Điểm này có thể
khiến người sử dụng mới của XForms thất vọng. Đoạn mã đặt trong Ví dụ
3 định nghĩa các không gian tên được sử dụng trong một tài liệu XHTML.
Sau một vài phép thử cho tới khi đúng, sự kết hợp riêng biệt này của
khai báo không gian tên
xsd và
xsd:date cho phép Firefox tạo ra một mục bảng
lịch.
##### Ví dụ 3. định nghĩa một kiểu dữ liệu ngày tháng

Tiếp đó, bạn sẽ khởi tạo một dữ liệu cá thể của biểu mẫu (form).
### Khởi tạo dữ liệu cá thể cho XForms
Một tính năng ít rõ ràng hơn
được thể hiện trong
[Hình 2](#fig2) là thực thể hộp ngày
tháng xuất hiện với ngày hiện tại trong nó. Cho dù tồn tại một vài lựa
chọn để đặt giá trị vào các nút XML, hầu hết các lựa chọn đều không áp
dụng tốt cho hành vi mong muốn trong trường hợp này, nghĩa là tải ngày
hiện tại vào trong nút. [Phần 2](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool2/) giải thích một vài phương pháp như là đặt trực tiếp
một giá trị vào khai báo XML của cấu trúc dữ liệu. Điều đó, cho thấy
cấu hình nút đó thành một giá trị cố định khi khởi động và, khi ứng
dụng bắt đầu ngày hôm sau, ngày tháng đó sẽ không còn là ngày hiện
tại. Gắn và sử dụng thuộc tính
calculate
cho phép lập trình viên có thể chỉ thị trình duyệt đặt một giá trị cho
nút; nhưng trong trường hợp này, gắn nút với
now() sẽ sinh ra một điều khiển mà người dùng thực hiện
một phép tính, người dùng ứng dụng chắc chắn không hiểu được điều
này.
### Sử dụng sự kiện XForms-ready
Nút chỉ cần một giá trị chứa trong nó
tại thời điểm tải trang chứ sau đó thì không, trừ khi người dùng đặt
giá trị. Đoạn mã trong Ví dụ 4 thể hiện mã XForms thực hiện hoạt động
đó.
[Phần 2](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool2/) giới thiệu một sự kiện gắn cho một trigger. Sự kiện
DOMActivate xuất hiện bên trong khai
báo của trigger trong biểu mẫu đăng nhập Ngân sách sử dụng một sự kiện
khác khai báo ở vị trí khác. Sự kiện
xforms-ready xảy ra khi trình duyệt đã tải hoàn thành cấu
trúc XForms, nhưng trước khi quyền điều khiển được chuyển cho người
dùng. Một thành tố khác trong xử lý XForms, thành tố setvalue sẽ hiện
ra ở
đây.
##### Ví dụ 4. Đặt giá trị ngày tháng tại sự kiện XForms-ready
<xforms:action ev:event="xforms-ready"> <xforms:setvalue ref="instance('acctToolBdgtInst')/startDate" value="now()"/> <xforms:setvalue ref="instance('acctToolBdgtInst')/endDate" value="now()"/> </xforms:action> </xforms:model>
Thành
tố setvalue định giá trị thuộc tính và áp đặt giá trị đó vào nút chỉ
ra bởi thuộc tính ref. Một hiện diện khác của setvalue tồn tại, nhưng
với khả năng đặc biệt cho phép ứng dụng của XPath tính giá trị hàm
now(), hàm sẽ trả về ngày tháng hiện
tại. Đoạn mã nhỏ sau đây được trình bày trong Ví dụ 5 trích từ biểu
mẫu thanh toán và giải thích ứng dụng của hàm XPath
substring để cắt kết quả của
now chỉ giữ lại
ngày.
##### Ví dụ 5. Cắt now chỉ giữ lại ngày
<xforms:setvalue ref="instance('acctToolBillInst')/endDate" value="substring(now(),1,10)"/>
### Kiểm tra tình hợp lệ của dữ liệu và các kiểu dữ liệu XML Schema
Lý do biểu mẫu thanh
toán đòi hỏi kết quả đã chỉnh sửa từ
now
đến từ kiểu dữ liệu đã định nghĩa cho trường. Kiểu dữ liệu XML Schema
date thực hiện nhiệm vụ như một ràng
buộc XML Schema cho dữ liệu trong trường đó. Firefox ước lượng tính
hợp lệ của dữ liệu khi một sự kiện submit (gửi đơn) xảy ra. Bằng cách
giữ nguyên kết quả không chỉnh sửa của
now
trong hộp ngày tháng, quá trình gửi đơn không phàn nàn về việc không
thể hợp lệ hoá dữ liệu. Không may, khi điều đó xảy ra, đôi khi trình
duyệt trả lời với một thông báo "Not able to validate," nhưng những
lúc khác trình duyệt hoàn toàn không trả lời, để mặc người dùng nhấn
nút lại nhiều lần và thắc mắc điều gì có thể đang xảy ra.
Biểu
mẫu ngân sách không đặc biệt đòi hỏi ngày tháng được cắt bởi vì nó
không sử dụng cá thể với ngày tháng trong nó để gửi đơn. Thực tế này
được thể hiện trong Ví dụ 6. Nâng cấp câu truy vấn để sử dụng ngày
tháng như các ràng buộc cho truy vấn đòi hỏi cá thể dữ liệu như một
đối số, và do đó, đòi hỏi tính hợp lệ của XML Schema cho ngày bắt đầu
và ngày kết thúc, đã được khai báo là
xsd:date. Đối số hiện tại cho phương thức gửi đơn
load_budget là một cá thể
departmentsInst. Nút đối số,
acctToolBdgtInst, chứa startDate và endDate, cả hai đều bị
ràng buộc bởi xsd:date, đòi hỏi cắt giờ khỏi kết quả của
now() trước khi phương thức gửi đơn được thực
hiện.
##### Ví dụ 6. Tránh kiểm tra tính hợp lệ của XML Schema
<xforms:instance id="acctToolBdgtInst"> <formui xmlns=""> <startDate/> <endDate/> ... </xforms:instance> ... <xforms:submission id="load_budget" action="get_budget.php" method="get" replace="instance" instance="departmentsInst" ref="instance('departmentsInst')" /> ...
Tiếp theo, bạn sẽ thấy được biểu mẫu ngân sách sẽ trông như thế nào.
### Cái nhìn đầu tiên tại các gian hàng
Khi người dùng kích hoạt nút Refresh, một hiển thị giống hoặc gần giống Hình 3 sẽ hiện ra. Mã XForm của nút Refresh chứa một trigger, kích hoạt cơ chế gửi đơn. Cài đặt này, về chức năng giống hệt một thành tố submit thông thường, thể hiện một biểu mẫu có thể có và sử dụng thành tố gửi đơn có hay không có một thành tố submit.
##### Hình 3. Lập ngân sách sau khi refresh
![ Lập ngân sách sau khi refresh](fig03.jpg)
Sự khác nhau nhỏ giữa cài đặt submit và trigger nằm ở chỗ Firefox đạt các thành tố submit trên một dòng mới trừ khi được chỉ dẫn, còn đặt các thành tố trigger trên cùng dòng. Ví dụ 7 trình bày mã trigger.
##### Ví dụ 7. Tạo ra sự gửi đơn mà không cần thành tố submit
<xforms:trigger ref="instance('acctToolBdgtInst')/loadBudget"> <xforms:label>Refresh</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:dispatch name="xforms-submit" target="load_budget"/> </xforms:action> </xforms:trigger>
Tiếp theo bạn sẽ thấy bạn có thể sử dụng các thành tố action và dispatch trong XForm như thế nào.
### Sử dụng action và dispatch trong XForms
Biểu
mẫu ngân sách có thể thực thi tốt với một thành tố XForm submit, nhưng
sử dụng trigger đem đến một lựa chọn thú vị. Thành tố action trong
XForms thực hiện các thành tố chứa bên trong nó liên tiếp. Sử dụng cơ
cấu này, một nút bấm duy nhất có thể chi phối nhiều cơ chế gửi đơn hay
thực hiện nhiều thao tác. Thành tố dispatch phục vụ như một người điều
khiển một sự kiện. Bằng cách sử dụng dispatch, một biểu mẫu XForm có
thể thực hiện gần như mọi hành động. Trường hợp này, thể hiện trong
[Ví dụ 7](#listing7), đã sử dụng sự kiện
xforms-submit, khi được chỉ đến đích
load_budget khiến cho phương thức gửi đơn của
load_budget thực thi. Thành tố gửi đơn
load_budget được thể hiện trong
[Ví dụ
6](#list6).
Tiếp đến, bạn sẽ quan sát một số dữ liệu cá thể XML cho biểu mẫu ngân sách.
### Cấu trúc dữ liệu XML của biểu mẫu ngân sách
Tới đây, giới thiệu cấu trúc giữ liệu cho các gian hàng là cần thiết. Ví dụ này sử dụng một cấu trúc dữ liệu phả hệ của các gian hàng trong XML. Ví dụ 8 trình bày một ví dụ ngắn gọn cách thức XML được cấu trúc. Cấu trúc phả hệ này cho phép quá trình tính toán thích hợp với từng gian hàng và gian hàng con của nó. Những cài đặt thay thế đặt tất cả các nút XML cùng một cấp nhưng bổ xung các nút thông tin để tạo khái niệm của phả hệ. Quá trình tính toán trở nên phức tạp tới mức bất khả thi đối với phương pháp đó.
##### Ví dụ 8. Phả hệ XML department
<?xml version="1.0" encoding="UTF-8"?> <budgetForm xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <departments> <maxid/> <hidden>0</hidden> <department id="9"> <name>United Cabinetry And Millwork</name> <department id="3"> <name>Boxgoods</name> <department id="4"> <name>Blanket Chests</name>
Phương
pháp phả hệ có một số sự khó khăn đáng quan tâm. Sự khó khăn chính đến
từ điều có thể làm gần như xong. Đoạn mã thể hiện trong
[Ví dụ 10](#list10) tạo ra hiển thị trong [Hình 3](#fig03). Ví dụ 9 trình bày một phiên bản lặp lại đơn giản hơn
nhiều, phiên bản mà cuối cùng không làm việc được bởi vì các thành tố
lặp lại coi nodelist như một cấu trúc thẳng, song song mà có thể được
chọn với một chỉ số nguyên cho các thao tác như là chèn (insert). Mã
nguồn Ví dụ 9 sử dụng biểu thức XPath
// để
tìm kiếm theo phả hệ tất cả các nút dưới các gian hàng tên là
department và sử dụng chúng như tập nodeset. Cuối cùng,
[Ví dụ 10](#list10) cung cấp một mô hình làm việc nơi mà
mỗi tập nút lặp lại sử dụng tất cả các nút gian hàng tại một cấp duy
nhất mà không sử dụng nút nào bên dưới. Phương pháp này cho phép quá
trình chèn một nút mới vào cây
department.
##### Ví dụ 9. Hiển thị phả hệ có chiều sâu động department
<xforms:repeat id="budgetRpt" nodeset="instance('departmentsInst')/departments//department" incremental="true">
### Các thành tố lặp lại lồng nhau
Ví dụ 10 thể hiện cách thức sử dụng một cáu trúc lặp lại lồng nhau trong XForms như thế nào. Ví dụ này sử dụng một bộ lồng nhau 3 cấp. Mỗi lần lặp có nhiều thành tố XForms khác và chứa một thuộc tính ID. Thuộc tính ID cung cấp truy cập tới chỉ số của cấu trúc lặp cụ thể. Lặp của XForms chạy rất giống các điều khiển biểu mẫu (form) dựa trên tương tác người dùng trực tiếp hơn khác. Một hành vi quan trọng để hiểu về lặp là dòng cuối cùng người dùng nhấn lên được lưu nhớ lại cho lặp đó và có thể lấy được bằng một hàm. Sau đó chỉ số này có thể được sử dụng để trình bày chức năng chèn (insert).
##### Ví dụ 10. Hiển thị department có chiều sâu mã cố định
<xforms:repeat id="budgetRpt" nodeset="instance('departmentsInst')/departments/department" incremental="true">

  > 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 <xforms:repeat id="budgetRpt2" nodeset="department" incremental="true">

  —> 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 <xforms:repeat id="budgetRpt3" nodeset="department" incremental="true">

  ——> 	  <xforms:textarea ref="name"/> 	  <xforms:textarea ref="planExp"/> <xforms:output ref="planExpDisplay"/> 	  <xforms:textarea ref="planPro"/> <xforms:output ref="planProDisplay"/> 	  <xforms:output ref="curExp"/> 	  <xforms:output ref="curPro"/>

 </xforms:repeat> </xforms:repeat> </xforms:repeat>
Một
tính năng quan trọng nữa của cấu trúc lặp là sự tái định nghĩa của ngữ
cảnh hiện tại cho các truy vấn XPath. Cấu trúc lặp kép (two-repeat)
thứ 2 sử dụng tập nút department. Mặc dù chúng ám chỉ cùng một văn
bản, nhưng mỗi cái chọn một tập các nút khác nhau. Lý do cho điều này
là sự tái định nghĩa tăng dần của ngữ cảnh vị trí hiện tại. Bởi vì các
biểu thức XPath không chứa lời gọi tới
instance() hoặc một tiếp đầu tố
/ hay một vài thành phần bổ nghĩa khác, chúng được tham
chiếu tới ngữ cảnh hiện tại, chính là một trong các nút được chọn bởi
biểu thức XPath trong thuộc tính nodeset của thành tố
repeat.
### Điều khiển biểu mẫu Textarea
Một điều khiển hiển thị biểu mẫu
mới của XForms được thể hiện trong
[Ví dụ 10](#list10).
Điểu khiển textarea cho phép người sử dụng nhập nhiều dòng dữ liệu.
Nhấn **Enter** trong một điều khiển biểu mẫu textarea nhảy tới dòng
văn bản tiếp theo chứ không phải để phát sinh một hành động. Trong
trường hợp này, thành tố input có vẻ là giải pháp thích hợp hơn. Tuy
nhiên, như Hình 4 trình bày, kết quả của việc thay thế các thành tố
textarea với các thành tố input cho một hình ảnh không đẹp lắm. Chú ý
rằng sự gióng hàng của tên các gian hàng trở nên xiên lệch và các con
số gióng sang trái trong input và gióng phải nếu là các giá trị.
##### Hình 4. Sử dụng input thay thế cho textarea
![ Sử dụng input thay thế cho textarea](fig04.jpg)
Cũng phải nhớ rằng textarea được điểu khiển bằng cách sử dụng CSS sau, như đã được thể hiện trong Ví dụ 11.
##### Ví dụ 11. Điều khiển diện mạo của các hộp nhập dữ liệu textarea
 <xforms:model id="acctToolBillModel" > ...
Đoạn
CSS trên làm cho các hộp textarea gióng thẳng nhau gọn gàng, như bạn
đã thấy trong
[Hình 3](#fig03).
Tiếp theo, bạn sẽ thấy cách thức để chèn thêm các thành tố department mới.
### Chèn thêm các gian hàng mới
Hàm chèn (insert) trên biểu mẫu ngân sách thực thi như được thể thiện trong Hình 5. Thành tố chèn (insert) thực hiện thao tác tạo một nút dữ liệu trong cấu trúc dữ liệu XML. XForms tái xử lý cấu trúc dữ liệu và cập nhật nội dung hiển thị để phản ánh nút dữ liệu mới. Thành tố chèn (insert) đòi hỏi hai nút, một nodeset, và một chỉ số để chèn thành tố mới. Sự cảnh báo của chèn (insert) đến từ thực thế rằng nút mới mà chèn (insert) tạo ra được tạo bởi nhân bản nút cuối cùng trong tập nút. Hai khó khăn tiềm tàng nảy sinh từ cách thức xử lý này. Khó khăn đầu tiên đến từ dữ liệu có thể đã hoặc chưa nằm trong nút được nhân bản. Trong trường hợp ngân sách, một gian hàng cấp thứ hai có thể có hoặc không một gian hàng cấp thứ ba dưới nó.
##### Hình 5. Chèn một gian hàng
![ Chèn một gian hàng](fig05.jpg)
Khó khăn thứ hai hiện ra như là một kết quả của vấn đề đầu tiên. Nếu không có nút nào để bắt đầu, không có gì có thể được tạo ra bởi vì không có gì để nhân bản. Những các xử lý này tạo ra một vài thử thách đáng quan tâm trong phát triển ứng dụng XForms với XForms 1.0, nhưng trong trường hợp này nếu người dùng muốn một gian hàng cấp ba, câu trả lời là phải chèn một gian hàng cấp 2 khác, mà sẽ có một gian cấp 3 gắn vào nó miễn phí, đáng khen cho một nút bù nhìn được sử dụng cho mục đích đặc biệt. Mã chèn (insert) cấp thứ ba được trình bày trong Ví dụ 12.
##### Ví dụ 12. Third-level chèn (insert)
<xforms:trigger ref="instance('acctToolBdgtInst')/newDept3rd"> <xforms:label>Add New 3rd Level Department</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:insert nodeset="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department" at="index('budgetRpt3')" position="after"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department[index ('budgetRpt')] /department[index('budgetRpt2')]/ department[index('budgetRpt3')+1]/@id" value="instance('departmentsInst')//departments/maxid"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/name" value="'Enter new department name'"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/planPro" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/planExp" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/ordersTotal" value="0"/> <xforms:setvalue ref="instance('departmentsInst')/departments/department [index('budgetRpt')]/department[index('budgetRpt2')]/department[index ('budgetRpt3')+1]/expensesTotal" value="0"/> </xforms:action> </xforms:trigger>
### Các bộ lọc XPath, chỉ số lặp, và đặt-giá-trị (setvalue)
[Ví dụ 12](#listing12) chứa rất nhiều mã; dù sao, sự kiểm
tra kĩ hơn cho thấy rằng phần lớn mã thực hiện các chứ năng giống hệt
nhau, để lại hai điều cần bàn là chèn (insert) và nhiều thuộc tính
setvalue. Thành tố chèn (insert) thực hiện như đoạn trước đã đề cập
đến; nó sao chép một nút và đặt bản sao mới vào cấu trúc dữ liệu. Chèn
(insert) cần một nodeset, và một vị trí hay chỉ số. Biểu thức nodeset,
một biểu thức XPath, chiếm hầu hết kí tự trắng trong [Ví dụ 12](#listing12), trông như một con yêu quái. Tuy
nhiên, biểu thức chỉ đơn thuần phục vụ để đánh chỉ số xuống tới nút
cấp ba sử dụng chỉ số từ các thành tố repeat đã được bàn trước đó. Một
nút nên được tạo có toán tử
[] trong một
biểu thức XPath không thực hiện điều mà một toán tử
[] điển hình của hầu hết ngôn ngữ làm. Trong
XPath, toán tử
[] phục vụ như một bộ lọc.
Trong trường hợp này, một số đơn được đặt vào bộ lọc để chọn chỉ số
đó; dù sao, rất nhiều thứ có thể được đặt vào bộ lọc.
Các dòng setvalue phục vụ để khởi tạo dữ liệu. Như đã đề cập ở trước, vì dữ liệu là một bản sao, nó có thể có những phần thông tin mà hoặc là không được áp dụng, hay thậm chí có thể gây rắc rối. Ở đây, một trong các khó khăn là duy trì các ID duy nhất của gian hàng. Điều đó được giải quyết bằng cách sử dụng giá trị maxId trong nút cao nhất của các gian hàng. Nó lần lượt được gắn với một hàm XPath để trở thành maxId (cộng thêm một) trong toàn bộ tập nút.
Tiếp đó, bạn sẽ cài đặt mã để bỏ đi các nút cấp 2 đã tồn tại.
### Bỏ đi các nút
Ví dụ 13 thể hiện đoạn mã cho các nút bấm bỏ nút đi. Đơn giản hơn rất nhiều so với tính năng chèn (insert), bỏ nút sử dụng chỉ số lặp. Thành tố delete xoá cấu trúc dữ liệu XML được chỉ ra và, do đó, dữ liệu được hiển thị liên kết với thành tố đó sẽ bị xoá bỏ.
##### Ví dụ 13. Bỏ đi các nút cấp 2
<xforms:trigger ref="instance ('acctToolBdgtInst')/remove"> <xforms:label>Remove 2nd Level Department</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:delete nodeset="instance ('departmentsInst')/departments/department[index ('budgetRpt')]/department" at="index('budgetRpt2')"/> </xforms:action> </xforms:trigger>
### Ẩn và hiện các nút
Biểu mẫu ngân sách sử dụng thuộc tính thích hợp để ẩn và hiện các gian hàng. Tính năng này hoạt động không được tốt trong trường hợp này bởi vì phần thụt lề thể hiện cấp của gian hàng. Một thành tố setvalue thực hiện chức năng này rất giống hàm khởi tạo trong một thủ tục chèn (insert). Bởi vì thuộc tính thích hợp đã được gắn với tất cả các nút hiển thị, ẩn các nút đi trở thành vấn đề thiết đặt các nút ẩn thành giá trị 1 và ngược lại đối với các nút hiện, như được thể hiện trong Ví dụ 14.
##### Ví dụ 14. Ẩn và hiện các nút
<xforms:trigger ref="instance('acctToolBdgtInst')/show2nd"> <xforms:label>Show 2nd and 3rd Level Children</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="instance ('departmentsInst')//departments/department[index ('budgetRpt')]/hidden" value="0"/> </xforms:action> </xforms:trigger> 	  <xforms:trigger ref="instance ('acctToolBdgtInst')/hide2nd"> <xforms:label>Hide 2nd and 3rd Level Children</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="instance ('departmentsInst')//departments/department[index ('budgetRpt')]/hidden" value="1"/> </xforms:action> </xforms:trigger>
Tiếp theo, bạn sẽ thấy cách thức để tạo một số kỹ thuật với các nút lá gian hàng như thế nào.
### Bằng cách nào các gian hàng với các ngân sách gian hàng con là chỉ chứa thuộc tính đọc (read-only)
Với mục đích lập ngân sách, ngân sách của gian hàng được xác định bởi tổng của các ngân sách của các gian hàng dưới nó. Manh mối trực quan dẫn tới bản chất read-only của gian hàng cha là số liệu không thể thay đổi được. Mỗi một giá trị, lợi nhuận, phí tổn của ngân sách, có hai điều khiển biểu mẫu (form). Bằng cách kích hoạt (enable) điểu khiển biểu mẫu textarea, giá trị trở thành read-write và manh mối trực quan là gian hàng là một nút lá được tạo. Ngược lại, kích hoạt (enable) điểu khiển biểu mẫu đầu ra tạo một hiển thị read-only, chỉ ra rằng gian hàng có các gian hàng con. Quá trình chuyển đổi giữa read-only và read-write và hành vi tính toán số liệu xảy ra như một kết quả của sự gắn kết tới dữ liệu thích hợp và tính toán. Ví dụ 15 thể hiện đoạn mã cho sự gắn kết.
##### Ví dụ 15. Các phép tính và sự tương thích
<xforms:bind nodeset="instance ('departmentsInst')//department/planPro" relevant="../department/@id=false()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planExp" relevant="../department/@id=false()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/leafPlanExp" relevant="../department/@id=false()" calculate="../planExp"/> <xforms:bind nodeset="instance ('departmentsInst')//department/leafPlanPro" relevant="../department/@id=false()" calculate="../planPro"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planProDisplay" calculate="sum(..//leafPlanPro)" relevant="../department/@id=true()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/planExpDisplay" calculate="sum(..//leafPlanExp)" relevant="../department/@id=true()"/> <xforms:bind nodeset="instance ('departmentsInst')//department/curPro" calculate="round(sum(..//ordersTotal))"/> <xforms:bind nodeset="instance ('departmentsInst')//department/curExp" calculate="round(sum(..//expensesTotal))"/> <xforms:bind nodeset="instance ('departmentsInst')//departments/maxid" calculate="max(//department/@id)+1"/>
Biểu
thức XPath tất cả đều sử dụng toán tử
// để
chọn tất cả các nút department. Các nút sau đó tiếp tục được khử tham
chiếu cho đến khi tất cả các trường của planPro trong tất cả các nút
department đều có kết nối thích hợp đặt cho chúng. Nhắc lại từ
[bài viết trước](http://www.ibm.com/developerworks/vn/edu/x-xformsaccttool2/) là kí tự
@ chỉ ra
một thuộc tính. ID là một thuộc tính, và do đó, được tham chiếu với kí
tự
@ trong biểu thức XPath. Sự so sánh là
cho
true() hay
false(). Hai hàm XPath đặc biệt đó định các giá trị logic
(Boolean) đúng và sai. Được sử dụng theo cách được trình bày trong
[Ví dụ 15](#listing15), sự so sánh trả về true nếu nút
được tham chiếu tồn tại. Cũng phải chú ý ứng dụng của các hàm làm tròn
(round) và tính tổng (sum) của XPath. Cũng cần xem hàm lấy giá trị lớn
nhất (max) trong áp dụng bên trên khi thành tố //departments/maxid
được đặt. Thành tố maxid được sử dụng để đặt ID cho các hàng mới được
thêm vào, đảm bảo các ID riêng biệt với nhau.
Tiếp theo bạn sẽ tìm hiểu một chút về cách thức để sinh dữ liệu cá thể cho biểu mẫu sử dụng DOM của PHP.
### Đề cập ngắn gọn về sinh dữ liệu biểu mẫu ngân sách sử dụng PHP
Vì XForms đòi hỏi toàn bộ cấu trúc cơ bản của dữ liệu XML, cấu trúc dữ liệu phải được tạo từ đầu bởi kịch bản PHP. Kịch bản PHP cố gắng thực hiện với ít hàm nhất có thể; dù sao, dữ liệu này cũng đòi hỏi một cấu trúc phả hệ từ một bảng cơ sở dữ liệu SQL, lại là một cấu trúc thẳng. Kịch bản PHP get_budget thực hiện một chức năng đơn: nó thu thập tất cả các gian hàng từ bảng department trong cơ sở dữ liệu SQL, và xây dựng lại phả hệ dựa trên ID của mỗi nút và ID được lưu trữ của nút cha. Giá trị 0 được cho là nút gốc.
Các truy vấn SQL cho nhiệm vụ này không đáng để quan tâm nhiều. Cơ sở dữ liệu SQL là cần thiết để sử dụng PHP, như đã thể hiện trong Ví dụ 16. Giải thuật được sử dụng là tìm kiếm theo chiều sâu (depth-first traversal), một nút được rút ra khỏi một hàng đợi (queue) và được tham chiếu như một nút cha trong mỗi vòng lặp. ID của nút đó sẽ được truy vấn như một nút cha, trả về tất cả các nút con của gian hàng đó.
##### Ví dụ 16. Truy vấn SQL cho gian hàng
$query = sprintf('SELECT * FROM `departments` WHERE Parent=%s AND NOT(department_id=%s);',$parentId, $parentId); $queryData = mysql_query($query, $sqldb); if (!$queryData) die ('Could not execute acct db query: '.$query.' because: ' . mysql_error()); while ($row = mysql_fetch_assoc($queryData)) {
Tài liệu XML khởi tạo một chuỗi tĩnh (static string), như đã thể hiện trong Ví dụ 17. Sử dụng nó như một cơ sở, các nút mới sẽ được tạo ra và thêm vào lặp lại, tiến dần xuống dưới cây theo phương pháp tìm kiếm sâu. Quá trình thêm các nút mới và sử dụng cấu trúc danh sách liên kết của DomNodes trong PHP được thể hiện trong Ví dụ 17.
##### Ví dụ 17. Xây dựng cây XML DOMNode và khởi tạo DomDocument
$doc = new DomDocument('1.0'); $doc->loadXml('<?xml version="1.0" encoding="UTF-8"?> <budgetForm xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <departments> <maxid/> <hidden>0</hidden> </departments> </budgetForm>'); ... do { ... if($curParent->previousSibling && $curParent- >previousSibling->nodeName == 'department') $curParent = $curParent->previousSibling; else $curParent = $curParent->childNodes->item($curParent- >childNodes->length-1); $parentId = $curParent->getAttribute('id'); } while ($parentId);
Chú ý cẩn thận khi xử lý các nút để không thực sự coi danh sách nút là một hàng đợi mà sử dụng hàm remove, bởi vì nút thực sự sẽ mất đi và XML thì không chứa bất cứ nút nào dưới kết quả cuối cùng.
Đó là vỏ
bọc cho biểu mẫu ngân sách! Chú ý rằng không phải tất cả mọi thứ trong
đó đều được bao quát, nhưng bạn có thể xem mã đầy đủ cho biểu mẫu
(form), bao gồm dữ hỗ trợ PHP và SQL khởi tạo cho cơ sở dữ liệu của
bạn, trong phần
[tải về](#download) đã được cung
cấp.
## Biểu mẫu thanh toán (Billing)
Biểu mẫu thanh toán sử dụng nhiều khái niệm tương tự như biểu mẫu ngân sách với một vài bổ xung mới. Biểu mẫu XForms thanh toán giới thiệu thủ tục để mở một cửa sổ mới hiển thị thông tin thích hợp để in một hoá đơn. Phần này cài đặt biểu mẫu này, trạng thái ban đầu được thể hiện trong Hình 6.
##### Hình 6. Trạng thái ban đầu của biểu mẫu thanh toán
![ Chèn một gian hàng](fig06.jpg)
### Hiển thị bảng
Mặc dù bảng HTML không hỗ trợ XForms và Firefox chưa
cài đặt thuộc tính repeat của XForms, vẫn có thể lặp lại toàn bộ cấu
trúc bảng. Biểu mẫu XForms thanh toán sử dụng cơ cấu đó để hiển thị dữ
liệu thanh toán. Hiển thị có được từ cấu trúc lặp đơn cấp như được thể
hiện trong
[Ví dụ 18](#list18). Hình 7 thể hiện biểu mẫu
sau khi nhấn nút **Refresh/Load Accounts**.
##### Hình 7. Biểu mẫu thanh toán đã được làm mới
![ Biểu mẫu thanh toán đã được làm mới](fig07.jpg)
##### Ví dụ 18. Các điều khiển XForms trực quan cho biểu mẫu thanh toán
<xforms:repeat id="acctRpt" nodeset="instance ('accts')//account">

  <xforms:output ref="acctId"/> 	  <xforms:output ref="creationDate"/> 	  <xforms:output ref="totalDue"/> 	  <xforms:output ref="accountState"/> 	  <xforms:trigger style="display: inline" ref="submitCollection"> <xforms:label>COLLECT!</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeDelURI" value="concat('doBillingAction.php? action=delinquent&acct=',../../acctId,'&amount=',../../payment Amt,'&bal=',../../totalDue)"/> <xforms:load ref="@makeDelURI" show="new"/> </xforms:action> </xforms:trigger> </xforms:trigger> <xforms:trigger ref="submitCredit"> <xforms:label>Issue Credit</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeCreURI" value="concat('doBillingAction.php? action=credit&acct=',../../acctId,'&amount=',../../totalDue)"/> <xforms:load ref="@makeCreURI" show="new"/> </xforms:action> </xforms:trigger> 	  <xforms:textarea ref="paymentAmt"/> 	  <xforms:trigger ref="pay"> <xforms:label>Record</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeRctURI" value="concat ('doBillingAction.php? action=makepayment&acct=',../../acctId,'&amount=',../../paymen tAmt,'&bal=', ../../totalDue - ../../paymentAmt)"/> <xforms:insert nodeset="../payment" at="count (../payment)" position="after"/> <xforms:setvalue ref="../payment[count (../payment)]/paymentDate" value="substring(now(),1,10)"/> <xforms:setvalue ref="../payment[count (../payment)]/amount" value="../../paymentAmt"/> <xforms:setvalue ref="../payment[count (../payment)]/acctId" value="../../acctId"/> <xforms:load ref="@makeRctURI" show="new"/> <xforms:setvalue ref="../paymentAmt" value="0"/> </xforms:action> </xforms:trigger> 	  <xforms:trigger ref="bill"> <xforms:label>Bill</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:setvalue ref="@makeBilURI" value="concat('doBillingAction.php? action=createbill&acct=',../../acctId,'&amount=',../../payment Amt,'&bal=',../../totalDue)"/> <xforms:load ref="@makeBilURI" show="new"/> </xforms:action> </xforms:trigger>

 </xforms:repeat> <xforms:bind nodeset="instance('accts')//bill" relevant="../accountState != 'Paid' and ../accountState != 'Current' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//pay" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//paymentAmt" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//submitCollection" relevant="../accountState = 'Delinquent'"/> <xforms:bind nodeset="instance('accts')//submitCredit" relevant="../accountState = 'Credit'"/> <xforms:bind nodeset="instance('accts')//accountState" calculate=" if(number(../totalDue)>0, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 30, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 90, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date (../creationDate), days-from-date (../lastPaymentDate)) > 180, 'Delinquent', 'Pastdue'), 'Due'), 'Current'), if(number(../totalDue) = 0,'Paid','Credit'))"/>
Tiếp theo bạn sẽ tìm hiểu về lưu trữ số tiền thanh toán cho các tài khoản.
### Lưu trữ số tiền thanh toán
Quá trình lưu trữ đỏi hỏi một giấy biên lai và chỗ chứa dữ liệu. Công cụ thanh toán giải quyết tình huống này bằng cách mở một cửa sổ mới nơi dữ liệu yêu cầu hiển thị trong một định dạng thích hợp cho in ấn và gửi thư. Cũng với sự thuận tiện như vậy, khách hàng có thể nhận được e-mail hoặc bất cứ một trong số các tiến trình thủ tục nào đó. Các nút bấm Record, Bill, và Collections thực thi tương tự bằng cách định dạng bằng tay một hoạt động gửi đơn GET và sử dụng kết quả đó như một đối số cho load với thuộc tính xuất hiện đầu tiên trong loạt bài viết tại thời điểm này. Thuộc tính show=new chỉ cho trình duyệt tạo một cấu trúc thể hiện mới. Hình 8 cho thấy kể quả khi kích hoạt nút bấm COLLECT!.
##### Hình 8. Hiển thị thu tiền
![ Hiển thị thu tiền](fig08.jpg)
Hình 9 cho thấy kết quả khi kích hoạt nút bấm
**Record**.
##### Hình 9. Hiển thị biên lai
![ Hiển thị biên lai](fig09.jpg)
Kích hoạt nút bấm Bill cho kết quả thể hiện trong Hình 10.
##### Hình 10. Hiển thị hoá đơn
![ Hiển thị hoá đơn](fig10.jpg)
Chọn nút bấm
**Issue Credit** cho kết quả thể hiện trong Hình
11.
##### Hình 11. Hiển thị tín dụng
![ Hiển thị tín dụng](fig11.jpg)
Tiếp đó, bạn sẽ thấy cách thức để đặt rất nhiều trạng thái khác nhau của một tài khoản dựa trên ngày tháng của lần trả tiền cuối cùng.
### Tính toán các trạng thái có thể cho mỗi tài khoản
Ba trạng thái khác
nhau xuất hiện trong
[Hình 7](#fig7). Mỗi trạng thái tạo ra
các điều kiện khác nhau cho hiển thị. Các tài khoản có quyết toán lớn
hơn không và chưa trả tiền quá 180 ngày có hiển thị nút bấm COLLECT!,
trong khi các tài khoản có quyết toán nhỏ hơn hoặc bằng 0 không có nút
bấm nào cả, tuy vậy một quyết toán âm cuối cũng sẽ cần một nút Credit.
Ví dụ 19 chứa các khai báo xác đáng và các khai báo tính toán tạo ra
hiệu ứng
này.
##### Ví dụ 19. Tính toán trạng thái tài khoản
<xforms:bind nodeset="instance('accts')//bill" relevant="../accountState != 'Paid' and ../accountState != 'Current' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//pay" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//paymentAmt" relevant="../accountState != 'Paid' and ../accountState != 'Credit'"/> <xforms:bind nodeset="instance('accts')//submitCollection" relevant="../accountState = 'Delinquent'"/> <xforms:bind nodeset="instance('accts')//submitCredit" relevant="../accountState = 'Credit'"/> <xforms:bind nodeset="instance('accts')//accountState" calculate=" if(number(../totalDue)>0, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate)) > 30, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate)) > 90, if(days-from-date(now()) - if(../maxYearPaid='NaN', days-from-date(../creationDate), days-from-date(../lastPaymentDate))>180, 'Delinquent', 'Pastdue'), 'Due'), 'Current'), if(number(../totalDue) = 0,'Paid','Credit'))"/>
Một
hàm XPath mới xuất hiện trong đoạn mã này, hàm
days-from-date, biến đổi giá trị ngày trở thành một giá
trị nguyên tính từ đầu kỷ nguyên. Hàm đó cho phép các tính toán như
thế này xảy ra. Như
[Ví dụ 19](#listing19) thể hiện, sự gia
tăng xuất phát từ một tài khoản Paid tới một tài khoản Delinquent dựa
trên một quyết toán dương và vượt qua 30, 90, rồi 180 ngày, và nếu
không tồn tại lần nộp tiền nào (nghĩa là không tồn tại ngày nộp tiền
nào), thì ngày tạo được sử dụng để so sánh. Một tính năng đáng quan
tâm của [Ví dụ 19](#listing19) là toán tử *và (and)*.
Nút bấm Bill áp dụng cho các tài khoản đến hoặc quá hạn trả. Bằng các
thực hiện hai phép so sánh logic, sự ảnh hưởng đó đã đạt được. Toán tử
logic *và (and)* là nguyên văn từ *and*, không phải kí hiệu
& hay && như rất nhiều lập trình viên đã quen
thuộc.
### Các con số được xử lý như thế nào
Một cách âm thầm, XForms thực hiện
một lượng lớn xử lý số học. Cấu trúc dữ liệu cơ bản bao gồm có một nút
tài khoản với một tập các nút có tên
*order* và một tập các nút
có tên *payment*. Bằng cách tính tổng/số lượng đơn đặt hàng trong
tập nút, tổng lượng tiền khác hàng đã đồng ý trả cho hãng đã sẵn dùng.
Đầu tiên, dù thế nào, cơ cấu XForm cũng phải tính số lượng của mỗi đơn
đặt hàng. Tổng của mỗi đơn hàng được tính toán bởi phương trình trong
Ví dụ
20.
##### Ví dụ 20. Số lượng đơn hàng và tổng giá tiền
<xforms:bind nodeset="instance('accts')//order/amount" calculate="../quantity * ../unitPrice * (1-../discount)"/> <xforms:bind nodeset="instance('accts')//totalDue" calculate="sum(..//order/amount) - sum(..//payment/amount)"/>
[Ví dụ 20](#listing20) giải thích một khả năng nội tại của
bộ xử lý XForms đã cung cấp một số sự trợ giúp cho lập trình viên.
Trình duyệt xử lý mã XForms giải quyết sự phụ thuộc trong các trật tự
thích hợp. Trong trường hợp này, đơn hàng/số lượng các nút cần thiết
để được giải quyết trước nút totalDue. Thuộc tính relevant trong [Ví dụ 19](#listing19) giải thích một hành vi tương tự với
sự phụ thuộc vào relevant khi tính toán trạng thái các tài
khoản.
Phép tính trạng thái tài khoản đòi hỏi ngày tháng. Một
vài lựa chọn để cung cấp thông tin tồn tại đó. Một lựa chọn là sử dụng
PHP để trích ngày đòi hỏi, và một lựa chọn khác là cho dữ liệu được
sắp xếp. XForms 1.0, đáng tiếc, không cung cấp hàm tính giá trị nhỏ
nhất
min có thể giải quyết ngày tháng chính
xác. Đoạn mã trong Ví dụ 21, dù sao, giải thích một cách tiếp cận mạnh
hơn để tìm ra ngày nhỏ nhất trong danh sách. Tiến trình bao gồm cả cắt
mỗi trường ngày tháng ra thành từng phần cấu tạo cho phép so sánh rồi
ráp kết quả lại trở thành một ngày
tháng.
##### Ví dụ 21. Tìm ngày đặt hàng (ngày tạo) nhỏ nhất và ngày trả (ngày trả cuối) lớn nhất
<xforms:bind nodeset="instance('accts')//order/yearCreate" calculate="substring(../orderDate, 1, 4)"/> <xforms:bind nodeset="instance('accts')//minYearCreate" calculate="min(..//yearCreate)"/> <xforms:bind nodeset="instance('accts')//order/monthCreate" calculate="if(../yearCreate = ../../minYearCreate, number(substring(../orderDate, 6, 2)), 13)"/> <xforms:bind nodeset="instance('accts')//minMonthCreate" calculate="min(..//order/monthCreate)"/> <xforms:bind nodeset="instance('accts')//order/dayCreate" calculate="if(../monthCreate = ../../minMonthCreate, number(substring(../orderDate, 9, 2)), 32)"/> <xforms:bind nodeset="instance('accts')//minDayCreate" calculate="min(..//order/dayCreate)"/> <xforms:bind nodeset="instance('accts')//creationDate" calculate="concat(../minYearCreate, '-', if(../minMonthCreate < 10, concat('0',../minMonthCreate), ../minMonthCreate), '-', if(../minDayCreate < 10, concat('0',../minDayCreate), ../minDayCreate))"/> <xforms:bind nodeset="instance('accts')//payment/yearPaid" calculate="substring(../paymentDate, 1, 4)"/> <xforms:bind nodeset="instance('accts')//maxYearPaid" calculate="max(..//yearPaid)"/> <xforms:bind nodeset="instance('accts')//payment/monthPaid" calculate="if(../yearPaid = ../../maxYearPaid, number(substring(../paymentDate, 6, 2)), 0)"/> <xforms:bind nodeset="instance('accts')//maxMonthPaid" calculate="max(..//payment/monthPaid)"/> <xforms:bind nodeset="instance('accts')//payment/dayPaid" calculate="if(../monthPaid = ../../maxMonthPaid, number(substring(../paymentDate, 9, 2)), 0)"/> <xforms:bind nodeset="instance('accts')//maxDayPaid" calculate="max(..//payment/dayPaid)"/> <xforms:bind nodeset="instance('accts')//lastPaymentDate" calculate="concat(../maxYearPaid, '-', if(../maxMonthPaid < 10, concat('0',../maxMonthPaid), ../maxMonthPaid), '-', if(../maxDayPaid < 10, concat('0',../maxDayPaid), ../maxDayPaid))"/>
Tiếp đó, bạn sẽ thu được một vài quan điểm về cách thức cải thiện thời gian tải XForm của bạn cho một lượng lớn dữ liệu cá thể.
### Cập nhập số liệu mà không phải chờ
Một sự cải thiện rõ ràng cho biểu mẫu XForms thanh
toán hiện tại là sự bổ sung của giới hạn số lượng các tài khoản được
hiển thị một lúc, do đó trình duyệt không phải duy trì cấu trúc dữ
liệu của toàn bộ cơ sở dữ liệu. Cho toàn bộ cơ sở dữ liệu trong cấu
trúc dữ liệu tập trung vào một việc quan trọng, dẫu vậy. Cần một lượng
đáng kể thời gian để truy vấn, xây dựng và tải cấu trúc dữ liệu và quá
trình đó rất quý giá đối với sự kiên nhẫn của người dùng. Biểu mẫu này
cài đặt một phím tắt để tăng khả năng nhận điều khiển của biểu mẫu
(form). Hành động lưu trữ chứa một khối chèn (insert) giống như phần
chèn (insert) đã miêu tả trong biểu mẫu ngân sách. Đoạn mã được nói
đến xuất hiện trong
[Ví dụ 18](#list18).
Đoạn mã chèn
(insert) tạo một nút payment mới và lưu dữ liệu thích hợp vào nút đó.
Thay đổi cấu trúc dữ liệu nội tại không thay đổi cơ sở dữ liệu; dù
sao, kịch bản PHP sinh ra biên lại có thể dễ dàng truy cập cơ sở dữ
liệu đưa ra một đáp trả nhanh hơn rất nhiều so với gửi một kho chứa
toàn bộ tập nút của tài khoản, hay thậm chí chỉ một nút đơn lẻ, có thể
đòi hỏi tải lại toàn bộ cấu trúc dữ liệu. Do tính toán các phương
trình trong
[Ví dụ 20](#listing20), quyết toán cho tài
khoản đó ngay lập tức phản ánh thông tin mới.
Bạn sắp hoàn thành rồi! Trong phần cuối cùng của đoạn này bạn sẽ học cách PHP trợ giúp biểu mẫu thanh toán
### PHP làm được gì cho biểu mẫu XForms thanh toán
PHP phục vụ như một giao diện tới cơ sở dữ liệu SQL trong suốt loạt bài viết này với hấu hết công việc được thực hiện bởi bộ xử lý XForms. Một giới hạn của XForms, dù thế nào, là sự đòi hỏi một nút phải tồn tại. XForms không thể dễ dàng tạo một nút mới và nó đòi hỏi một khuôn mẫu khi một nút mới được tạo. Hầu hết dữ liệu sau XForm thanh toán là dữ liệu đã được tính toán và lưu trữ dữ liệu đã tính toán ngốn không gian đĩa quý giá. PHP tạo một tập nút tài khoản và lồng đơn đặt hàng với các nút payment bên dưới nó, bổ sung thêm các nút vào các nút đơn hàng để tổng hợp và đồng thời cũng vào tài khoản để tính toán. Đoạn mã để thực hiện chức năng này rất giống với đoạn mã đã thể hiện để tính toán các nút ngân sách chỉ khác là cấu trúc dữ liệu kết quả có ít cấp phả hệ hơn.
Tốt lắm! Bạn đã hoàn thành bài viết này. Bây giờ hãy xem lại bài tóm tắt để tìm hiểu thêm về các vấn đề sắp tới, trong Phần 4.
## Tóm tắt
Bài viết này giới thiệu một vài khái niệm với XForms. Bài viết bao gồm mở cửa sổ trình duyệt mới và các lặp lồng nhau, đồng thời cũng giải quyết cơ cấu chèn. Biểu mẫu ngân sách giới thiệu quá trình bỏ các nút đi và các đòi hỏi nội tại của cấu trúc dữ liệu để cho phép hiển thị. Các phép tính toán chi tiết, chuỗi phụ thuộc, và nhiều hàm XPath mới xuất hiện trong cả biểu mẫu ngân sách và thanh toán.
Các phần tiếp theo của loạt bài viết này tinh chế cả cài đặt XForms khi cần thiết và các kĩ năng tham gia vào cái đặt XForms. Tiếp theo, Phần 4 cài đặt quản lý tài sản và một vài công cụ hành chính.
## Tải về
|Mô tả||Tên||Kích thước|
|Sample code for this tutorial|
## Tài nguyên
### Học tập
- Tìm hiểu những yếu tố cần thiết để tạo ra
thế hệ tiếp theo của các biểu mẫu trong bài viết sau đây:
[Căn bản XForms](http://www.ibm.com/developerworks/xml/library/x-xformsbasics/?S_TACT=105AGY75)(developerWorks, Tháng 9 năm 2006).
- Để mở rộng kiếm thức về XForms của bạn
hãy xem các loạt bài viết về XForms sau:
[Introduction to XForms, Part 1: The new Web standard for forms](http://www.ibm.com/developerworks/xml/library/x-xformsintro1/?S_TACT=105AGY75), [Introduction to XForms, Part 2: Forms, models, controls, and submission actions](http://www.ibm.com/developerworks/xml/library/x-xformsintro2/?S_TACT=105AGY75), và [Introduction to XForms, Part 3: Using actions and events](http://www.ibm.com/developerworks/xml/library/x-xformsintro3/?S_TACT=105AGY75)(developerWorks, Tháng 9 năm 2006).
- Tải về
[The PHP Manual](http://www.php.net/docs.php).
- Tìm hiểu thêm về các sự kiện gửi đơn của
XForms trong
[XForms tip: Using form submission events](http://www.ibm.com/developerworks/xml/library/x-xformstipsubmitevents/?S_TACT=105AGY75)(developerWorks, Tháng 11 năm 2006).
- Tìm hiểu cách để nhận dữ liệu XForms
trong
[Java](http://www.ibm.com/developerworks/xml/library/x-xformstipjava/?S_TACT=105AGY75)(developerWorks, Tháng 10 năm 2006), [Perl](http://www.ibm.com/developerworks/xml/library/x-xformstipperl/?S_TACT=105AGY75)(developerWorks, Tháng 10 năm 2006), và [PHP](http://www.ibm.com/developerworks/xml/library/x-xformstipphp/?S_TACT=105AGY75)(developerWorks, Tháng 10 năm 2006). [IBM XML certification](http://www-03.ibm.com/certify/certs/xmsdreltop.shtml): Tìm hiểu cách để trở thành một nhà phát triển XML và các công nghệ liên quan được chứng nhận bởi IBM. [XML technical library](http://www.ibm.com/developerworks/views/xml/library.jsp?S_TACT=105AGY75): Xem sét the developerWorks XML Zone để có rất nhiều các bài viết và lời khuyên chuyên môn, bài hướng dẫn, các chuẩn và IBM Redbooks. [developerWorks technical events and webcasts](http://www.ibm.com/developerworks/offers/techbriefings/?S_TACT=105AGY75): Theo kịp với công nghệ trong những bài này.
- Tìm hiểu tất cả về XML và thêm về XForms
trong IBM developerWorks
[XML zone](http://www.ibm.com/developerworks/xml).
### Lấy sản phẩm và công nghệ
- Tài liệu
[XForms Recommendation](http://www.w3.org/TR/xforms/)được duy trì bởi W3C.
- Tải
[MozzIE](http://sourceforge.net/projects/mozzie/), một điều khiển nguồn mở cho phép bạn kết xuất XForms trong Internet Explorer.
### Thảo luận
[developerWorks blogs](http://www.ibm.com/developerworks/blogs/): Trở thành một phần trong cộng đồng developerWorks.
## Bình luận
[Vùng dữ liệu trên developerWorks](http://www.ibm.com/developerworks/vn/views/data/libraryview.jsp)
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
[Vùng mã nguồn mở trên developerWorks](http://www.ibm.com/developerworks/vn/views/opensource/libraryview.jsp)
Xem các bài viết về HTML, CSS, JavaScript,...
[Điện toán đám mây](http://www.ibm.com/developerworks/vn/views/cloud/libraryview.jsp)
Tìm hiểu về điện toán đám mây

Content-Language: en-US


text:
Bài Hát
Ca Sỹ
Album
TRANG CHỦ
NHẠC MỚI
VIDEO CLIP
TOP 20
ALBUM MỚI
Album Ca Nhac Phim Tron Doi Ben Em 11 (Phien Ban Moi) - Ly Hai
THÀNH VIÊN
THỂ LOẠI
Nhạc Việt Nam
Nhạc Mới
Rap Việt
Việt Remix
Nhạc Hải Ngoại
Trữ Tình - Dân Ca
Nhạc Quốc Tế
Châu Á
Âu, Mỹ
DJ - Dance
NonStop
Video Clip
Clip Việt Nam
Clip Quốc Tế
Clip Tổng Hợp
Thể Loại Khác
Nhạc Phim OST
Nhạc Chế
Nhạc Game
Nhạc Playback
Nhạc Chuông
Phim Online
PT Production
Trang Chủ
>
Album Mới
Album Ca Nhạc Phim Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Album Ca Nhạc Phim Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải gồm các ca khúc:
Phần 1 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 2 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 3 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 4 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 5 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 6 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 7 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 8 Trọn Đời Bên Em 11 (Phiên Bản Mới), Phần 9 Trọn Đời Bên Em 11 (Phiên Bản Mới), Hoài Mong (Clip), Những Lời Dối Gian (Clip), Nụ Hôn Biệt Ly (Clip), Chỉ Mình Anh Nhớ Em (Clip), Quá Khứ Êm Đềm (Clip), Nỗi Đau Chạm Vào Tim (Clip),
Lượt nghe : 196849
Phần 1 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 2 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 3 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 4 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 5 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 6 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 7 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 8 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Phần 9 Trọn Đời Bên Em 11 (Phiên Bản Mới) - Lý Hải
Hoài Mong (Clip) - Lý Hải
Những Lời Dối Gian (Clip) - Lý Hải
Nụ Hôn Biệt Ly (Clip) - Lý Hải
Chỉ Mình Anh Nhớ Em (Clip) - Lý Hải
Quá Khứ Êm Đềm (Clip) - Lý Hải
Nỗi Đau Chạm Vào Tim (Clip) - Lý Hải
→
Next track
←
Previous track
Space
Play/pause
Phần 1 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 2 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 3 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 4 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 5 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 6 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 7 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 8 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Phần 9 Trọn Đời Bên Em 11 (Phiên Bản Mới)
Trình bày:
Lý Hải
Hoài Mong (Clip)
Trình bày:
Lý Hải
Những Lời Dối Gian (Clip)
Trình bày:
Lý Hải
Nụ Hôn Biệt Ly (Clip)
Trình bày:
Lý Hải
Chỉ Mình Anh Nhớ Em (Clip)
Trình bày:
Lý Hải
Quá Khứ Êm Đềm (Clip)
Trình bày:
Lý Hải
Nỗi Đau Chạm Vào Tim (Clip)
Trình bày:
Lý Hải
Liên Hệ Quảng Cáo Tại Đây
Powered by hMedia 4.0 . Author by La Marguerites
Ca sĩ muốn liên hệ với NhacPro vui lòng gọi: 0902551442
Nhạc Mới
|
Album Mới
|
Video Clip
|
Bảng Xếp Hạng
|
Liên Hệ BQT

WARC-Type: response

Content-Type: application/http; msgtype=response

WARC-Truncated: length

Server: Apache

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Content-Encoding: gzip

Vary: Accept-Encoding,User-Agent

Connection: close

Content-Type: text/html; charset=UTF-8