2010-07-29 52 views
4

在MVC模型視圖控制器設計中,實現模型單獨工作幷包含buisness邏輯,從數據庫中提取信息。MySQL + PHP:實現一個好的模型

我在實現一個好的模型的設計上掙扎如此之多。我知道需要從數據庫中取出哪些信息,我只是不知道實現它的最佳方式。我認爲模型作爲程序API,我自己用像

  1. 這樣的問題超載自己如果我需要排序字段呢?
  2. 如果我需要通過某個用戶名/ ID進行選擇,該怎麼辦?
  3. 如果我需要按特定字段分組怎麼辦?
  4. 如果我正在選擇,只是在調用函數可能需要拉下的任何信息時,性能會受到多大的影響?

我的API /型號變得極其臃腫,具有獨立的功能,查詢(只是slighlty調諧/改變)對每個功能

例如

$cart->getShoppingCart() 
$cart->getShoppingCartSortByTitle() 
$cart->getShoppingCartGroupByItemType() 

我感覺這使得模型非常臃腫和非常捆綁,創造了很多重複的代碼。這種模式可能會更好;

一個更好的想法

$cart->getItems('title, price')->order_by('title'); 

哪裏'title, price'是MySQL字段,你可以選擇,明顯受到getItems()功能被驗證。這樣它不僅限於返回某些領域。

  1. 我怎麼能做到這一點?
  2. 這是一個真正的好模型嗎?
  3. 你們有沒有其他的建議?

回答

1

使用對象關係映射(ORM)...

嘗試Doctrine ORM項目。

另一種解決方案是CodeIgniter,它有最好的活動記錄庫。很有幫助。

如果您仍然決定編寫自己的類,然後使用PHP5的method chaining。語法會更漂亮......

0

「更好的主意」絕對是一個更好的主意。你可能會考慮看看如何Django implements this,因爲那是在那裏使用的方法。 Django是用Python編寫的,它使一些事情變得容易一些,但是你也應該能夠在PHP中使用它的概念(只是不太清楚)。總而言之,進行查詢會創建一個查詢對象,其中包含像order_by這樣的方法。應用這些方法將改變查詢的狀態,並且只有在查詢實際執行時才需要生成SQL並在數據庫上執行該查詢。

如果你堅持前者,你可能會考慮使用'神奇的方法',像許多現有的框架一樣使用動態名稱。例如,

getShoppingCart_groupby 
getShoppingCart_orderby 

你將有一個「包羅萬象」與動態參數列表,上面寫着被調用的函數的名稱,並執行它是否有效所需的行爲(和拋出的標準方法如果沒有找到'方法未找到'錯誤)。這與你現在正在做的基本相同,但它會清理代碼並整理你的模型。你將需要PHP5,你正在尋找the __call magic method

Julien在他的回答中提到了代碼點火器 - 編寫好的模型非常困難,所以通常您最好使用現有的框架。 (但它很有趣!)

0

首先,確保你問自己的所有這些「問題」都涉及你的應用程序實際上現在需要的功能。我在設計新項目時遇到的最大問題之一就是投機設計。只添加你需要的東西。爲你添加的內容編寫單元測試。當你到了需要額外功能的地步時,如果需要的話,可以重構爲更好的設計。

如果您確實需要所有的功能,我仍然建議重構方法。實施一些您可以看到的與「膨脹」類似或有助於的功能。完成後,退後一步,看看是否可以重構更優雅的東西,或者是在不同的對象和/或方法之間更均勻地分配責任。然後繼續。各種「模式」和「重構」書籍將在這裏幫助你很多。

0

首先應該考慮的是:

  • 沒有很好的通用模型。每個項目都需要自己的模型。
  • 易於閱讀,可管理的代碼
  • 不重複相同的代碼(或查詢),所以如果您有某個任務的功能,並且您希望以某種方式訂購它,請修改該功能本身,而不要克隆它
  • 使用複雜的數據結構,如數組或對象將數據發送到函數,所以您不必總是修改函數需要的參數
  • 資源使用情況。你希望它越多,通用解決方案就會使用更多的資源。

如果我正在選擇,只是在調用函數時可能會影響性能會有多嚴重?可能需要將任何信息拉下來?

這取決於你的網站的負載。大多數時候(如果你不拉大斑點和文本)是可以的,但是當資源稀缺時,你必須指定列。所以你可以節省一些IO時間。


