2012-01-12 29 views
6

Tôi đã xây dựng một dịch vụ web đầu tiên trên Zend Framework (1.10), và bây giờ tôi đang tìm cách để tái cấu trúc một số logic trong Bộ điều khiển Hành động để nó dễ dàng hơn cho tôi và những người còn lại trong nhóm của tôi để mở rộng và duy trì dịch vụ.Zend Action Controller - chiến lược tái cấu trúc

Tôi có thể thấy nơi có cơ hội để tái cấu trúc, nhưng tôi không rõ ràng về các chiến lược tốt nhất về cách thức. Các tài liệu và hướng dẫn tốt nhất về các bộ điều khiển chỉ nói về các ứng dụng quy mô nhỏ, và không thực sự thảo luận cách trừu tượng mã lặp đi lặp lại nhiều hơn mà leo lên các quy mô lớn hơn.

Cấu trúc cơ bản cho các bộ điều khiển hành động của chúng tôi là:

  1. Extract nhắn XML ra khỏi cơ thể theo yêu cầu - Điều này bao gồm xác nhận chống lại một lược đồ RelaxNG hành động cụ thể
  2. Chuẩn bị phản ứng XML
  3. Validate dữ liệu trong thông báo yêu cầu (dữ liệu không hợp lệ ném ngoại lệ - một thông báo được thêm vào phản hồi được gửi ngay lập tức)
  4. Thực hiện hành động cơ sở dữ liệu (chọn/chèn/cập nhật/xóa)
  5. Return thành công hay thất bại của hành động, với thông tin cần thiết

Một ví dụ đơn giản là hành động này mà trả về một danh sách các nhà cung cấp dựa trên một tập hợp linh hoạt các tiêu chí:

class Api_VendorController extends Lib_Controller_Action 
{ 
    public function getDetailsAction() 
    { 
     try { 
      $request = new Lib_XML_Request('1.0'); 
      $request->load($this->getRequest()->getRawBody(), dirname(__FILE__) . '/../resources/xml/relaxng/vendor/getDetails.xml'); 
     } catch (Lib_XML_Request_Exception $e) { 
      // Log exception, if logger available 
      if ($log = $this->getLog()) { 
       $log->warn('API/Vendor/getDetails: Error validating incoming request message', $e); 
      } 

      // Elevate as general error 
      throw new Zend_Controller_Action_Exception($e->getMessage(), 400); 
     } 

     $response = new Lib_XML_Response('API/vendor/getDetails'); 

     try { 
      $criteria = array(); 
      $fields = $request->getElementsByTagName('field'); 
      for ($i = 0; $i < $fields->length; $i++) { 
       $name = trim($fields->item($i)->attributes->getNamedItem('name')->nodeValue); 
       if (!isset($criteria[$name])) { 
        $criteria[$name] = array(); 
       } 
       $criteria[$name][] = trim($fields->item($i)->childNodes->item(0)->nodeValue); 
      } 

      $vendors = $this->_mappers['vendor']->find($criteria); 
      if (count($vendors) < 1) { 
       throw new Api_VendorController_Exception('Could not find any vendors matching your criteria'); 
      } 

      $response->append('success'); 
      foreach ($vendors as $vendor) { 
       $v = $vendor->toArray(); 
       $response->append('vendor', $v); 
      } 

     } catch (Api_VendorController_Exception $e) { 
      // Send failure message 
      $error = $response->append('error'); 
      $response->appendChild($error, 'message', $e->getMessage()); 

      // Log exception, if logger available 
      if ($log = $this->getLog()) { 
       $log->warn('API/Account/GetDetails: ' . $e->getMessage(), $e); 
      } 
     } 

     echo $response->save(); 
    } 
} 

Vì vậy, - biết nơi những đặc tính chung trong các bộ điều khiển của tôi, chiến lược tốt nhất cho việc tái cấu trúc là gì trong khi vẫn giữ nó giống như Zend và cũng có thể kiểm thử với PHPUnit?

Tôi đã suy nghĩ về việc trừu tượng hóa logic điều khiển thành lớp cha (Lib_Controller_Action), nhưng điều này làm cho việc kiểm thử đơn vị phức tạp hơn theo cách mà dường như tôi sai.

+2

Có thể đẩy tính phổ biến vào các lớp dịch vụ/kho lưu trữ? Các lớp như vậy sẽ có thể kiểm tra được, có thể sử dụng được trên các bộ điều khiển và có thể làm cho mã điều khiển nhỏ gọn hơn. –

+3

Một cách tiếp cận khác là thu thập tính phổ biến thành người trợ giúp hành động. –

Trả lời

1

