如何在MVC中构建模型?

时间:2011-05-03 00:28:43

标签: php oop model-view-controller architecture model

我只是掌握了MVC框架,我常常想知道模型中应该有多少代码。我倾向于拥有一个具有以下方法的数据访问类:

public function CheckUsername($connection, $username)
{
    try
    {
        $data = array();
        $data['Username'] = $username;

        //// SQL
        $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

        //// Execute statement
        return $this->ExecuteObject($connection, $sql, $data);
    }
    catch(Exception $e)
    {
        throw $e;
    }
}

我的模型往往是映射到数据库表的实体类。

模型对象应该具有所有数据库映射属性以及上面的代码,还是可以将实际上数据库工作的代码分开?

我最终会有四层吗?

5 个答案:

答案 0 :(得分:867)

答案 1 :(得分:35)

业务逻辑的所有内容都属于模型,无论是数据库查询,计算,REST调用等。

您可以在模型本身中访问数据,MVC模式不会限制您这样做。您可以使用服务,映射器和其他方法对其进行糖涂层,但模型的实际定义是处理业务逻辑的层,仅此而已。它可以是一个类,一个函数,或一个包含大量对象的完整模块,如果这就是你想要的。

拥有一个实际执行数据库查询的单独对象总是更容易,而不是让它们直接在模型中执行:这在单元测试时会特别派上用场(因为在你的模拟数据库依赖注入中很容易模型):

class Database {
   protected $_conn;

   public function __construct($connection) {
       $this->_conn = $connection;
   }

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

此外,在PHP中,您很少需要捕获/重新抛出异常,因为保留了回溯,特别是在您的示例中。只是抛出异常并在控制器中捕获它。

答案 2 :(得分:20)

在网络 - “MVC”中,你可以做任何你想做的事。

原始概念 (1) 将模型描述为业务逻辑。它应该代表应用程序状态并强制执行一些数据一致性。这种方法通常被描述为“胖模型”。

大多数PHP框架遵循更浅层的方法,其中模型只是一个数据库接口。但至少这些模型仍应验证传入的数据和关系。

无论哪种方式,如果将SQL内容或数据库调用分成另一层,那么你就不是很远了。这样,您只需关注真实的数据/行为,而不是实际的存储API。 (但是过度使用它是不合理的。如果没有提前设置,你将永远无法用文件存储替换数据库后端。)

答案 3 :(得分:6)

通常,大多数应用程序都有数据,显示和处理部分,我们只是将所有这些应用程序放在MVC字母中。

模型(M - >具有保存应用状态的属性,并且不了解VC的任何内容。

查看(V - >显示应用程序的格式,并且只知道如何在其上消化模型,并且不关心{{1} }。

控制器(C ---->处理应用程序的一部分并充当M和V之间的接线,它取决于C,{{ 1}}与MV不同。

每个人之间总是存在分离关系。 将来可以非常轻松地添加任何更改或增强功能。

答案 4 :(得分:0)

在我的例子中,我有一个数据库类来处理所有直接数据库交互,例如查询,提取等。因此,如果我必须将数据库从MySQL更改为PostgreSQL,则不会有任何问题。所以添加额外的图层会很有用。

每个表都有自己的类并具有其特定的方法,但是为了实际获取数据,它允许数据库类处理它:

档案Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

表对象classL

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

我希望这个例子可以帮助你创建一个好的结构。