Sử dụng XForms để tạo công cụ kế toán, Phần 4: Quản lí và báo cáo tài sản

Theo dõi các yêu cầu của người sử dụng liên quan tới các tài sản trong X-Trapolate

Loạt bài sáu phần trình bày về cách làm thế nào tận dụng sức mạnh của XForms kết hợp với MySQL và PHP để hỗ trợ tiến trình tạo ra một công cụ kế toán trực tuyến được gọi là X-Trapolate. Tất cả công nghệ lập trình tốt đều xử lý một mảng các bài toán mà nó có thể giải quyết tốt. Loạt bài này nêu bật những vấn đề mà XForms giải quyết một cách hiệu quả, chẳng hạn như nhu cầu về những tính toán trực tuyến và tương tác cao. Phần 4 của loạt bài sáu phần này sẽ giải thích cách kết hợp nhiều kỹ thuật đã được đề cập trong phần trước bằng việc sử dụng các ví dụ về biểu mẫu xem lại đơn đặt hàng và biểu mẫu quản lí tài sản, với những đặc quyền cho những người sử dụng cung ứng. Phần này cũng giới thiệu các kỹ thuật mới giúp giải quyết những vấn đề phát sinh thực tế.

Nicholas Chase, Tác giả tự do, Site Dynamics Interactive Communications

Nicholas Chase đã phát triển trang web cho các công ty lớn như Lucent Technologies, Sun Microsystems, Oracle, và Tampa Bay Buccaneers. Nick đã từng là một giáo viên vật lý ở trường phổ thông, một nhà quản lý thiết bị phóng xạ mức thấp, một nhà biên tập tạp chí khoa học viễn tưởng trực tuyến, một kỹ sư đa phương tiện, một hướng dẫn của Oracle, và một trưởng phòng công nghệ của một công ty tương tác truyền thông. Nick là tác giả của một số sách


Tác giả chuyên gia của
        developerWorks

Stony Yakovac, Kỹ sư phần mềm, 自由职业者

Stony Yakovac là một kỹ sư và là một nhà viết sách tự do, ông đang sống tại Lava Hot Springs, bang Idaho, Hoa Kỳ. Ông làm cho rất nhiều dự án thuộc nhiều lĩnh vực, bao gồm các thiết kế về phần mềm và phần cứng số



10 07 2009

Trước khi bắt đầu

Hướng dẫn này dành cho những người phát triển nghiên cứu áp dụng của XForms trong tình hình thực tế, hơn là trong việc tạo ra các ứng dụng "đồ chơi". Nó miêu tả áp dụng của XForms trong việc tạo ra hai biểu mẫu kế toán thuộc ứng dụng kết toán X-Trapolate. Hướng dẫn này mặc định rằng bạn đã có kiến thức cơ bản về XForms, nhưng không cần biết về những nghiệp vụ kế toán.

Về hướng dẫn này

Tổng quan về các hướng dẫn và các bài viết khác trong loạt bài này

Trong Phần 3 của loạt bài viết này, bạn đã tạo ra một biểu mẫu để theo dõi các tài sản liên quan tới ngân sách, lợi nhuận, và chi tiêu của công ty mà bạn giả định. Trong Phần 4 này, bạn sẽ nghiên cứu sâu hơn về các tài sản.

Các doanh nghiệp đều có tài sản, đó có thể là các tòa nhà, dây chuyền lắp ráp tự động, máy vi tính, hay các công cụ đơn giản khác. Những tài sản đó phải được mua, sửa chữa, và thay thế tại nhiều thời điểm khác nhau. Trong hướng dẫn này, bạn sẽ xây dựng một biểu mẫu để theo dõi những yêu cầu của người sử dụng liên quan đến các tài sản. Bạn sẽ xây dựng một biểu mẫu dành cho những người sử dụng điển hình, và một biểu mẫu nữa cho những người sử dụng cung ứng chịu trách nhiệm về giải quyết những vấn đề phát sinh.

Bạn cũng sẽ xây dựng một biểu mẫu dành cho việc truy lục các đơn đặt hàng. Trong cả hai trường hợp, bạn sẽ thấy một loại vấn đề phát sinh xảy ra khi bạn xây dựng một ứng dụng thực tế. Bạn làm thế nào để kết hợp thông tin từ các bảng cơ sở dữ liệu riêng rẽ? Điều gì xảy ra khi dữ liệu không được cấu trúc để giúp chức năng XForms được thuận tiện? Hướng dẫn này sẽ chỉ ra những vấn đề phát sinh đó.

Trong khuôn khổ hướng dẫn này, bạn sẽ nghiên cứu:

  • Cách tạo ra một biểu mẫu chính-chi tiết (master-detail) bằng việc sử dụng XForms
  • Cách sử dụng các câu lệnh lồng nhau switch/case để xử lý các tình huống xảy ra đồng thời
  • Cách xây dựng một thể hiện XML từ nhiều bảng cơ sở dữ liệu
  • Cách thiết lập tự động dữ liệu "trực tiếp" như là ngày hiện tại sau khi một biểu mẫu được nạp
  • Cách xây dựng một hộp lựa chọn đơn giá trị

Về loạt bài viết này

Mục đích của loạt bài viết này là chỉ ra các tiện ích của XForms trong phát triển các ứng dụng Web thực tế và hướng dẫn người đọc cách sử dụng XForms.

  • Phần 1 giới thiệu tổng quan về toàn bộ loạt bài viết này, tóm tắt tất cả các phần của kết quả cuối cùng và khía cạch mà XForms sẽ được sử dụng trong mỗi một phần.
  • Phần 2 giới thiệu về đăng nhập và quản lí tài khoản.
  • Phần 3 đề cập về phát triển các biểu mẫu gắn với quản lí tài sản.
  • Phần 4 tiếp tục giới thiệu về phát triển quản lí tài sản và báo cáo của nhiều khía cạnh kế toán của một doanh nghiệp.
  • Phần 5 giới thiệu về quản lí trách nhiệm pháp lý và cách cải tiến nó.
  • Phần 6 tổng kết loạt bài viết này với một tóm tắt về các công cụ được phát triển, đưa ra một số đề nghị cho việc cải tiến bộ công cụ trong tương lai.

Các điều kiện tiên quyết

Hướng dẫn 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 bài viết này, nhưng nó đòi hỏi người đọc phải có kiến thức về cách hoạt của MySQL. PHPMyAdmin cung cấp những truy cập tương ứng để cấu hình cơ sở dữ liệu MySQL và xem toàn bộ từ một giao diện đồ họa hướng thực đơn.

Mặc dù mục đích của loạt bài viết này là để hướng dẫn người đọc sử dụng XForms, nhưng người đọc vẫn cần có một số kiến thức cơ bản về lĩnh vực này. Có một số bài viết và loạt bài giới thiệu về XForms rất hay trên trang developerWorks (xem Tài nguyên). XForms được xây dựng trên XML, và vì thế, người đọc cũng cần có kiến thức cơ bản về XML.

Trong bài viết này, các công nghệ và khái niệm khác cũng có thể được đề cập, nhưng chúng sẽ được đề cập một cách ngắn gọn.

Các yêu cầu về hệ thống

Để thực hành các ví dụ theo hướng dẫn của bài này, bạn cần có những phần mềm như dưới đây:

  • Một trình duyệt có khả năng hiển thị XForms, ví dụ như Firefox 2.0.1.
  • Một máy chủ có khả năng làm việc với PHP như là WAMP
  • Một máy chủ SQL, MySQL, trong trường hợp này, nó là một phần của gói WAMP.

Tổng quan

Trong ba phần đầu của loạt bài viết về chủ đề này, bạn đã được giới thiệu rất nhiều khái niệm và các kỹ thuật cần thiết để xây dựng nên một ứng dụng "thực sự" sử dụng XForms. Trong hướng dẫn này, bạn sẽ xem cách các quá trình tương kết khi bạn xây dựng hai biểu mẫu từ sự hỗn tạp, cũng như các điều kiện cần thiết của phía sau PHP để làm chúng hoạt động.

Chúng ta hãy bắt đầu

Hướng dẫn này miêu tả quá trình xây dựng của hai biểu mẫu riêng biệt. Đầu tiên là một biểu mẫu xem lại đơn đặt hàng, biểu mẫu này cho phép người sử dụng xem các thông tin liên quan tới hóa đơn, bao gồm ngày đặt hàng, số tài khoản, và phần mô tả về số lượng của các mục được mua từ công ty đồ nội thất được giả định, và đây cũng là chủ đề chính của loạt bài viết này, như bạn có thể thấy trong Hình 1.

Hình 1. Biểu mẫu xem lại đơn đặt hàng
Biểu mẫu xem lại đơn đặt hàng

Biểu mẫu này hoạt động như là một biểu mẫu "chi tiết chủ". Khi người sử dụng chọn một hóa đơn mới, những thông tin về hóa đơn đó sẽ tự động xuất hiện trong vùng chi tiết phía dưới.

Hướng dẫn này cũng miêu tả quá trình xây dựng một biểu mẫu phức tạp hơn, biểu mẫu quản lí tài sản, biểu mẫu này theo dõi những vấn đề phát sinh liên quan tới những tài sản do công ty sở hữu, các công cụ như vậy, bạn có thể thấy trong Hình 2.

Hình 2. Biểu mẫu quản lí tài sản
Biểu mẫu quản lí tài sản

Biểu mẫu này cũng cung cấp cách nhìn thứ hai cho những người sử dụng có quyền truy cập, nó cho phép những người sử dụng quản lí các vấn đề phát sinh một cách trực tiếp, như bạn có thể thấy trong Hình 3.

Hình 3. Tổng quan vấn đề phát sinh
Tổng quan vấn đề phát sinh

Cơ sở dữ liệu

Để hoàn thành nhiệm vụ này, bạn sẽ cần tạo mới một số bảng trong cơ sở dữ liệu của bạn. Các cấu trúc bảng và dữ liệu mẫu đã được bao gồm trong tệp tải xuống của hướng dẫn này. Nếu bạn làm theo mã trình, tải xuống tệp mẫu, và chạy nó trên cơ sở dữ liệu của bạn. Bạn nên hiểu rõ cách các bảng mà bạn thấy trong hướng dẫn này liên kết với nhau. Các bảng đó là:

  • hóa đơn (invoices)
  • sản phẩm (products)
  • phòng ban (departments)
  • tài sản (assets)
  • assetdeptlinkage
  • assetissues

