2009-02-10 33 views
2

我在我的控制器中有一個函數,它比我更喜歡的時間長了,我想重構它來調用一些離散函數,使它更容易管理。如何在Codeigniter控制器中更好地組織長功能?如何重構Codeigniter控制器功能太長?

我已經試過:

我知道你可以通過與領先的下劃線(_Myfunc)命名他們創建一個控制器專用的功能,但隨後在該函數的變量超出範圍的調用控制器功能。所以你必須從函數返回所有需要的數據,這是一個麻煩。

這是管理複雜控制器功能的最佳選擇嗎?是否有一種更簡單的方法,其中的變量可能全都是控制器類的全局變量,如標準類成員變量?

對此提出建議?提前致謝!

編輯:有人要求代碼,所以我在下面添加了巨型控制器的代碼。一個改進的機會是將switch語句中的邏輯移到單獨的函數中(刪除,預覽,排序等)。但是我想在此之後決定下一步。將大的驗證設置代碼移動到它自己的函數中真的需要一些權重,但我應該在哪裏移動它?

function categories() { 
    $this->load->library('upload'); 
    $this->load->model('categories_m'); 
    $this->load->model('products_m'); 
    $this->load->model('pages_m'); 
    $this->load->model('backoffice/backofficecategories_m'); 
    $data['body'] = $this->load->view('backoffice/categories/navigation_v', '', TRUE); 
    $data['cat_tree'] = $this->categories_m->getCategoryTree(); 
    $data['page_list'] = $this->pages_m->getPageList(); 
    $data['category_dropdown'] = $this->load->view('backoffice/categories/category_dropdown_v',$data,TRUE); 

    switch ($this->uri->segment(3)) { //display views based on parameter in URL. 
    case 'delete':   
     $categoryTreeID = $this->sitewide_m->checkURLParam($this->uri->segment(4),'CategoryTree'); //if parameter is in URL, show 404 if invalid parameter is passed. Otherwise, set variable known to be safe. 
     if (isset($_POST['delete'])) { 
      $this->backofficecategories_m->deleteCategory($categoryTreeID); 
      $data['body'] .= '<span class="error">Category Deleted.</span>'; 
     } else { 
      $data['cat_details'] = $this->categories_m->getCategoryDetails('',$categoryTreeID); 
      $data['parent_category'] = $this->categories_m->getParentCategory($categoryTreeID); 
      $data['products_to_reassign'] = $this->products_m->getProductsInCategory('',$categoryTreeID); 
      $data['body'] .= $this->load->view('backoffice/categories/delete_v',$data,TRUE); //pull fresh category tree data since tree was just updated. 
     } 
     break; 
    case 'preview': 
     if ($this->uri->segment(4)) $data['categoryTreeID'] = $this->sitewide_m->checkURLParam($this->uri->segment(4),'CategoryTree'); //if parameter is in URL, show 404 if invalid parameter is passed. Otherwise, set variable known to be safe. 
     $data['cat_details'] = $this->categories_m->getCategoryDetails(NULL,$data['categoryTreeID']); //get category ID being edited from the URL and store it. Returns false if category ID isn't found. 
     foreach ($data['cat_details']->result() as $detail) { 
      $data['categoryName'] = $detail->Name; 
      $data['categoryID'] = $detail->ID; 
     } 
     $data['body'] .= $this->load->view('backoffice/categories/preview_v', $data, TRUE); 
     break; 

    ...cases continue... 
    default: 
     $this->load->library('table'); 
     $data['body'] .= $this->load->view('backoffice/categories/categories_v', $data, TRUE); 
     break; 
    } 
    $this->load->view('backoffice/template_v',$data);  
} 
+0

你可以發佈控制器功能供我們看看嗎? – robsymonds 2009-02-10 14:18:45

+1

爲什麼你不讓CI做第三段的路由而不是使用switch語句? – 2009-02-10 15:33:59

+0