Hai ý tưởng (chỉ cần tạo ra một câu trả lời từ các ý kiến ​​ở trên):

  1. Đẩy tương đồng xuống vào hoạt động lớp/kho? Các lớp như vậy sẽ có thể kiểm tra được, có thể sử dụng được trên các bộ điều khiển và có thể làm cho mã điều khiển nhỏ gọn hơn.

  2. Thu thập sự phổ biến thành người trợ giúp hành động.

+0

Bạn có liên kết đến bất kỳ ví dụ nào không? Nếu chúng bao gồm mã thử nghiệm, điều đó sẽ tuyệt vời - Zend và TTD/thử nghiệm tự động vẫn còn khá mới đối với tôi. – HorusKol

+1

Vâng, đây là phần mà tôi vẫy tay điên cuồng để đánh lạc hướng vì thiếu chi tiết cụ thể, chỉ tới tìm kiếm của Google cho PHPUnit/TDD. Một số tài liệu tham khảo cụ thể: (1) Tôi tìm thấy các bài kiểm tra đơn vị trong ZF chính nó là khá instructive. (2) Tôi thích [mã nguồn của Dasprids blog] (http://site.svn.dasprids.de/trunk/) cho các ví dụ về việc sử dụng các dịch vụ cho mã điều khiển lean-up. (3) Các kho lưu trữ Doctrine2 là các ví dụ tốt về việc đẩy truy cập dữ liệu vào một lớp kho lưu trữ. (4) [Bài viết này] (http://devzone.zend.com/1218/action-helpers-in-zend-framework/) từ MWOP là một phần giới thiệu tốt cho những người giúp đỡ hành động. –

+0

Cảm ơn thời gian đó để tiếp tục với một số đọc – HorusKol

1

Vì bạn phải thực hiện bước này mỗi khi một yêu cầu được thực hiện, bạn có thể lưu trữ mà tiếp nhận, phân tích và xác nhận yêu cầu nhận được trong một Zend_Controller_Plugin mà sẽ được chạy mỗi PreDispatch của tất cả các bộ điều khiển.(Chỉ có thể thực hiện được nếu yêu cầu XML của bạn được chuẩn hóa) (Nếu bạn sử dụng XMLRPC, REST hoặc một số cách tiêu chuẩn để xây dựng yêu cầu cho dịch vụ của mình, bạn có thể xem xét các mô-đun được xây dựng trong ZF)

Xác thực dữ liệu (hành động cụ thể) có thể được thực hiện trong một phương pháp điều khiển (sau đó sẽ được gọi bởi (các) hành động cần) (nếu các tham số của bạn là cụ thể cho một hoặc nhiều hành động của bộ điều khiển đó) hoặc bạn có thể thực hiện nó với các mẫu FactoryBuilder trong trường hợp bạn có nhiều thông số được chia sẻ giữa các bộ điều khiển/hành động

// call to the factory 
$filteredRequest = My_Param_Factory::factory($controller, $action, $paramsArray) // call the right builder based on the action/controller combination 

// the actual Factory 

class My_Param_Factory 
{ 
    public static function factory($controller, $action, $params) 
    { 
     $builderClass = "My_Param_Builder_" . ucfirst($controller) . '_' . ucfirst($action); 

     $builder = new $builderClass($params); 

     return $builder->build(); 
    } 
} 

Trình tạo sau đó sẽ gọi thông số cụ thể s lớp xác nhận dựa trên những nhu cầu xây dựng cụ thể (mà sẽ cải thiện lại khả năng sử dụng)

Trong điều khiển của bạn, nếu mỗi params cần có giá trị, bạn vượt qua quá trình xử lý với phương pháp đúng của mô hình đúng

$userModel->getUserInfo($id) // for example 

Mà sẽ loại bỏ tất cả các hoạt động dataprocessing từ các bộ điều khiển mà sẽ chỉ phải kiểm tra nếu đầu vào là ok và sau đó gửi cho phù hợp.

Store kết quả (lỗi hoặc succes) trong một biến mà sẽ được gửi đến các quan điểm

Process dữ liệu (định dạng và thoát (thay thế < với & lt; nếu chúng được bao gồm trong phản ứng cho ví dụ)), gửi đến trình trợ giúp xem để xây dựng XML rồi in (echo) dữ liệu trong chế độ xem (đây sẽ là phản hồi cho người dùng của bạn).

public function getDetailsAction() 
{ 
    if ($areRequestParamsValid === true) { 
     // process data 
    } else { 
     // Build specific error message (or call action helper or controller method if error is general) 
    } 

    $this->view->data = $result 
} 
Các vấn đề liên quan