Bảng hóa đơn bao gồm các thông tin về sản phẩm được bán và số lượng được bán là bao nhiêu. Nó chỉ bao gồm tên sản phẩm, hoặc mã hàng, nên muốn xem thông tin chi tiết về sản phẩm hiện thời, bạn cần xem nó trong bảng sản phẩm.

Trước đó, trong Phần 2, tất cả người sử dụng đã được gắn kèm với một phòng ban. Bảng assetdeptlinkage kết hợp các phòng ban với những tài sản riêng lẻ. Cuối cùng, bảng assetissues bao gồm các thông tin về những vấn đề phát sinh và tên tài sản.


Hóa đơn (Invoices): Dữ liệu

Hãy bắt đầu với biểu mẫu hóa đơn. Bước đầu tiên cần trích dữ liệu từ cơ sở dữ liệu bằng cách sử dụng một tập lệnh PHP và xuất nó ra dưới dạng XML để sinh ra các thể hiện trong biểu mẫu.

Cấu trúc mục tiêu

Biểu mẫu thể hiện cần bao gồm các thông tin về các hóa đơn và các mục có trong chúng (xem Ví dụ 1).

Ví dụ 1. Tài liệu thể hiện hóa đơn
   <data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <invoices>
           <invoice>
              <invoiceId/>
              <orderDate/>
              <acctId/>
              <order>
                <sku/>
                <quantity/>
                <unitPrice/>
                <description/>
              </order>
              <order>
                ...
              </order>
          </invoice>
          <invoice>
             ...
          </invoice>
      </invoices>
   </data>

Cấu trúc định nghĩa mỗi mục riêng lẻ được đặt hàng trên một hóa đơn như là một phần tử order. Số lượng của hóa đơn bao gồm trong cấu trúc này được quyết định bởi ngày bắt đầu và kết thúc được gửi bởi biểu mẫu.

Xử lý dữ liệu đầu vào

Dữ liệu đầu vào từ biểu mẫu như là một thể hiện XML với cấu trúc được thấy trong Ví dụ 2.

Ví dụ 2. Thể hiện đối số
            <formui xmlns="">
               <startDate/>
               <endDate/>
               <loadInvoices/>
               <errorMessage/>
            </formui>

Tập lệnh PHP nạp dữ liệu này như một phần của ký tự trắng yêu cầu POST (xem Ví dụ 3).

Ví dụ 3. Truy lục các tham số
<?php
   if (!isset($HTTP_RAW_POST_DATA)) 
        $HTTP_RAW_POST_DATA = file_get_contents("php://input");
   $xml = $HTTP_RAW_POST_DATA;

   $args = new DomDocument('1.0');
   if ($xml) $args->loadXML($xml);

?>

Sau đó, bạn sẽ trích các tham số đơn lẻ từ tài liệu các đối số.

Tạo các khuôn mẫu

Mục đích của tập lệnh này là để tạo ra một tài liệu XML mà bạn sẽ trả về biểu mẫu XForms. Để làm điều đó, đầu tiên bạn tạo ra tài liệu để sản sinh (xem Ví dụ 4).

Ví dụ 4. Tài liệu và các khuôn mẫu
 ...
   $args = new DomDocument('1.0');
   if ($xml) $args->loadXML($xml);

   $doc = new DomDocument('1.0');
   $doc->loadXml('<?xml version="1.0" encoding="UTF-8"?>
   <data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <invoices/>
   </data>');

   $iTmplt = $doc->createElement("invoice");
   $tmp = $doc->createElement("invoiceId");
   $iTmplt->appendChild($tmp);
   $tmp = $doc->createElement("orderDate");
   $iTmplt->appendChild($tmp);
   $tmp = $doc->createElement("acctId");
   $iTmplt->appendChild($tmp);

   $oTmplt = $doc->createElement("order");
   $tmp = $doc->createElement("sku");
   $oTmplt->appendChild($tmp);
   $tmp = $doc->createElement("quantity");
   $oTmplt->appendChild($tmp);
   $tmp = $doc->createElement("unitPrice");
   $oTmplt->appendChild($tmp);
   $tmp = $doc->createElement("description");
   $oTmplt->appendChild($tmp);

   $invoicesNode=$doc->GetElementsByTagName('invoices')->item(0);
  
echo $doc->saveXML();
?>

Tài liệu trống tương đối đơn giản. Từ đó, sử dụng đối tượng tài liệu để tạo ra hóa đơn và các phần tử đặt hàng. Bạn sẽ sử dụng điều này như những khuôn mẫu để tạo ra các phần tử được sinh ra trong một thời điểm. Bạn sẽ thêm những phần tử được sản sinh này vào trong phần tử invoices chính, và bây giờ hãy truy lục một tham chiếu với điều đó.

Cuối cùng, bạn sẽ xuất ra tài liệu như dữ liệu đầu ra của tập lệnh.

Lấy ra hóa đơn duy nhất

Tại điểm này, bạn có một lựa chọn. Bạn đang cố gắng sinh ra các phần tử invoice đơn lẻ, nó có thể bao gồm những phần tử order bội. Trong một môi trường có dung lượng lớn (hay bộ dữ liệu lớn), bạn có thể chọn làm điều này trong một lượt sử dụng một câu lệnh SQL đã được kiểm tra cẩn thận. Ví dụ, để đơn giản hơn về biểu mẫu XForms, bạn sẽ chọn tùy chọn khác, đầu tiên nạp các thông tin hóa đơn đơn lẻ và sau đó nạp các đơn đặt hàng.

Bắt đầu bằng việc tập hợp các thông tin hóa đơn (xem Ví dụ 5).

Ví dụ 5. Tập hợp hóa đơn
...
   $invoicesNode=$doc->GetElementsByTagName('invoices')->item(0);

   $startDate= $args->GetElementsByTagName('startDate')
                    ->item(0)->nodeValue;
   $endDate= $args->GetElementsByTagName('endDate')
                    ->item(0)->nodeValue;

   $sqldb = mysql_connect('localhost', 'root');
   if (!$sqldb) 
      die('Could not connect to MySQL server at localhost because: ' . 
                    mysql_error());

   $sqlseldb = mysql_select_db('acct1', $sqldb);
   if (!$sqlseldb) 
       die ('Can\'t select the acct database on MySQL server @ '.
            'localhost because: ' . mysql_error());

   $query = sprintf('SELECT DISTINCT invoiceId, orderDate, acctId '.
                    'FROM invoices '.
                    'WHERE orderDate >= \'%s\' '.
                           'AND orderDate <= \'%s\' '.
                    'ORDER BY invoices.orderDate DESC ;',
                                         $startDate, $endDate);

   $invoiceIdList = mysql_query($query, $sqldb);
   if (!$invoiceIdList) 
         die ('Could not execute acct db query: <b>'.$query.
                             '</b> because:  ' . mysql_error());

   while ($invoiceRow = mysql_fetch_assoc($invoiceIdList)) {

      $newInvoice = $iTmplt->cloneNode(TRUE);
      $invoicesNode->appendChild($newInvoice);
      $invoiceId = $invoiceRow['invoiceId'];
      for($temp = $newInvoice->firstChild;
          $temp != NULL;
          $temp = $temp->nextSibling) {

         if (array_key_exists($temp->nodeName, $invoiceRow)) {
            $temp->nodeValue=$invoiceRow[$temp->nodeName];
         }
      }
   }

echo $doc->saveXML();
?>

Đầu tiên, truy lục các thông tin ngày đầu và ngày cuối từ biểu mẫu, như đã được trình bài trong tài liệu args. Tiếp theo, kết nối với máy chủ và lựa chọn cơ sở dữ liệu thích hợp. Từ đó, tạo ra các truy vấn giúp cấu trúc nó để truy lục các thông tin liên quan đến hóa đơn cho mỗi hóa đơn liên quan, ví dụ như orderDate.

Tránh sử dụng trực tiếp dữ liệu đệ trình bởi người sử dụng

Trong một ứng dụng sản xuất, bạn muốn tránh sử dụng trực tiếp dữ liệu đệ trình bởi người sử dụng, như đề cập ở đây, để chống những tấn công tín hiệu SQL. Xem Tài nguyên để biết thêm thông tin về cách phòng chống loại tấn công này của vấn để bảo mật.

Khi bạn có danh sách, hãy lặp qua nó. Ở mỗi dòng, tạo ra một bản sao của khuôn mẫu hóa đơn và kết nối với các hóa đơn. Các phần tử con của nó được đặt tên cẩn thận tương ứng những phần tử trong cơ sở dữ liệu, nên bạn có thể lặp qua các phần tử con của nó để tìm kiếm những giá trị thích hợp và sản sinh ra chúng cho phù hợp.

Sản sinh các đơn đặt hàng

Sản sinh các đơn đặt hàng riêng lẻ gần như là quá trình giống nhau (xem Ví dụ 6).

Ví dụ 6. Truy lục các đơn đặt hàng
...
         if (array_key_exists($temp->nodeName, $invoiceRow)) {
            $temp->nodeValue=$invoiceRow[$temp->nodeName];
         }
      }

      $query = sprintf('SELECT * FROM invoices WHERE invoiceId=%d;',
                                                      $invoiceId);

      $invoiceRows = mysql_query($query, $sqldb);
      if (!$invoiceRows) 
             die ('Could not execute acct db query: <b>'.$query.
                                 '</b> because:  ' . mysql_error());

      while ($orderRow = mysql_fetch_assoc($invoiceRows)) {
         $acctId = $orderRow['acctId'];
         $sku = $orderRow['sku'];

         $newOrder = $oTmplt->cloneNode(TRUE);
         $newInvoice->appendChild($newOrder);
         for($temp=$newOrder -> firstChild;
             $temp != NULL;
             $temp = $temp->nextSibling) {

            if (array_key_exists($temp->nodeName, $orderRow)) {
               $temp->nodeValue=$orderRow[$temp->nodeName];
            }

         }

      }
   }

echo $doc->saveXML();
?>