這是一個很好的觀點 - 我之前沒有的理由是switch語句之前的代碼適用於switch語句正在檢查的所有操作。如果將switch語句拆分爲單獨的函數,如何才能在交換機可重用之前創建該部分?一個單獨的功能將超出範圍,對吧? – 2009-02-10 16:07:57

回答

4

看着你的代碼,你正在使用一種方法來執行幾個動作。我會讓每個行動都是自己的方法。公共資源可以是類成員並加載到構造函數中。

因此,而不是像一個URL「your_controller /分類/加」你可以改變你的網址爲「category_controller /添加」,併爲每個動作的方法。如果你不想改變你的網址,然後使用路線:

$route['your_controller/categories/(.*)'] = 'your_controller/$1'; 
0

您使用的是哪個版本的PHP? PHP 5有真正的面向對象的支持,這樣你就可以宣佈將通過解釋如此對待私有函數:

private function foo(){ 
... 
} 

如果你想擴展您的類(子類)來訪問該功能類,取代privateprotected.

我從來沒有使用過CodeIgnniter,因此恐怕我無法幫助您處理您的特定問題域。然而,重構一個變得很長的函數是一個非常普遍的問題,並帶有常見的解決方案。馬丁福勒是一個聰明的人,他寫了一些關於這個話題的書籍,這些書很受好評,所以你可以看看你是否可以找到his books之一。也有在線教程讓你開始重構。

+0

謝謝你的回答傑里米。我熟悉一般的重構原則,試圖找出在Codeigniter的約束條件下工作的最佳方法。 – 2009-02-10 14:14:50

5

您使用的是模型嗎?代碼點火器不強制執行此操作,但使用控制器和視圖以外的模型是控制器功能更短的好方法。或者,你可以將一些函數放在你自己的幫助器中,然後導入它。

如果你想爲整個構造函數設置一些默認值,你可以使用類的構造函數。這是這裏概述:

http://codeigniter.com/user_guide/general/controllers.html#constructors

+0

謝謝斯圖爾特。是的,使用模型,但我不在乎Codeigniter對模型的反思。 Codeigniter的文檔基本上說你只能將db查詢放入模型中。我想將我的很多邏輯移到我的模型中,但這似乎違背了model = db的codeigniter思想。同意? – 2009-02-10 14:31:35

2

服務層會有所幫助。

2

如果你想保持你的邏輯在同一個控制器中,你可以通過在函數名前加下劃線來模擬一個私有方法,例如:_myMethod()。就像link所說的那樣,函數名稱前面的下劃線會阻止CI從URL調用它。例如,您可以在類別控制器中創建_delete(),_preview(),_order()等方法。但是,如果您使用相同的邏輯來刪除,預覽,排序等其他內容,也許您應該將這些方法移到模型或幫助程序中。

1

就我個人而言,我認爲你使用單一控制器方法做得太多。我要做的第一件事情之一是將您的CRUD(創建讀取更新刪除)功能作爲單獨的方法分開。例如,您的示例用於處理「類別」,爲什麼不具有單獨的「類別」控制器?

class Categories extends Controller 
{ 
    function __construct() 
    { 
    parent::Controller(); 
    } 

    function index() 
    { 
    //display logic/code here 
    } 

    function edit() 
    { 
    //get the category to update from the post or url for editing 
    //do the editing, etc 
    } 

    function delete() 
    { 
    //delete the category 
    } 

    function add() 
    { 
    //create the new category 
    } 
} 

您的網址將引用類控制器:

http://www.example.com/categories/edit http://www.example.com/categories/delete

我建議是升級到1.7.1笨第二件事情 - 更新form_validation庫使它輕鬆將所有驗證規則移至單獨的配置文件。

1

嘗試查看codeigniter中控制器的_remap()函數。

使用它你可以將常用代碼保存在_remap函數中,然後從_remap中調用任何其他函數來刪除,更新等等(基於uri_segment(3))。

0

您可以將通用函數放入庫中並調用它。