我感覺這使得模型非常臃腫,非常捆綁,創造了大量的重複的代碼。這種模式可能會更好;

也許試試這個:

首先,對於複雜的查詢,我使用這個類我做了很久以前的MySQL。它幫助了很多人。

class sqlAssembler 
{ 
    private $data = array(); 
    var $S = array(); 
    var $F = array(); 
    var $W = array(); 
    var $G = array(); 
    var $H = array(); 
    var $O = array(); 
    var $L = array(); 

    //Clause abbreviations 
    var $clauselist = array 
    (
    'S' => 'SELECT', 
    'F' => 'FROM', 
    'W' => 'WHERE', 
    'G' => 'GROUP BY', 
    'H' => 'HAVING', 
    'O' => 'ORDER BY', 
    'L' => 'LIMIT' 
    ); 

    //Default clause separators 
    var $clausesep = array 
    (
    'S' => ',', 
    'F' => ',', 
    'W' => ' AND ', 
    'G' => ',', 
    'H' => ' AND ', 
    'O' => ',', 
    'L' => '' 
    ); 

    function gen() 
    { 
     $tmp = ''; 

     foreach ($this->clauselist as $area => $clause) 
     { 
      if (count($this->{$area})) 
      { 
       $tmp .= ($clause != 'S' ? ' ' : '') . $clause . ' '; 
       for ($i=0; $i < count($this->{$area}); $i++) 
       { 
        //echo $area = (string)$area; 
        $tmp .= $this->{$area}[$i]; 
       } //for 
      } //if 
     } //foreach 

     return $tmp; 
    } //function 


    function genSection($area, $showsection = 0) 
    { 
     $tmp = ''; 
     if (count($this->{$area})) 
     { 
      for ($i=0; $i < count($this->{$area}); $i++) 
      { 
       $tmp .= $this->{$area}[$i]; 
      } //for 
     } //if 

     return $tmp; 
    } //function 

    function clear() 
    { 
     foreach ($this as $area => $v) 
     { 
      //We only care about uppercase variables... do not declare any else variable with ALL UPPERCASE since it will be purged 
      if (ctype_upper($area)) 
      { 
       if ($area == 'L') 
        $this->$area = ''; 
       else 
        $this->$area = array(); 
      } //if 
     } //foreach 
    } //function 

    public function add($area, $str, $criteria = 1, $sep = '#') 
    { 
     if ($criteria) 
     { 
      if ($sep == '#') 
       $sep = $this->clausesep[$area]; 

      //Postgres' OFFSET should be set like: $str = '25 OFFSET 0' 
      //Not very neat I know, but fuck it 
      if ($area == 'L') 
      { 
       $this->{$area} = array(); 
      } //if 

      //$ref = $this->$area; 
      $this->{$area}[] = (count($this->$area) ? $sep : '').$str; 

      return count($this->$area)-1; 
     } //if 
    } //function 

    public function del($area,$index) 
    { 
     if (isset($this->{$area}[$index])) 
      unset($this->{$area}[$index]); 
     else 
      trigger_error("Index nr. {$index} not found in {$area}!",E_USER_ERROR); 
    } //function 

//-*-* MAGIC CHAIN FUNCTIONS 

    public function S($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function F($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function W($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function G($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function H($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function O($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 

    public function L($str,$criteria = 1,$sep = '#') 
    { 
     $this->add(__FUNCTION__,$str,$criteria,$sep); 
     return $this; 
    } //function 
} //_sql 

也許試試這個:

function getShoppingCart($d) 
{ 
    $xx = new sqlAssembler(); 

    $xx->S('*')-> 
    F('items')-> 
    //Notice, that we specified a criteria... if $d['id_item'] exists it will be joined to the WHERE clause, if not it will be left out 
    W("(id_item > '{$d[id_item]}')",$d['id_item'])-> 
    //Same here 
    O("dt DESC",$d['date']) 
    $sql = echo $xx->gen(); 

    //id_item = 11, date = 2009-11-12 
    //$sql = "SELECT * FROM items WHERE (id_item > '11') ORDER BY dt DESC"; 

    //id_item = null, date = null 
    //$sql = "SELECT * FROM items"; 

    $data = sqlArray($sql); 

    //... handle data 
}