Khi bạn đang xử lý mỗi hóa đơn, hãy sử dụng invoiceId để truy lục các đơn đặt hàng riêng lẻ. Nhân bản khuôn mẫu đặt hàng và sinh ra nó, kết nối nó với hóa đơn hiện thời.

Sản sinh thông tin sản phẩm

Xét về mặt dữ liệu, đó tất cả những gì bạn cần, nhưng để hiển thị mô tả sản phẩm mà người bình thường có thể đọc được, bạn cần phải truy lục nó từ cơ sở dữ liệu (xem Ví dụ 7).

Ví dụ 7. Truy lục thông tin sản phẩm
...
            if (array_key_exists($temp->nodeName, $orderRow)) {
               $temp->nodeValue=$orderRow[$temp->nodeName];
            }

         }

         $query = sprintf('SELECT * FROM products WHERE sku=%d ;', 
                                                             $sku);

         $productRows = mysql_query($query, $sqldb);
         if (!$productRows) 
              die ('Could not execute acct db query: <b>'.$query.
                               '</b> because:  ' . mysql_error());
         while ($productRow = mysql_fetch_assoc($productRows)) {

            for($temp = $newOrder->firstChild;
                $temp != NULL;
                $temp = $temp->nextSibling) {

               if (array_key_exists($temp->nodeName, $productRow) 
                                      && ($temp->nodeValue == NULL)) {
                  $temp->nodeValue=$productRow[$temp->nodeName];
               }
            }
         }

      }
   }

echo $doc->saveXML();
?>

Tại bước này, tài liệu đã hoàn thiện, chúng ta hãy nhìn vào biểu mẫu.


Hóa đơn: Biểu mẫu chi tiết chủ

Trong biểu mẫu chi tiết chủ, người sử dụng lựa chọn từ một danh sách của các định danh và tự động lấy ra các thông tin mở rộng trên vùng chọn. Đây cũng là nơi mà các mục đơn lẻ thường cần được kiểm tra. Chúng ta hãy xem một cách để thực thi điều đó trong XForms.

Chúng ta hãy bắt đầu bằng việc nhìn vào sự hiển thị cơ bản của bảng thông tin kiểm kê, và sau đó xem tiếp phần chi tiết chủ.

Biểu mẫu cơ bản

Bắt đầu bằng cách tạo ra biểu mẫu cơ bản, bao gồm những thông tin hóa đơn sẽ được hiển thị (xem Ví dụ 8).

Ví dụ 8. Biểu mẫu cơ bản
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
          "http://www.w3.org/TR/xhtml1/D/tdxhtml1-strict.dtd">
<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xforms="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
   <head>
      <title>XForms Accounting Tool Order Viewer</title>
      <xforms:model id="atipm" >

         <xforms:instance id="atipi">
            <formui xmlns="">
               <startDate/>
               <endDate/>
               <loadInvoices/>
               <errorMessage/>
            </formui>
         </xforms:instance>

         <xforms:instance id="work" >
            <invoices xmlns="">
               <backorder/>
               <invoice><invoiceId>2560555</invoiceId>
<orderDate>2007-04-06</orderDate><acctId>634</acctId>
<order><sku>113896</sku><quantity>875</quantity>
<unitPrice>561.00</unitPrice><description>Laser Detailed 
Jatoba 4ft.x5ft. Legal Bookcase</description></order><order>
<sku>115965</sku><quantity>42</quantity>
<unitPrice>750.00</unitPrice><description>Carved Zebrawood 
Nightstand with Drawer and Magazine 
Rack</description></order><order><sku>124167
</sku><quantity>382</quantity><unitPrice>2772.00
</unitPrice><description>Customized Teak 4ft. 
Square Pedestal Table</description></order></invoice>
               <date/>
            </invoices>
         </xforms:instance>

         <xforms:instance id="data" >
            <data xmlns=""/>
         </xforms:instance>

      <xforms:bind nodeset="instance('atipi')/startDate"
         type="xsd:date"/>
      <xforms:bind nodeset="instance('atipi')/endDate"         
         type="xsd:date"/>
      </xforms:model>

      <xforms:action ev:event="xforms-ready">
         <xforms:setvalue ref="instance('atipi')/startDate"
                          value="'2006-07-01'"/>
         <xforms:setvalue ref="instance('atipi')/endDate"
                          value="substring(now(),1,10)"/>
      </xforms:action>

   </head>
  
   <body>
      <hr/>
      <xforms:output class="errorMessage" 
            ref="instance('acctToolBillInst')/errorMessage"/>
      <xforms:input ref="instance('atipi')/startDate"> 
          <xforms:label>Start Date</xforms:label> 
      </xforms:input>
      <xforms:input ref="instance('atipi')/endDate"> 
          <xforms:label>End Date</xforms:label> 
      </xforms:input>

      <hr/>

   </body>               
</html>

Bắt đầu từ trên xuống dưới, thể hiện atipi chứa các tham số dành cho biểu mẫu nạp hóa đơn. Thể hiện work chứa các hóa đơn riêng lẻ được hiện thị trong trường chi tiết. Thể hiện data sẽ cơ bản chứa tất cả các hóa đơn được trả về bởi tập lệch.

Các câu lệnh bind giúp cho biểu mẫu biết rằng ngày bắt đầu và ngày kết thúc là những giá trị ngày tháng, nó khiến chúng được hiển thị cùng với công cụ lịch biểu, như bạn thấy trong Hình 4. Giá trị của hai trường này được tự động thiết lập khi biểu mẫu nạp xong hoàn toàn, nhờ vào hành động.

Cuối cùng, bạn hiển thị bất cứ thông báo lỗi nào đã được trả lại (cuối cùng -- không có sự kiện nào thực sự được đệ trình!) và ngày bắt đầu và kết thúc.

Hiển thị các hóa đơn

Thực sự việc hiển thị thông tin hóa đơn là một vấn đề đơn giản khi sử dụng các điểu khiển xuất ra và lặp lại, như bạn đã thấy trong các phần trước của loạt bài viết này (xem Ví dụ 9).

Ví dụ 9. Hiển thị hóa đơn
...
      <xforms:input ref="instance('atipi')/endDate"> 
          <xforms:label>End Date</xforms:label> 
      </xforms:input>

      <hr/>

              <table width="100%">
                 <tr><th align="left">Invoice ID:  <xforms:output 
                      value="instance('work')/invoice/invoiceId"/>
                     </th></tr>
                 <tr><th align="left">Order Date:  <xforms:output 
                      value="instance('work')/invoice/orderDate"/>
                     </th></tr>
                 <tr><th align="left">Account ID:  <xforms:output 
                         value="instance('work')/invoice/acctId"/>
                     </th></tr>
              </table>
              <hr/>
              <table width="100%">
                 <tr>
                    <th width="50px">Quantity Ordered</th>
                    <th width="100px" align="left">Description</th>
                 </tr>
              </table>

              <xforms:repeat id="orderLineRpt" 
                           nodeset="instance('work')/invoice/order">

                 <table width="100%">
                    <tr>
                       <td align="center" width="50px">
                            <xforms:output value="quantity"/>
                       </td>
                       <td align="left" width="100px">
                            <xforms:output value="description" />
                       </td>
                    </tr>
                 </table>

              </xforms:repeat>

   </body>
</html>

Như bạn thấy trong Hình 4, tất cả thông tin được hiển thị tại chỗ.

Hình 4. Thông tin hóa đơn
Thông tin hóa đơn

Ẩn hiển thị

Biểu mẫu này chỉ xuất hiện trên ngày hóa đơn đã được chọn, nên chúng ta hãy sử dụng một xây dựng khóa chuyển đổi/trường hợp để ẩn nó cho tới khi nó được yêu cầu (xem Ví dụ 10).

Ví dụ 10. Ẩn cấu trúc hóa đơn
...
      <xforms:input ref="instance('atipi')/endDate"> 
          <xforms:label>End Date</xforms:label> 
      </xforms:input>

      <hr/>

      <xforms:switch>

          <xforms:case id="blank" selected="true()">
          </xforms:case>

          <xforms:case id="show_invoice_detail">
              <table width="100%">
                 <tr><th align="left">Invoice ID:  <xforms:output 
                      value="instance('work')/invoice/invoiceId"/>
...
                    </tr>
                 </table>

              </xforms:repeat>

          </xforms:case>
      </xforms:switch>

   </body>
</html>

Khi biểu mẫu nạp, trường hợp trống được kích hoạt, và cấu trúc được ẩn.

Nạp các hóa đơn

Với cấu trúc hiển thị tại chỗ, bây giờ hãy nạp dữ liệu trực tiếp (xem Ví dụ 11).

Ví dụ 11. Nạp dữ liệu
...
         <xforms:instance id="work" >
            <invoices xmlns="">
               <backorder/>
               <invoice/>
               <date/>
            </invoices>
         </xforms:instance>

         <xforms:instance id="data" >
            <data xmlns=""/>
         </xforms:instance>

         <xforms:submission id="load_invoices"
                            action="get_invoices.php" 
                            method="post"
                            replace="instance" 
                            instance="data"
                            ref="instance('atipi')" />

      <xforms:bind nodeset="instance('atipi')/startDate"          
         type="xsd:date"/>
...
      <xforms:input ref="instance('atipi')/endDate"> 
          <xforms:label>End Date</xforms:label> 
      </xforms:input>

      <xforms:submit submission="load_invoices" 
                        ref="instance('atipi')/loadInvoices">
         <xforms:label>Refresh/Load Invoices</xforms:label>
         <xforms:toggle ev:event="DOMActivate" 
                        case="show_invoice_detail"/>
      </xforms:submit>

      <hr/>

      <xforms:switch>
...

Ở đây, bạn đang xóa bỏ dữ liệu mẫu và thêm mới một nút bấm để nạp thực hiện data (không phải thực hiện work) với các hóa đơn thích hợp như được trả về bởi tập lệnh PHP mà bạn đã viết trong phần trước. Cũng như vậy, khi người sử dụng nhấn vào nút bấm, nó làm thay đổi trường hợp để hiển thị biểu mẫu mà bạn vừa làm ẩn.

Mặc dù vậy, hiện tại, biểu mẫu không có dữ liệu.

