2009-01-15 15 views
15

嗯,我不是一個龐大的框架人,但我一直喜歡我聽到的關於整個MVC運動的內容,所以我想我會嘗試創建一個簡單的應用程序在我的選擇語言(PHP)請批評我在PHP MVC上的第一次嘗試

所以我想問題是:我哪裏出錯了?我知道有很多關於控制器/模型應該如何肥胖的爭論,所以希望我們可以避免這種情況,但是我特別好奇你對我如何適合數據的想法。

另外我買了一個域做一些測試,所以如果你想看到它在行動,你可以去www.omgmvc.com

首先,這裏是我的數據庫模式:

CREATE TABLE `movies` (
    `id` int(11) NOT NULL auto_increment, 
    `movie_name` varchar(255) NOT NULL, 
    `release_date` date NOT NULL, 
    `directors_name` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`) 
); 

INSERT INTO `movies` VALUES (1,'Star Wars', '1977-05-25', 'George Lucas'); 
INSERT INTO `movies` VALUES (2,'The Godfather', '1972-03-24', 'Francis Ford Coppola'); 
INSERT INTO `movies` VALUES (3,'The Dark Knight', '2008-07-18', 'Christopher Nolan'); 

而這裏的文件:

的index.php(控制器)

<?php 

include('datatier.php'); 
include('models/m_movie.php'); 

if (isset($_GET['movie']) && is_numeric($_GET['movie'])) 
{ 
    $movie = new Movie($_GET['movie']); 

    if ($movie->id > 0) 
    { 
     include('views/v_movie.php'); 
    } 
    else 
    { 
     echo 'Movie Not Found'; 
    } 
} 
else 
{ 
    $movies = Movie::get_all(); 

    include('views/v_list.php'); 
} 

?> 

datatier.php(數據層)

<?php 

class DataTier 
{ 
    private $database; 

    function __construct() 
    { 
     $this->connect(); 
    } 

    function __destruct() 
    { 
     $this->disconnect(); 
    } 

    function connect() 
    { 
     $this->database = new PDO('mysql:host=localhost;dbname=dbname','username','password'); 
    } 

    function disconnect() 
    { 
     $this->database = null; 
    } 

    function get_all_from_database($type) 
    { 
     $database = new PDO('mysql:host=localhost;dbname=dbname','username','password'); 

     switch ($type) 
     { 
      case 'movie': 
       $query = 'SELECT id FROM movies'; 
       break; 
     } 

     $movies = array(); 

     foreach ($database->query($query) as $results) 
     { 
      $movies[sizeof($movies)] = new Movie($results['id']); 
     } 

     $database = null; 

     return $movies; 
    } 

    function get_from_database($type,$id) 
    { 
     switch ($type) 
     { 
      case 'movie': 
       $query = 'SELECT movie_name,release_date,directors_name FROM movies WHERE id=?'; 
       break; 
     } 

     $database_call = $this->database->prepare($query); 
     $database_call->execute(array($id)); 

     if ($database_call->rowCount() > 0) 
     { 
      return $database_call->fetch(); 
     } 
     else 
     { 
      return array(); 
     } 
    } 
} 

?> 

模型/ m_movie.php(模型)

<?php 

class Movie extends DataTier 
{ 
    public $id; 
    public $movie_name; 
    public $release_date; 
    public $directors_name; 

    function __construct($id) 
    { 
     parent::connect(); 

     $results = parent::get_from_database('movie',$id); 

     if ($results == array()) 
     { 
      $this->id = 0; 
     } 
     else 
     { 
      $this->id = $id; 
      $this->movie_name = $results['movie_name']; 
      $this->release_date = $results['release_date']; 
      $this->directors_name = $results['directors_name']; 
     } 
    } 

    function __destruct() 
    { 
     parent::disconnect(); 
    } 

    static function get_all() 
    { 
     $results = parent::get_all_from_database('movie'); 

     return $results; 
    } 
} 

?> 

的意見/ v_list.php(圖)

<html> 
    <head> 
     <title>Movie List</title> 
    </head> 
    <body> 
     <table border="1" cellpadding="5" cellspacing="5"> 
      <thead> 
       <tr> 
        <th>Movie Name</th> 
        <th>Directors Name</th> 
        <th>Release Date</th> 
       </tr> 
      </thead> 
      <tbody> 
<?php foreach ($movies as $movie) { ?> 
       <tr> 
        <td><a href="/?movie=<?php echo $movie->id; ?>"><?php echo $movie->movie_name; ?></a></td> 
        <td><?php echo $movie->directors_name; ?></td> 
        <td><?php echo $movie->release_date; ?></td> 
       </tr> 
<?php } ?> 
      </tbody> 
     </table> 
    </body> 
</html> 

意見v_movie.php(圖)

<html> 
    <head> 
     <title><?php echo $movie->movie_name; ?></title> 
    </head> 
    <body> 
     <h1><?php echo $movie->movie_name; ?></h1> 
     <h2>Directed by <?php echo $movie->directors_name; ?></h2> 
     <h3>Released <?php echo $movie->release_date; ?></h3> 
    </body> 
</html> 
+2

不錯的問題,但我建議這真的屬於codereview。 – GordonM 2012-03-27 19:01:14

回答

28

首先,你是在讓事情做得相當好分離/ 。它在未來會回報,所以不要放棄。

數據庫佈局(甚至數據庫本身)與MVC的本質無關。在大多數情況下,它恰好是關係數據庫,但是MVC並不需要顯式地使用它(也可以使用XML存儲或一些網格/雲)。對於MVC來說至關重要的是保持模型與其他模型分離,你做了。

你的看法也清楚地與其他人分開。與MVC的M部分類似,Views不僅可以呈現HTML,而且還可以呈現任何可由文本表示的輸出(XML,XML + XSL,RSS,純文本甚至電子郵件),視圖可以通過幾種方式實現:PHP包括像您的,模板(即Smarty)或完全成熟的可串行化爲文本的對象。我遠非判斷哪種策略是最好的,而是個人編碼風格和項目需求的問題。

您的控制器很混亂(它比應用程序控制器更多的頁面控制器)。這可能是由於MVC架構中存在一個隱藏部分。它被稱爲前端控制器調度員。由分派器解析輸入,實例化控制器(如在應用程序控制器中)並調用請求的方法。如果你想保持與自定義的MVC實現持續,我建議你使用通過控制器類和URL的方法名的一些常見的方式,即

index.php/Movies/list 
index.php/Movies/details/35 

然後在新的index.php你只是解析$ _ SERVER ['PATH_INFO 「],實例Movies類並調用其list方法,即

$args = explode('/', ltrim($_SERVER['PATH_INFO'], '/')); 
$className = array_shift($args); 
$method = array_shift($args); 
require "$className.php"; 
call_user_func_array(array(new $className(), $method), $args); 

然後你只需if-else塊的內容移動到電影類兩種不同的方法。

class Movies { // may extend generic Controller class if you wish 

    public function list() { 
     $movies = Movie::get_all(); 
     include 'views/v_list.php'; 
    } 

    public function details($movieId) { 
     $movie = new Movie($movieId); 
     if ($movie->id > 0) { 
      include 'views/v_movie.php'; 
     } else { 
      echo "Movie Not Found"; 
    } 

} 

這樣你可以有多個控制器,每個控制器都有多個動作。

最後的言論。

  • 在數據庫方面,使用現有的ORM框架之一是很方便的。他們將爲您節省數天的工作時間,並且可能會比手工製作的db層表現更好。我還建議處理PDO實例的實例化,因爲在每個Model對象中實例化PDO不是最簡潔的方式。像DBFactory::getConnection就可以做。

  • 您可能會考慮返回HTML而不是在控制器中回顯它。如果你想實現攔截過濾器這會給你帶來更大的靈活性,它會包裹控制器,攔截它的輸出並對它進行預處理或後處理。過濾器自動附加HTML頁眉和頁腳是非常方便的。

  • 創建自定義框架是非常有趣且有價值的教育體驗,但是我建議使用現有框架之一來執行更嚴肅的任務。

一切順利。

+0

+1使用現有的ORM - 嘗試將類自己映射到關係模型是一種痛苦 – Wickethewok 2009-01-15 15:48:06

+0

感謝您的好帖子 – 2009-01-15 20:31:53

10

你做得不錯,但我有幾個建議:

  1. 由於您使用PHP5不要忘記__autoload功能。
  2. 最好將您的數據層命名爲Model。
  3. get_all_from_database沒有被聲明爲靜態,但是您正在靜態調用它,這會生成E_STRICT級別警告。設置error_reporting(E_ALL | E_STRICT);你應該看到警告。
  4. get_all()靜態函數應該在Model類中(在你的情況Datatier中),這樣你就不必爲每個其他模型重寫它。您需要在該功能中進行的唯一更改是替換該行:

    $ results = parent :: get_all_from_database('movie');

$results = $this->get_all_from_database(get_class($this)); 

這是假定你的模型的名稱必須與表的名稱在數據庫

1

唯一令立即跳轉我(匹配具有不已經被提及)爲「奇怪」的是你正在使用兩個PDO實例與同一個數據庫交談。本身並不太壞,但是你也存儲了用戶名,密碼和dsn的其餘部分兩次。

這可能只是因爲這是張貼到網絡上的示例代碼。