2009-01-15 18 views
15

Tôi không phải là một anh chàng khuôn khổ lớn nhưng tôi đã thích những gì tôi đã nghe về toàn bộ phong trào MVC vì vậy tôi nghĩ tôi sẽ cố gắng tạo ra một ứng dụng đơn giản bằng ngôn ngữ của tôi (PHP)Hãy phê bình nỗ lực đầu tiên của tôi tại MVC trong PHP

Vì vậy, tôi đoán câu hỏi là: tôi đã đi sai ở đâu? Tôi biết có rất nhiều cuộc tranh luận về mức độ chất béo của bộ điều khiển/mô hình nên hy vọng chúng ta có thể tránh được điều đó, tuy nhiên tôi đặc biệt tò mò với suy nghĩ của bạn về cách tôi phù hợp với bộ dữ liệu.

Ngoài ra tôi đã mua miền để làm một số xét nghiệm vì vậy nếu bạn muốn nhìn thấy nó trong hành động mà bạn có thể đi đến www.omgmvc.com

Thứ nhất, đây là giản đồ cơ sở dữ liệu của tôi:

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'); 

Và đây là các tập tin:

index.php(điều khiển)

<?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(data tier)

<?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ô hình/m_movie.php(model)

<?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; 
    } 
} 

?> 

views/v_list.php(view)

<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> 

views/v_movie.php(view)

<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

Câu hỏi hay, nhưng tôi muốn đề xuất rằng điều này thực sự thuộc về codereview. – GordonM

Trả lời

28

Trước tiên, bạn đang làm khá tốt để giữ mọi thứ ngăn cách . Nó trả lại trong tương lai, vì vậy đừng bỏ cuộc.

Bố cục cơ sở dữ liệu (hoặc thậm chí cơ sở dữ liệu chính nó) không liên quan đến bản chất của MVC. Nó xảy ra là cơ sở dữ liệu quan hệ trong hầu hết các trường hợp, tuy nhiên MVC không yêu cầu nó một cách rõ ràng (bạn có thể sử dụng lưu trữ XML hoặc một số lưới/đám mây). Điều quan trọng đối với MVC là giữ Mô hình tách biệt với phần còn lại, mà bạn đã làm.

Chế độ xem của bạn cũng được tách biệt rõ ràng với phần còn lại. Tương tự như phần M của MVC, các khung nhìn không chỉ có thể trình bày HTML, mà là bất kỳ đầu ra văn bản nào (XML, XML + XSL, RSS, văn bản thuần hoặc thậm chí là các thông báo email), các khung nhìn có thể được thực hiện theo nhiều cách: , các mẫu (tức là Smarty) hoặc các đối tượng đầy đủ có thể tuần tự hóa thành văn bản. Tôi không đánh giá chiến lược nào là tốt nhất, đó là vấn đề về các yêu cầu về dự án và yêu cầu của dự án.

Bộ điều khiển của bạn gây nhầm lẫn (Bộ điều khiển trang nhiều hơn Bộ điều khiển ứng dụng). Nó có lẽ là do thực tế, có một phần ẩn trong kiến ​​trúc MVC. Nó được gọi là Bộ điều khiển mặt trước hoặc Bộ điều phối. Điều này phụ thuộc vào Dispatcher để phân tích đầu vào, điều khiển khởi tạo (như trong Application Controller) và gọi phương thức được yêu cầu.Nếu bạn muốn tiếp tục đi với tùy chỉnh MVC thực hiện của bạn tôi khuyên bạn nên sử dụng một số cách phổ biến của truyền lớp điều khiển và tên phương pháp trong URL, ví dụ:

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

Sau đó in new index.php bạn chỉ cần phân tích cú pháp $ _SERVER [ 'PATH_INFO '], nhanh chóng lớp Movies và gọi phương thức list của nó, tức là

$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); 

Sau đó, bạn chỉ cần di chuyển các nội dung của if-else khối để hai phương pháp riêng biệt trong lớp phim.

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"; 
    } 

} 

Bằng cách này bạn có thể có nhiều bộ điều khiển, mỗi bộ điều khiển có nhiều hành động.

Nhận xét cuối cùng.

  • Về phía cơ sở dữ liệu, sẽ thuận tiện khi sử dụng một trong các khung ORM hiện có. Họ sẽ tiết kiệm cho bạn ngày làm việc và có thể sẽ hoạt động tốt hơn so với tầng db thủ công. Tôi cũng sẽ đề nghị xử lý instantiation của PDO instance như instantiating PDO trong mọi đối tượng Model không phải là cách sạch nhất. Một cái gì đó như DBFactory::getConnection sẽ làm.

  • Bạn có thể xem xét trả về HTML thay vì lặp lại nó trong bộ điều khiển. Điều này cho phép bạn linh hoạt nếu bạn muốn triển khai Bộ lọc chặn sẽ bao gồm bộ điều khiển, chặn đầu ra của nó và trước hoặc sau xử lý nó. Rất thuận tiện để có bộ lọc tự động đính kèm tiêu đề và chân trang HTML.

  • Tạo khung tùy chỉnh là trải nghiệm giáo dục có giá trị và thú vị, tuy nhiên tôi khuyên bạn nên sử dụng một trong các khung công tác hiện có cho các tác vụ nghiêm trọng hơn.

Tất cả tốt nhất.

+0

+1 để sử dụng ORM hiện tại - cố gắng ánh xạ các lớp học theo mô hình quan hệ của riêng bạn là một nỗi đau – Wickethewok

+0

Cảm ơn bạn đã đăng bài tốt –

10

Bạn đang làm tốt, nhưng tôi có một vài gợi ý:

  1. Vì bạn đang sử dụng php5 dont quên về chức năng __autoload.
  2. Tốt hơn nên đặt tên tầng dữ liệu là Mô hình.
  3. get_all_from_database không được khai báo là tĩnh nhưng bạn đang gọi nó tĩnh, điều này tạo ra cảnh báo cấp E_STRICT. Đặt error_reporting (E_ALL | E_STRICT); và bạn sẽ thấy cảnh báo.
  4. get_all() chức năng tĩnh phải ở trong lớp Model (trong trường hợp Datatier của bạn), do đó bạn không phải viết lại nó cho mọi mô hình khác.Thay đổi duy nhất bạn cần thực hiện trong chức năng đó là thay thế dòng:

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

với

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

này giả định rằng tên của mô hình của bạn phải phù hợp với tên của các bảng của bạn trong cơ sở dữ liệu

+0

Rất nhiều điểm tốt. Cảm ơn Joey! –

+0

Tôi ngạc nhiên không ai khác là upvoting, tôi thấy đây là một câu trả lời thực sự tốt –

1

Điều duy nhất mà ngay lập tức nhảy vào tôi (có không đã được đề cập) như là "lẻ" là bạn đang sử dụng hai trường hợp PDO để nói chuyện với cùng một cơ sở dữ liệu. Không quá tệ, nhưng bạn cũng lưu trữ tên người dùng, mật khẩu và phần còn lại của dsn hai lần.

Có thể chỉ vì đây là mã mẫu được đăng lên web tho.

Các vấn đề liên quan