Lựa chọn một hóa đơn

Cuối cùng, bạn đã sắp hoàn thành, tiếp theo bạn cần chọn một cách để lựa chọn một hóa đơn riêng lẻ (xem Ví dụ 12).

Ví dụ 12. Chọn một hóa đơn
...
         <xforms:toggle ev:event="DOMActivate" 
                        case="show_invoice_detail"/>
      </xforms:submit>

      <xforms:select1 ref="instance('work')" id="selinv" 
                                            incremental="true">
         <xforms:label>Select An Invoice To View:  </xforms:label>
         <xforms:itemset nodeset="instance('data')/invoices/invoice">
            <xforms:label ref="invoiceId"/>
            <xforms:copy ref="."/>
         </xforms:itemset>
      </xforms:select1>

      <hr/>

      <xforms:switch>
...

Đây là nơi sự kỳ diệu xảy ra. Điều khiển select1 chứa một itemset, nó bao gồm tất cả các phần tử invoice như nội dung của nó. Mặc dù vậy, phần tử hiện thời select1 là thực hiện work. Nó cũng chứa thuộc tính incremental = "true", có nghĩa là khi người sử dụng chọn một giá trị mới, thì biểu mẫu sẽ đánh giá lại.

Khi biểu mẫu đánh giá lại, phần tử select1 lấy giá trị của những nội dung của nó, trong trường hợp này nó là phần tử hóa đơn được lựa chọn hoàn thiện. Theo cách này, bạn sẽ sinh ra thực hiện work, làm cho dữ liệu hiển thị, như trong Hình 5.

Hình 5. Biểu mẫu được hoàn thành
Biểu mẫu được hoàn thành

Đó là kết thúc về biểu mẫu hóa đơn. Chúng ta hãy chuyển sang biểu mẫu quản lí tài sản.


Tài sản: Dữ liệu

Biểu mẫu quản lí tài sản bao gồm dữ liệu từ một số bảng khác nhau. Trong phần này, bạn sẽ kết hợp các tập lệnh PHP với nhau và đặt chúng vào một thể hiện XML đơn lẻ.

Cấu trúc mục tiêu

Cấu trúc XML được mong muốn bởi biểu mẫu quản lí tài sản, theo nhiều cách nó giống như một cơ sở dữ liệu liên quan tới bản thân nó (xem Ví dụ 13).

Ví dụ 13. Dữ liệu XML mong muốn
 <data>
    <assets>
       <asset>
          <assetId/>
          <description/>
          <purchaseDate/>
          <vendorId/>
          <issue>
             <issueId/>
             <reason/>
             <action/>
             <date/>
             <status/>
             <acctId/>
             <response/>
          </issue>
       </asset>
    </assets>
    <vendors>
       <vendor vendorId="">
          <brief/>
          <acctId/>
          <company/>
          <firstName/>
          <lastName/>
          <company/>
          <street/>
          <city/>
          <state/>
          <zip/>
          <country/>
       </vendor>
    </vendors>
 </data>

Đối với mỗi tài sản, bạn muốn hiển thị thông tin nhà cung cấp, nhưng nó không có nghĩa là bao gồm tất cả các thông tin đó với mọi tài sản. Thay vào đó, thể hiện bao gồm các nhà cung cấp riêng biệt, và tham chiếu chúng bằng vendorId.

Lấy phòng ban

Trong trường hợp này, biểu mẫu chỉ nên hiển thị thông tin trên các tài sản liên quan với phòng ban của người sử dụng hiện thời, do vậy bạn sẽ cần kiểm tra để đảm bảo người sử dụng đã đăng nhập trước khi làm việc gì đó (xem Ví dụ 14).

Ví dụ 14. Kiểm tra trạng thái đăng nhập
<?php

session_start();
if (!isset($HTTP_RAW_POST_DATA)) 
      $HTTP_RAW_POST_DATA = file_get_contents("php://input");
$xml = $HTTP_RAW_POST_DATA;

$args = new DomDocument('1.0');
if ($xml) $args->loadXML($xml);

if ($_SESSION['loginToken'] != 
       $args->getElementsByTagName('loginToken')->item(0)->nodeValue) {
   $errorMessage = 
            $doc->getElementsByTagName('errorMessage')->item(0);
   $errorMessage->nodeValue="Not logged in!";
   exit;
}
$deptId = $_SESSION['at_deptId'];

?>

Trở lại Phần 2, bạn đã xây dựng hệ thống đăng nhập, trong đó bao gồm một mã thông báo đăng nhập được gán cho phiên khi người sử dụng đăng nhập. Trong trường hợp này, tập lệnh khởi chạy phiên, sau đó kiểm tra loginToken đang tồn tại với mã đăng nhập được đệ trình với biểu mẫu. Nếu nó không khớp, tập lệnh sẽ thoát. Nếu nó khớp, tập lệnh sẽ truy lục departmentId từ phiên.

Tạo ra tài liệu và các khuôn mẫu cơ bản

Quá trình tổng quát như ở đây giống như quá trình được sử dụng trong biểu mẫu chi tiết chủ: Tạo ra một tài liệu rỗng và các khuôn mẫu cho các thông tin đang được nạp (xem Ví dụ 15).

Ví dụ 15. Tạo tài liệu cơ bản
<?php

session_start();

$doc = new DomDocument('1.0');
$doc->loadXml('<?xml version="1.0" encoding="UTF-8"?>
<data xmlns:xforms="http://www.w3.org/2002/xforms" 
      xmlns:ev="http://www.w3.org/2001/xml-events" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <errorMessage/>
   <assets/>
   <vendors/>
</data>');

if ($_SESSION['loginToken'] != 
...
$deptId = $_SESSION['at_deptId'];

$assetsNode = $doc->getElementsByTagName('assets')->item(0);

$aTmplt = $doc->createElement("asset");
$assetsNode->appendChild($aTmplt);
$temp = $doc->createElement("assetId");
$aTmplt->appendChild($temp);
$temp = $doc->createElement("description");
$aTmplt->appendChild($temp);
$temp = $doc->createElement("purchaseDate");
$aTmplt->appendChild($temp);
$temp = $doc->createElement("vendorId");
$aTmplt->appendChild($temp);

$iTmplt = $doc->createElement("issue");
$aTmplt->appendChild($iTmplt);
$iTmplt->setAttribute("selected",'0');
$temp = $doc->createElement("issueId");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("reason");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("action");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("date");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("status");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("acctId");
$iTmplt->appendChild($temp);
$temp = $doc->createElement("response");
$iTmplt->appendChild($temp);

$vendorsNode = $doc->getElementsByTagName('vendors')->item(0);
$vTmplt = $doc->createElement("vendor");
$vendorsNode->appendChild($vTmplt);
$temp = $doc->createElement("brief");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("acctId");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("company");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("firstName");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("lastName");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("company");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("street");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("city");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("state");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("zip");
$vTmplt->appendChild($temp);
$temp = $doc->createElement("country");
$vTmplt->appendChild($temp);

echo $doc->saveXML();

?>

Trong trường hợp này, bạn thấy một chút thay đổi. Trong khi trước đây, các khuôn mẫu thuộc tài liệu nhưng nó không thực sự là một phần của cấu trúc. Trong trường hợp này chúng được kết nối với các nốt tài sản hiện thời và chú ý nhà cung cấp.

Lấy tài sản

Quá trình hiện thời của việc truy lục thông tin tài sản cũng gần giống với quá trình được sử dụng để truy lục các hóa đơn (xem Ví dụ 16).

Ví dụ 16. Lấy tài sản
...
$temp = $doc->createElement("country");
$vTmplt->appendChild($temp);


$sqldb = mysql_connect('localhost', 'root');
if (!$sqldb) 
   die('Could not connect to MySQL server at localhost because: ' . 
                                                     mysql_error());

$sqlseldb = mysql_select_db('acct1', $sqldb);
if (!$sqlseldb) 
   die ('Can\'t select the acct database on MySQL server @ '.
                            'localhost because: ' . mysql_error());

$queryEndDate= 
    $args->GetElementsByTagName('queryEndDate')->item(0)->nodeValue;
$queryStartDate= 
  $args->GetElementsByTagName('queryStartDate')->item(0)->nodeValue;

$query = sprintf('SELECT DISTINCT assetId FROM assetdeptlinkage '.
                         'WHERE deptId=%d',$deptId);

$assetIdRows = mysql_query($query, $sqldb);
if (!$assetIdRows) 
      die ('Could not execute acct db query: <b>'.$query.
                          '</b> because:  ' . mysql_error());

while ($assetIdRow = mysql_fetch_assoc($assetIdRows)) {
   $assetId=$assetIdRow['assetId'];
   if ($queryEndDate != '') {
       $query = sprintf(
            'SELECT * FROM assets WHERE '.
                      '(assetId=%d AND purchaseDate<=\'%s\' AND '.
                      'status=\'active\')', 
                      $assetId, $queryStartDate).
            sprintf(' OR (assetId= %d AND purchaseDate<=\'%s\' '.
                           'AND retireDate>=\'%s\')',
                      $assetId, $queryStartDate, $queryEndDate);
   }
   else 
   {
   $query = sprintf('SELECT * FROM assets WHERE ').
            sprintf('status=\'active\' AND assetId=%d', $assetId);
   }

   $assetQueryData = mysql_query($query, $sqldb);
   if (!$assetQueryData) 
          die ('Could not execute acct db query: <b>'.$query.
                            '</b> because:  ' . mysql_error());
   while ($assetRow = mysql_fetch_assoc($assetQueryData)) {
      $newAsset=$aTmplt->cloneNode(TRUE);
      $assetsNode->appendChild($newAsset);
      $assetId = $assetRow['assetId'];
      for($temp=$newAsset->firstChild;
          $temp!=NULL;
          $temp=$temp->nextSibling) {

         foreach($assetRow as $field => $value) {
            if($temp->hasAttribute($field)) {
               $temp->setAttribute($field, $assetRow[$field]);
            }
            if ($field == 'Vendor_acctId') $vendorAcctId=$value;
         }
         if ($temp->nodeName == 'vendorId') 
               $temp->nodeValue=$vendorAcctId;

         if (array_key_exists($temp->nodeName, $assetRow)) {
            $temp->nodeValue=$assetRow[$temp->nodeName];
         }
      }

   }

}

echo $doc->saveXML();

?>

Trong trường hợp này, thay vì sử dụng một truy vấn cố định, bạn cần điều chỉnh theo ngữ cảnh mà ở đó người sử dụng đơn giản muốn tất cả các tài sản kích hoạt, đối lập với những tài sản đã được mua, nhưng không được gián đoạn giữa ngày bắt đầu và ngày kết thúc.

Thêm thông tin nhà cung cấp

Khi bạn có tài sản, bạn cần thêm thông tin nhà cung cấp, thông tin này được lưu trữ trong bảng tài khoản (accounts) (xem Ví dụ 17).

Ví dụ 17. Thêm thông tin nhà cung cấp
...
         if (array_key_exists($temp->nodeName, $assetRow)) {
            $temp->nodeValue=$assetRow[$temp->nodeName];
         }
      }

      $query = sprintf("SELECT * FROM accounts WHERE acctId=%d;", 
                                                   $vendorAcctId);
      $vendorRows = mysql_query($query, $sqldb);
      if (!$vendorRows) 
            die ('Could not execute acct db query: <b>'.$query.
                                '</b> because:  ' . mysql_error());
      while ($vendorRow = mysql_fetch_assoc($vendorRows)) {
         $newVendor=$vTmplt->cloneNode(TRUE);
         $vendorsNode->appendChild($newVendor);
         for($temp = $newVendor->firstChild;
             $temp != NULL;
             $temp = $temp->nextSibling) {

            foreach($vendorRow as $field => $value) {
               if($temp->hasAttribute($field)) {
                  $temp->setAttribute($field, $vendorRow[$field]);
               }
            }
            if (array_key_exists($temp->nodeName, $vendorRow)) {
                $temp->nodeValue=$vendorRow[$temp->nodeName];
            }
         }
      }
   }

}

echo $doc->saveXML();

?>

Bây giờ, quá trình đã trở lên dễ dàng.

Thêm các vấn đề phát sinh

Quá trình tương tự áp dụng để kết thúc bất cứ vấn đề phát sinh nào liên quan tới tài sản (xem Ví dụ 18).

Ví dụ 18. Thêm các vấn đề phát sinh
...
            if (array_key_exists($temp->nodeName, $vendorRow)) {
                $temp->nodeValue=$vendorRow[$temp->nodeName];
            }
         }
      }
   }

   $query = sprintf('SELECT * FROM assetissues WHERE assetId=%d;',
                                                         $assetId);
   $issueRows = mysql_query($query, $sqldb);
   if (!$issueRows) 
          die ('Could not execute acct db query: <b>'.$query.'</b>'.
                                      'because:  ' . mysql_error());
   while ($issueRow = mysql_fetch_assoc($issueRows)) {
      $newIssue = $iTmplt->cloneNode(TRUE);
      $newIssue->setAttribute('real','1');
      for($temp = $newIssue->firstChild; 
          $temp != NULL;
          $temp=$temp->nextSibling) {

         foreach($issueRow as $field => $value) {
            if($temp->hasAttribute($field)) {
               $temp->setAttribute($field, $issueRow[$field]);
            }
         }
         if (array_key_exists($temp->nodeName, $issueRow)) {
             $temp->nodeValue=$issueRow[$temp->nodeName];
         }
      }
      $newAsset->appendChild($newIssue);   
   }
}


$assetsNode->removeChild($aTmplt);
$vendorsNode->removeChild($vTmplt);

echo $doc->saveXML();

?>

Chú ý bước cuối cùng; nếu bạn gọi lại, các khuôn mẫu được thêm vào tài liệu hiện thời. Bởi vì chúng là rỗng, nên bạn sẽ xóa bỏ chúng trước khi trả lại tài liệu.

Bây giờ bạn đã sẵn sàng cho biểu mẫu.


Biểu mẫu quản lí tài sản: Lồng nhau chuyển/trường hợp kê.

Biểu mẫu quản lí tài sản là một biểu mẫu XForms tương đối phức tạp, nó cho phép người sử dụng thêm thông tin cho thực hiện và lưu nó trở lại cơ sở dữ liệu. Nó cũng sử dụng những câu lệnh lồng nhau chuyển/trường hợp để giải quyết vấn đề của nhiều điều kiện không cần thiết liên quan.

Đăng nhập (XForm)

Bắt đầu bằng việc tạo ra một biểu mẫu cơ bản, bao gồm chức năng cho phép người sử dụng đăng nhập (xem Ví dụ 19).

Ví dụ 19. Biểu mẫu đăng nhập
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
          "http://www.w3.org/TR/xhtml1/D/tdxhtml1-strict.dtd">
<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xforms="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
   <head>
      <title>XForms Accounting Tool Issue And Service Request 
Processing</title>

      <link rel="stylesheet" href="style.css" type="text/css"/>
      <style type="text/css">
         textarea { font-family: sans-serif; height: 6em; 
                    width: 400px; }
      </style>

      <xforms:model id="atuim" >

         <xforms:instance id="isol">
            <isol xmlns="">
               <queryStartDate/>
               <queryEndDate/>
            </isol>
         </xforms:instance>

         <xforms:instance id="atuii">
            <formui xmlns="">
               <loginLogout>Login</loginLogout>
               <password/>
               <login>1</login>
               <loginToken/>
               <username/>
               <deptId/>
               <welcome/>

               <issueView/>

               <errorMessage/>

               <issueId/>
               <statusOpts txt="open"/>
               <statusOpts txt="closed"/>
               <statusOpts txt="pending"/>
               <statusOpts txt="confirmed"/>

               <queryStartDate/>
               <queryEndDate/>
               <queryIssueStatus/>
               <queryAcctId/>
               <loadAssets/>

               <numIssuesSelected/>
               <someIssuesSelected/>
               <issueMod/>
               <issueReason/>
               <issueAction/>
               <issueStatus/>
               <issueResponse/>
               <issueSpecialRepairInstructions/>
               <issueRepairInstructions/>
               <issueDate/>
               <issueAssetId/>
               <updateIssue/>
               <submitIssue/>
               <issueActionOpts txt="Repair"/>
               <issueActionOpts txt="Retire"/>
               <issueActionOpts txt="Replace"/>
               <issueActionOpts txt="Purchase"/>
               <issueActionOpts txt="Remove"/>
               <issueActionOpts txt="Add"/>
            </formui>
         </xforms:instance>

         <xforms:instance id="work" >
            <workData xmlns="">
            </workData>
         </xforms:instance>

         <xforms:instance id="queryData" >
            <data xmlns="">
               <errorMessage/>
               <assets/>
               <vendors/>
            </data>
         </xforms:instance>

         <xforms:submission id="login_logout"
                            action="login_logout.php" 
                            method="post"
                            replace="instance" 
                            instance="atuii"
                            ref="instance('atuii')" />

         <xforms:bind nodeset="instance('atuii')/password"
            relevant="number(instance('atuii')/login)=1"/>
         <xforms:bind nodeset="instance('atuii')/username"
            relevant="number(instance('atuii')/login)=1"/>
         <xforms:bind nodeset="instance('atuii')/welcome"
            relevant="instance('atuii')/loginLogout = 'Logout'"
            calculate="concat('Welcome ',
                              instance('atuii')/username)"/>

      </xforms:model>

   </head>
  
   <body>
      <hr/>

      <xforms:input ref="instance('atuii')/username">
          <xforms:label>Username:  </xforms:label>
      </xforms:input>
      <xforms:secret ref="instance('atuii')/password">
          <xforms:label>Password:  </xforms:label>
      </xforms:secret>
      <xforms:submit submission="login_logout" 
                     ref="instance('atuii')/loginLogout">
          <xforms:label ref="instance('atuii')/loginLogout"/>
      </xforms:submit>

      <xforms:output class="errorMessage" 
                     value="concat(instance('atuii')/errorMessage,
                                instance('queryData')/errorMessage)"/>
      <xforms:output ref="instance('atuii')/welcome"/>

   </body>
</html>

Thể hiện atuii rất dài, nhưng là một trình giữ chỗ cho tất cả các thông tin cần bởi giao diện người dùng hiện thời, ví dụ như ID phòng ban hiện tại và trong thông tin được thêm vào một tài sản để đệ trình. Thể hiện work chứa tài sản như trước đây, và thể hiện queryData chứa dữ liệu được trả về từ tập lệnh PHP.

Các câu lệnh bind quyết định biểu mẫu nên hiển thị hộp tên đăng nhập và mật khẩu hay hiển thị thông điệp chào mừng và nút bấm đăng xuất. Khi người sử dụng đăng nhập, biểu mẫu gọi đệ trình login_logout, đệ trình này gọi tập lệnh login_logout.php.

Đăng nhập: PHP

Tập lệnh login_logout.php có chức năng đúng như tên của nó: Nếu những người sử dụng không đăng nhập, nó sẽ đăng nhập họ vào. Nếu họ đã đăng nhập rồi, nó sẽ đăng xuất họ ra (xem Ví dụ 20).

Ví dụ 20. Tập lệnh login_logout.php
<?php
session_start();
if (!isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = file_get_contents("php://input");
$xml = $HTTP_RAW_POST_DATA;
$doc = new DomDocument('1.0');
$doc->loadXML($xml);

if ($doc->GetElementsByTagName('loginLogout')->item(0)->nodeValue == 'Logout'){
   unset($_SESSION['loginToken']);
   unset($_SESSION['username']);
   unset($_SESSION['at_deptId']);
   unset($_SESSION['acctId']);
   $doc->GetElementsByTagName('deptId')->item(0)->nodeValue = "";
   $doc->GetElementsByTagName("errorMessage")->item(0)->nodeValue = 
         sprintf('You have successfully logged out, please reload');
   $doc->GetElementsByTagName('loginLogout')->item(0)->nodeValue = 
         "Login";
   $doc->GetElementsByTagName("username")->item(0)->nodeValue = "";
   $doc->GetElementsByTagName("loginToken")->item(0)->nodeValue = "";
   $doc->GetElementsByTagName('login')->item(0)->nodeValue=1;
   echo $doc->saveXML();
   exit;
}

if (array_key_exists('loginToken', $_SESSION)) { 
   $doc->GetElementsByTagName("username")->item(0)->nodeValue = 
                                         $_SESSION['username'];
   $doc->GetElementsByTagName("loginToken")->item(0)->nodeValue = 
                                         $_SESSION['loginToken'];
   $doc->GetElementsByTagName("errorMessage")->item(0)->nodeValue = 
                     sprintf('%s Logged In',$_SESSION['username']);
   $doc->GetElementsByTagName('loginLogout')->item(0)->nodeValue = 
                                          "Logout";
   $doc->GetElementsByTagName('deptId')->item(0)->nodeValue = 
                                         $_SESSION['at_deptId'];
   $doc->GetElementsByTagName('login')->item(0)->nodeValue=0;
   echo $doc->saveXML();
   exit;
}

$pass = $doc->getElementsByTagName("password")->item(0)->nodeValue;
$uname = $doc->getElementsByTagName("username")->item(0)->nodeValue;

if ($uname == '' && $pass == ''){
   echo $doc->saveXML();
   exit;
}

$sqldb = mysql_connect('localhost', 'root');
if (!$sqldb) die('Could not connect to MySQL server at localhost 
    because: ' . mysql_error());

$sqlseldb = mysql_select_db('acct1', $sqldb);
if (!$sqlseldb) die ('Can\'t select the acct database on MySQL server @ localhost 
    because: ' . mysql_error());

$sqlQuery = sprintf("SELECT * FROM accounts WHERE username='%s' ".
                    "and password='%s'", 
                                      mysql_real_escape_string($uname), 
                                      mysql_real_escape_string($pass));
$queryData = mysql_query($sqlQuery, $sqldb);
if (!$queryData) die ('Could not insert token into tokentable on MySQL server 
     because:  ' . mysql_error());

$doc->getElementsByTagName("password")->item(0)->nodeValue = '';

$numRows = mysql_num_rows($queryData);
if($numRows <= 0)
{
   mysql_close($sqldb);
   $doc->getElementsByTagName("errorMessage")->item(0)->nodeValue = 
                                         'Invalid login credentials!';
   echo $doc->saveXML();
   exit;
}
else
{
   $row = mysql_fetch_assoc($queryData);
   $_SESSION['at_deptId'] = $row['deptId'];
   $_SESSION['acctId'] = $row['acctId'];
   $_SESSION['username'] = $uname;

   $loginToken = rand();
   $_SESSION['loginToken'] = $loginToken;
   $now = localtime();
   $datetime = sprintf("%04d-%02d-%02d",$now[5]+1900,$now[4],$now[3]);
   $sqlQuery = sprintf("INSERT INTO logintokens ".
                         "(logintoken, username, creation) ".
                         " VALUES ( '%d', '%s', '%s');", 
      $_SESSION['loginToken'],
      mysql_real_escape_string($username),
      $datetime);
   $queryData = mysql_query($sqlQuery, $sqldb);
   if (!$queryData) die ('Could not insert token into tokentable on '.
                           'MySQL server because:  ' . mysql_error());
   mysql_close($sqldb);

   $doc->getElementsByTagName("password")->item(0)->nodeValue = '';
   $doc->GetElementsByTagName("errorMessage")->item(0)->nodeValue = 
                      sprintf('%s Logged In',$_SESSION['username']);
   $doc->getElementsByTagName('loginLogout')->item(0)->nodeValue = 
                                                      "Logout";
   $doc->GetElementsByTagName("loginToken")->item(0)->nodeValue = 
                                          $_SESSION['loginToken'];
   $doc->getElementsByTagName('deptId')->item(0)->nodeValue = 
                                          $_SESSION['at_deptId'];
   $doc->GetElementsByTagName('login')->item(0)->nodeValue=0;

   echo $doc->saveXML();
   exit;
}
?>

Điều này thực sự khá đơn giản, tất cả thao tác được thực hiện trong một bước và cùng một lúc. Nếu người sử dụng đăng xuất, nó sẽ xóa hết phiên và thực thể, và yêu cầu người sử dụng đăng nhập lại. (Trường hợp lý tưởng là biểu mẫu đăng nhập sẽ xuất hiện sau đó, nhưng một lỗi trong thực thi hiện tại ngăn cản điều này, nên ở đây chúng tôi yêu cầu người sử dụng nạp lại.)

Tiếp theo, kiểm tra xem liệu người sử dụng đã đăng nhập chưa (có thể từ tương tác với một biểu mẫu khác), và nếu đăng nhập rồi, hãy thêm thông tin thích hợp vào thể hiện và gửi nó trở lại biểu mẫu.

Nếu người sử dụng chưa đã đăng nhập, kiểm tra tên đăng nhập và mật khẩu -- sẽ trả về dữ liệu không có thông tin nếu họ không hiện hữu -- và sau đó kết nối với cơ sở dữ liệu và kiểm tra thẩm định quyền của họ. Nếu thông tin của họ không đúng, nó gửi một thông điệp báo lỗi trở lại biểu biểu mẫu. Nếu thông tin là đúng, nó trích thông tin như là ID phòng ban tương ứng và hiệu chỉnh phiên. Tương tự, nó tạo mới một bản ghi inToken và hiệu chỉnh phiên và cơ sở dữ liệu. Cuối cùng, nó sinh ra thể hiện, thiết lập yêu cầu đăng xuất thay vì đăng nhập, và gửi nó trở lại biểu mẫu.

Nạp các tài sản (biểu mẫu)

Bây giờ, người sử dụng đã đăng nhập, tiếp theo là nạp các tài sản (xem Ví dụ 21).

Ví dụ 21. Nạp các tài sản
...
                            replace="instance" 
                            instance="atuii"
                            ref="instance('atuii')" />

         <xforms:submission id="load_assets"
                            action="get_assets.php" 
                            method="post"
                            replace="instance" 
                            instance="queryData"
                            ref="instance('atuii')" />

         <xforms:bind nodeset="instance('isol')/queryStartDate"          
            type="xsd:date"/>
         <xforms:bind nodeset="instance('isol')/queryEndDate"            
            type="xsd:date"/>

         <xforms:bind nodeset="instance('atuii')/queryStartDate"          
            calculate="instance('isol')/queryStartDate"/>
         <xforms:bind nodeset="instance('atuii')/queryEndDate"            
            calculate="instance('isol')/queryEndDate"/>

         <xforms:bind nodeset="instance('atuii')/password"
...
      </xforms:model>

      <xforms:action ev:event="xforms-ready">
         <xforms:setvalue ref="instance('isol')/queryStartDate" 
               value="substring(now(),1,10)"/>
         <xforms:setvalue ref="instance('isol')/queryEndDate" 
               value="substring(now(),1,10)"/>
         <xforms:dispatch name="xforms-submit" target="login_logout"/>
      </xforms:action>
   </head>
  
   <body>
      <hr/>

      <xforms:input ref="instance('isol')/queryStartDate">
          <xforms:label>Start Date:  </xforms:label>
      </xforms:input>
      <xforms:input ref="instance('isol')/queryEndDate">
          <xforms:label>End Date:  </xforms:label>
      </xforms:input>
      <xforms:submit submission="load_assets" 
                     ref="instance('atuii')/loadAssets">
          <xforms:label>Refresh/Load Assets</xforms:label>
      </xforms:submit>

      <xforms:input ref="instance('atuii')/username">
...

Như trước đây, bạn đang sử dụng các giá trị được hạ xuống kiểu dữ liệu, nên một công cụ lịch biểu xuất hiện. Trong trường hợp này, bạn sử dụng một thể hiện đơn lẻ và thiết lập những giá trị của nó khi biểu mẫu nạp vào. Sau đó, bạn có thể đưa các giá trị đó vào trong các nút "trực tiếp" sử dụng thuộc tính calculate.

Cuối cùng, thêm nút Refresh/Load Assets, để gọi đệ trình load_assets. Đệ trình sẽ tham chiếu tới tập lệnh get_assets.php mà bạn đã xây dựng ở phần trước.

Hiển thị các tài sản

Bởi vì chúng ta muốn người sử dụng có thể dễ dàng lựa chọn một tài sản để nghiên cứu sâu hơn bằng cách hiển thị mỗi tài sản như một nút bấm (xem Ví dụ 22).

Ví dụ 22. Hiển thị các tài sản như những nút bấm
...
      <xforms:output ref="instance('atuii')/welcome"/>
      <hr />
            <xforms:repeat id="assetSelect" incremental="true" 
                        nodeset="instance('queryData')/assets/asset">
               <table><tr><td>
                  <xforms:trigger>
                     <xforms:label ref="description"/>
                  </xforms:trigger>
               </td></tr></table>
            </xforms:repeat>
   </body>
</html>

Kết quả như trong Hình 6.

Hình 6. Các tài sản như những nút bấm
Các tài sản như những nút bấm

Hiển thị thông tin tài sản

Khi người sử dụng bấm vào một trong các nút bấm, bạn sẽ cho hiển thị thông tin tài sản (xem Ví dụ 23).

Ví dụ 23. Hiển thị thông tin tài sản
...
                            instance="queryData"
                            ref="instance('atuii')" />

         <xforms:bind nodeset="instance('queryData')//vendor/brief"          
            calculate="concat(if(../company = '', 
                                 concat(../lastName,', ', 
                                        ../firstName),
                                 ../company),';
                              ',../street,';
                              ',../city, ', 
                              ', ../state, '  ', ../zip) "/>

         <xforms:bind nodeset="instance('isol')/queryStartDate"          
            type="xsd:date"/>
...
            <xforms:repeat id="assetSelect" incremental="true" 
                        nodeset="instance('queryData')/assets/asset">
               <table><tr><td>
                  <xforms:trigger>
                     <xforms:label ref="description"/>
                     <xforms:toggle ev:event="DOMActivate" 
                                    case="browse_issues"/>
                  </xforms:trigger>
               </td></tr></table>
            </xforms:repeat>

            <hr/>

            <xforms:switch>
               <xforms:case id="blank" selected="true()"/>
               <xforms:case id="browse_issues">
                  <table border="1" width="100%">
                     <tr>
                        <th width="5%" >Id</th>
                        <th width="20%" >Description</th>
                        <th width="15%" >Purchase Date</th>
                        <th width="10%" >Status</th>
                        <th width="50%" >Vendor</th>
                     </tr>
                     <tr>
                        <td><xforms:output value=
   "instance('queryData')/assets/asset[index('assetSelect')]/assetId"
                            /></td>
                        <td><xforms:output value=
"instance('queryData')/assets/asset[index('assetSelect')]/description"
                            /></td>
                        <td><xforms:output value=
"instance('queryData')/assets/asset[index('assetSelect')]/purchaseDate
"                           /></td>
                        <td><xforms:output value="
                if (instance('queryData')/assets/asset[
                            index('assetSelect')]/status='retired',         
                   concat('Retired ',
instance('queryData')/assets/asset[index('assetSelect')]/retireDate),
                   'Active')"/></td>
                        <td><xforms:output value=
            "instance('queryData')/vendors/vendor[
     acctId = instance('queryData')/assets/asset[index('assetSelect')
                                                 ]/vendorId]/brief"/>
                        </td>
                     </tr>
                  </table>

               </xforms:case>
            </xforms:switch>

   </body>
</html>

Chú ý: Do các giới hạn của hiển thị Web, chúng ta phải ngắt một số XML; nên bạn phải đảm bảo ghép nó lại cùng nhau trên biểu riêng của bạn, như vậy nó sẽ làm việc.

Ngày được đóng trong một câu lệnh chuyển/trường hợp để cấu trúc nhảy các năm khi thích hợp. Chuyển chế độ trong nút bấm kích hoạt đảm bảo nó được hiện rõ. Bản thân dữ liệu tương đối dễ hiểu. Phần thú vị ở đây là thông tin nhà cung cấp, nó không được biểu đạt từ thông tin tài sản, thay vào đó nó được biểu đạt từ phần nhà cung cấp của thể hiện dựa trên vendorId, như bạn có thể thấy trong Hình 7.

Hình 7. Thông tin tài sản
Thông tin tài sản

Hiển thị thông tin vấn đề phát sinh

Mỗi tài sản và không có hay có nhiều vấn đề phát sinh sẽ được hiển thị (xem Ví dụ 24).

Ví dụ 24. Hiển thị các vấn đề phát sinh
...
     acctId = instance('queryData')/assets/asset[index('assetSelect')
                                                 ]/vendorId]/brief"/>
                        </td>
                     </tr>
                     <tr>
                        <td colspan="5">
                           <table width="100%">
                              <tr>
                                 <th width="40%">Issue Reason</th>
                                 <th width="10%">
                                      Requested Action 
                                 </th>
                                 <th width="10%">
                                      Issue Request Date 
                                 </th>
                                 <th width="10%">
                                      Current Issue Status
                                 </th>
                                 <th width="30%">Issue Response</th>
                              </tr>
                           </table>
                        </td>
                     </tr>
                     <tr>
                        <td colspan="5">
                        <xforms:repeat id="issuesRpt" nodeset=
    "instance('queryData')/assets/asset[index('assetSelect')]/issue">
                           <table width="100%">
                              <tr>
                                 <td width="40%" align="left">
                                     <xforms:output ref="reason"/>
                                 </td>
                                 <td width="10%" align="left">
                                     <xforms:output ref="action"/> 
                                 </td>
                                 <td width="10%" align="left">
                                     <xforms:output ref="date"/> 
                                 </td>
                                 <td width="10%" align="left">
                                     <xforms:output ref="status"/> 
                                 </td>
                                 <td width="30%" align="left">
                                     <xforms:output ref="response"/> 
                                 </td>
                              </tr>
                           </table>
                        </xforms:repeat> 
                        </td>
                     </tr>
                  </table>

               </xforms:case>
            </xforms:switch>

   </body>
</html>

Kết quả giống như Hình 8.

Hình 8. Hiển thị các vấn đề phát sinh
Hiển thị các vấn đề phát sinh

Biểu mẫu vấn đề mới phát sinh

Tất nhiên, người sử dụng cần thêm những vấn đề mới phát sinh, nên thêm trước khi cho phép nó (xem Ví dụ 25).

Ví dụ 25. Biểu mẫu vấn đề mới phát sinh
...
                        </xforms:repeat> 
                        </td>
                     </tr>
                  </table>
                  <xforms:textarea 
                            ref="instance('atuii')/issueReason">
                     <xforms:label>
                          Description Of Problem: 
                     </xforms:label >
                  </xforms:textarea>

                  <xforms:select1 ref="instance('atuii')/issueAction">
                     <xforms:itemset 
                        nodeset="instance('atuii')//issueActionOpts">
                        <xforms:label ref="@txt"/>
                        <xforms:value ref="@txt"/>
                     </xforms:itemset>
                  </xforms:select1>

               </xforms:case>
            </xforms:switch>

   </body>
</html>

Ở đây bạn đang xây dựng một danh sách lựa chọn sử dụng các giá trị issueActionOpts trong thể hiện atuii. Kết quả giống như Hình 9.

Hình 9. Biểu mẫu thêm vấn đề phát sinh
Biểu mẫu thêm vấn đề phát sinh

Bắt đầu đệ trình vấn đề phát sinh

Đệ trình biểu mẫu thực chất là vấn để của việc gọi tập lệnh PHP (xem Ví dụ 26).

Ví dụ 26. Đệ trình biểu mẫu
...
                            instance="atuii"
                            ref="instance('atuii')" />

         <xforms:submission id="submit_issue"
                            action="submit_issue.php" 
                            method="post"
                            ref="instance('atuii')" />

         <xforms:submission id="load_assets"
                            action="get_assets.php" 
...
                        <xforms:value ref="@txt"/>
                     </xforms:itemset>
                  </xforms:select1>

                  <xforms:trigger ref="instance('atuii')/submitIssue">
                     <xforms:label>Submit</xforms:label>
                     <xforms:action ev:event="DOMActivate">
                        <xforms:setvalue   
                                  ref="instance('atuii')/issueDate" 
                                  value="substring(now(),1,10)"/>
                        <xforms:setvalue 
                                  ref="instance('atuii')/issueStatus" 
                                  value="'open'"/>
                        <xforms:setvalue 
                                  ref="instance('atuii')/issueAssetId" 
                                  value=
    "instance('queryData')/assets/asset[index('assetSelect')]/assetId"
                        />
                        <xforms:dispatch name="xforms-submit" 
                                         target="submit_issue"/>
                     </xforms:action>
                  </xforms:trigger>

               </xforms:case>
            </xforms:switch>

   </body>
</html>

Khi người sử dụng nhấn nút Submit, đầu tiên thiết lập cơ quan mặc định, như là issueDate, issueStatus, và assetId. Sau đó, nó gửi đi đệ trình, được gọi submit_issue.php. Tập lệnh dễ dàng trích thông tin từ thể hiện và đưa nó vào bảng assetissues. (Xem mã trình nguồn dành cho tệp này.)

Hoàn thành đệ trình

Khi dữ liệu được đệ trình xong, bạn cần làm sạch biểu mẫu (xem Ví dụ 27).

Ví dụ 27. Làm sạch biểu mẫu
...
                        <xforms:dispatch name="xforms-submit" 
                                         target="submit_issue"/>
                        <xforms:insert nodeset=
      "instance('queryData')/assets/asset[index('assetSelect')]/issue" 
                                       at="1" 
                                       position="before"/>

                        <xforms:setvalue ref=
"
instance('queryData')/assets/asset[index('assetSelect')]/issue/status
"                              value="instance('atuii')/issueStatus"/>
                        <xforms:setvalue ref=
"
instance('queryData')/assets/asset[index('assetSelect')]/issue/reason
"
                               value="instance('atuii')/issueReason"/>
                        <xforms:setvalue ref=
"
instance('queryData')/assets/asset[index('assetSelect')]/issue/action
"
                               value="instance('atuii')/issueAction"/>
                        <xforms:setvalue ref=
"
instance('queryData')/assets/asset[index('assetSelect')]/issue/date
"
                                value="substring(now(),1,10)"/>
                        <xforms:setvalue 
                                ref="instance('atuii')/issueReason" 
                                value=""/>
                        <xforms:setvalue 
                                ref="instance('atuii')/action" 
                                value=""/>
                     </xforms:action>
                  </xforms:trigger>

               </xforms:case>
            </xforms:switch>

   </body>
</html>

Đây cơ bản là một quá trình của việc di chuyển dữ liệu từ biểu mẫu vào trong thể hiện dữ liệu trực tiếp, queryData, và sau đó làm sạch biểu mẫu.


Người sử dụng cung ứng

Bây giờ, bạn có một biểu mẫu quản lí tài sản được phục vụ hoàn hảo, cho phép những người sử dụng thêm các vấn đề phát sinh vào các tài sản đang tồn tại. Nhưng cần có một số người phải giải quyết vấn đề phát sinh đó, và đó là trách nhiệm của phòng ban cung ứng. Những người sử dụng thuộc phòng ban cung ứng (trong trường hợp này, phòng ban số 123), nên có thêm khả năng để yêu cầu "xem vấn đề phát sinh," và liệt kê tất cả các vấn đề phát sinh để cho phép họ thêm các phản hồi.

Kiểm tra những người sử dụng cung ứng

Bước đầu tiên là kiểm tra xem liệu người sử dụng có thuộc phòng ban cung ứng hay không, và nếu thuộc, thì cung cấp cho người sử dụng một nút bấm (xem Ví dụ 28).

Ví dụ 28. Kiểm tra những người sử dụng cung ứng
...
            calculate="concat('Welcome ',
                              instance('atuii')/username)"/>

         <xforms:bind nodeset="instance('atuii')/issueView"            
            relevant="instance('atuii')/deptId = '123'"/>

      </xforms:model>
...
      <xforms:output ref="instance('atuii')/welcome"/>
      <hr />

      <xforms:switch>

         <xforms:case id="standard_view" selected="true()">

            <xforms:trigger ref="instance('atuii')/issueView">
               <xforms:label>Issue View</xforms:label>
               <xforms:action ev:event="DOMActivate">
                  <xforms:setvalue ref="instance('atuii')/issueView" 
                                   value="1"/>
                  <xforms:toggle case="issue_view"/>
               </xforms:action>
            </xforms:trigger>

            <br/>
            <hr/>

            <xforms:repeat id="assetSelect" incremental="true" 
                        nodeset="instance('queryData')/assets/asset">
...

               </xforms:case>
            </xforms:switch>

         </xforms:case>
         <xforms:case id="issue_view">

            <xforms:trigger ref="instance('atuii')/issueView">
               <xforms:label>Asset View</xforms:label>
               <xforms:action ev:event="DOMActivate">
                  <xforms:setvalue ref="instance('atuii')/issueView" 
                                   value="0"/>
                  <xforms:toggle case="standard_view"/>
               </xforms:action>
            </xforms:trigger>

         </xforms:case>
      </xforms:switch>

   </body>
</html>

Chú ý rằng phần tử issueNew chỉ liên quan với những người sử dụng trong phòng ban 123. Chỉ những người sử dụng này mới nên có quyền nhìn thấy nút bấm Issue View. (Chú ý: Những người sử dụng đang báo cáo rằng nút bấm này không xuất hiện ngay cả khi họ thuộc phòng ban tương ứng. Điều này xuất hiện như là một lỗi trong thực thi Firefox XForms xảy ra sau các đệ trình.)

Mặc dù vậy, bây giờ bạn có một kịch bản lồng nhau chuyển đổi/trường hợp. Để bắt đầu, cả hai trường hợp standard_view và blank cases cần được lựa chọn. Khi người sử dụng nhấn nút bấm tài sản, nó kích hoạt trường hợp browse_issues dành cho chuyển đổi/trường hợp nội bộ. Điều này không có tác dụng đối với chuyển đổi/trường hợp bên ngoài. Bạn có thể quản lí chuyển đổi/trường hợp đó một cách độc lập bằng việc sử dụng các nút bấm Issued View và Asset View, nó chỉ ảnh hưởng tới các trường hợp mà chúng có liên quan.

Hiển thị các vấn đề phát sinh

Hiển thị các vấn đề phát sinh đang tồn tại rất dễ dàng (xem Ví dụ 29).

Ví dụ 29. Hiển thị các vấn đề phát sinh
...
            </xforms:trigger>

            <br/>
            <hr/>

            <table width="100%">
               <tr>
                  <th width="5%" >Asset ID</th>
                  <th width="5%">Concerned Party </th>
                  <th width="75%">Issue Reason</th>
                  <th width="5%">Requested Action </th>
                  <th width="5%">Issue Request Date </th>
                  <th width="5%">Current Issue Status</th>
               </tr>
            </table>

            <xforms:repeat id="issueRpt" 
                nodeset="instance('queryData')//issue[reason != '']">
            <table width="100%">
               <tr>
                  <td align="left" width="5%" >
                      <xforms:output value="../assetId"/>
                  </td>
                  <td align="left" width="5%"> 
                      <xforms:output value="acctId"/> 
                  </td>
                  <td align="left" width="75%">
                      <xforms:output value="reason"/> 
                  </td>
                  <td align="left" width="5%"> 
                      <xforms:output value="action"/> 
                  </td>
                  <td align="left" width="5%"> 
                      <xforms:output value="date"/> 
                  </td>
                  <td align="left" width="5%"> 
                      <xforms:output value="status"/> 
                  </td>
               </tr>
            </table>

            </xforms:repeat>

         </xforms:case>
      </xforms:switch>

   </body>
</html>

Bạn có thể thấy kết quả như trong Hình 10.

Hình 10. Kết quả
Kết quả

Hộp lựa chọn một trong cùng một thời điểm

Những người sử dụng cần một cách để lựa chọn một vấn đề phát sinh cụ thể và hộp lựa chọn dường như là một ý tưởng hay, nhưng nó có một khó khăn đặc biệt (xem Ví dụ 30).

Ví dụ 30. Hộp lựa chọn
...
            <xforms:repeat id="issueRpt" 
               nodeset="instance('queryData')//issue[reason !='']">
            <table width="100%">
               <tr>
                  <td align="left" width="1%" >
                     <xforms:select incremental="true()" 
                                    appearance="full" ref="@selected"> 

                        <xforms:action ev:event="DOMActivate">
                           <xforms:setvalue 
ref="instance('queryData')//issue[@selected=1]/@selected" value="0" />
                           <xforms:setvalue ref="." value="1" />
                        </xforms:action>

                        <xforms:item>
                           <xforms:label value=""/> 
                           <xforms:value>1</xforms:value>
                        </xforms:item>

                     </xforms:select>

                  </td>
                  <td align="left" width="5%" >
                      <xforms:output value="../assetId"/>
                  </td>
...

Khi bạn muốn người sử dụng có thể chọn chỉ một tùy chọn, thì điều khiển select1 dường như là sự lựa chọn hoàn hảo, nhưng trong trường hợp này bạn gặp một vấn đề. Mỗi phép lặp của điều khiển này được tạo ra bởi một thi hành riêng rẽ thông qua phần tử repeat, nên mỗi điều khiển là một mục độc lập. Thay vì có một số giá trị của một điều khiển select1 đơn lẻ, bạn cần có một số điều khiển select1, mỗi một trong số chúng có khả năng được lựa chọn đồng thời.

Để giải quyết vấn đề này, bạn có thể tạo ra một hộp lựa chọn và xóa các mục được lựa chọn trước đó bằng cách thủ công trước khi chọn mục hiện tại. Cách này, khi những người sử dụng chọn hộp lựa chọn thứ hai, hộp lựa chọn thứ nhất được làm sạch và chỉ một hộp lựa chọn được chọn tại một thời điểm. Kết quả như Hình 11.

Hình 11. Hộp lựa chọn
Hộp lựa chọn

Biểu mẫu vấn đề phát sinh

Cuối cùng, những người sử dụng cần một cách để giải quyết vấn đề phát sinh. Bạn có thể thực hiện điều đó bằng cách cung cấp cho người sử dụng một biểu mẫu (xem Ví dụ 31).

Ví dụ 31. Biểu mẫu vấn đề phát sinh
...
                            instance="atuii"
                            ref="instance('atuii')" />

         <xforms:submission id="update_issue"
                            action="update_issue.php" 
                            method="post"
                            ref="instance('atuii')" />

         <xforms:submission id="submit_issue"
                            action="submit_issue.php" 
...
         <xforms:bind nodeset="instance('atuii')/issueView"            
            relevant="instance('atuii')/deptId = '123'"/>

         <xforms:bind 
               nodeset="instance('atuii')/issueRepairInstructions"
            calculate=
              "instance('queryData')//issue[@selected='1']/reason"/> 

         <xforms:bind nodeset="instance('atuii')/password"
            relevant="number(instance('atuii')/login)=1"/>
...
                  <td align="left" width="5%"> 
                      <xforms:output value="status"/> 
                  </td>
               </tr>
            </table>

            </xforms:repeat>

            <xforms:select1 ref="instance('atuii')/issueStatus"> 
               <xforms:label>New Status:  </xforms:label>
               <xforms:itemset nodeset="instance('atuii')/statusOpts">
                  <xforms:label ref="@txt"/>
                  <xforms:value ref="@txt"/>
               </xforms:itemset>
            </xforms:select1>

            <br/>
            <xforms:textarea ref="instance('atuii')/issueResponse"> 
               <xforms:label >Response:  </xforms:label>
            </xforms:textarea>
            <br/>

            <xforms:output 
                      ref="instance('atuii')/issueRepairInstructions"> 
               <xforms:label >Issue Reason:  </xforms:label>
            </xforms:output>

            <br/>

            <xforms:trigger ref="instance('atuii')/updateIssue">
              <xforms:label>Update Issue</xforms:label>
              <xforms:action ev:event="DOMActivate">
                <xforms:setvalue ref="instance('atuii')/issueAssetId" 
                                 value=
           "instance('queryData')//issue[@selected='1']/../assetId"/>
                <xforms:dispatch name="xforms-submit"  
                                 target="update_issue"/>
              </xforms:action>
            </xforms:trigger>

         </xforms:case>
      </xforms:switch>

   </body>
</html>

Biểu mẫu rất đơn giản, cung cấp các trạng thái tùy chọn, khu vực văn bản dành cho một phản hồi, và một lặp lại của lý do, được sản sinh bằng việc sử dụng một phần tử đóng kết. Khi người sử dụng nhấn vào nút bấm Update Issue, nó sẽ được kích hoạt và biểu mẫu sẽ đệ trình dữ liệu tới tập lệnh update_issue.php. Tập lệnh đó đơn giản chỉ cần lấy dữ liệu đó và đưa nó vào trong cơ sở dữ liệu. (Xem tải xuống mã trình dành cho tệp update_issue.php.)

Kết quả giống như Hình 12.

Hình 12. Biểu mẫu cuối cùng
Biểu mẫu cuối cùng

Tóm tắt

Những hướng dẫn này được thiết kế để giúp bạn hiểu một kỹ năng cụ thể theo một cách riêng biệt, từ đó có thể tạo ra những ứng dụng tương đối đơn giản. Mặc dù vậy, trong trường hợp này, mục đích là để giúp bạn biết được một số vấn để phát sinh mà bạn có thể gặp trong việc thiết kế một ứng dụng thực tế như là một ứng dụng kế toán.

Trong hướng dẫn này bạn đã nghiên cứu về các vấn đề phát sinh như là khi làm việc với nhiều bảng cơ sở dữ liệu và dịch chúng sang XML, cũng như là thực thi các câu lệnh chuyển đổi/trường hợp, và tạo ra một biểu mẫu chi tiết chủ.

Trong Phần 5, bạn sẽ tiếp tục tìm hiểu về các thanh toán và các trách nhiệm pháp lý dành cho công ty và cách phân tích tài chính khác.


Tải về

Mô tảTênKích thước
Mã nguồn phần 4xforms4code.zip11KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

  • XForms Recommendation được bảo trì bởi W3C.
  • Lấy MozzIE, một điều khiển nguồn mở cho phép bạn hoàn trả XForms trong Internet Explorer.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=407872
ArticleTitle=Sử dụng XForms để tạo công cụ kế toán, Phần 4: Quản lí và báo cáo tài sản
publish-date=07102009