第四章 – 模型和ORM基础1

对于任何一个MVC架构,模型(Model)层的实现都是占据了很大一部分。对于Magento来说,模型占据了一个更加重要的位置,因为它常常包含了一部分商业逻辑代码(可以说它对,也可以说它错)。这些代码在其他的MVC框架中往往出现在控制器或者帮助函数中。

传统的PHP MVC架构中的模型

本来MVC的定义就不是很清晰,不同的人有不同的看法,而对于模型的定义争议就更多了。在MVC模式被广泛采用之 前,PHP程序员往往通过SQL语 句直接操作数据库。也有些程序员通过一个SQL抽象层来操作数据库(比如AdoDB)。程序员往往关注SQL语句本身,而不是和数据相关的对象。

虽然直接操作SQL的方式一直被病诟,但是很多PHP框架还是以SQL为中心的。模型层提供了一系列对象,抽象/封装了数据操作,但是程序员最终还是需为模型层对象写SQL语句操作数据库。

 

还有一些框架回避了SQL,使用了对象关系映射(Object Relational Mapping,ORM)来解决这个问题。使用这个方法的话,程序员不用关注SQL,而只需要和对象打交道。我们可以操作一个对象的属性,当“Save” 方法被调用的时候,对象的属性会作为数据自动的被写入数据库。有些ORM框架会根据数据表的信息自动推测对象的属性,也有框架要求用户显示的生命对象属性 和表的关系。比较有名的ORM框架有ActiveRecord等等。【注:ActiveRecord源自Ruby on Rails,不过现在PHP也有了】

关于ORM的概念,我就解释到这里。但是和许多计算机领域的其他概念一样,ORM的定义也越来越模糊了。我不想在这片文章中讨论关于ORM的争议,所以我说的ORM就是那个最基本的ORM概念。

Magento的模型

Magento理所当然的也追随潮流应用了ORM。虽然Magento自带的Zend框架提供了SQL抽象层,但是 在大多数情况下我们将通过 Magento自带的模型和我们自己的模型来进行数据访问。他和视图层(View)一样,Magento的模型层也不是简单的ORM,而是一个高度灵活, 高度抽象甚至有点令人费解。

解剖Magento的模型

大部分的Magento模型分为两类。第一类是基本的ActiveRecord类型,一张表一个对象的模型。第二类 是Entity Attribute Value(EAV)模型。【注:EAV翻译成“实体属性值”有点词不达意,还是就叫EAV的好】Magento自己定义了一个数据类型叫做模型集合 (Model Collection)。顾名思义,模型集合就是一个对象里面包含了很多模型对象。Magento的创造者Varien团队实现了PHP类库的标准接 口,“IteratorAggregate”,“Countable”。这样模型集合就能调用这些方法,这也是模型集合和数组的区别。

Magento的模型并不直接访问数据库。每一个模型都有一个资源模型(Resource Model),每一个资源模型拥有两个适配器(Adapter),一个读,一个写。这样的话逻辑模型和数据库访问就分开了,所以从理论上讲更改底层数据库 只需要重写适配器就可以了,所有上层代码都不需要更改。
创建一个基本模型

继续我们Hello World的例子。在Hello World模块中创建BlogController.php如下

class
 App_Helloworld_BlogController extends
 Mage_Core_Controller_Front_Action {
 
public function indexAction( )
{
echo 'Hello Blog' ;
}
}

访问以下URL

http:
//127.0.0.1/Magento/helloworld/blog

你应该看到“Hello Blog”输出。

创建数据表

我们可以通过Magento自带的方法创建或者修改数据库,但是为了不引入过多新内容,我们暂且手工创建一张表。在你的数据库中执行以下语句

CREATE
 TABLE
 `blog_posts`
 (
 
`blogpost_id` int( 11 ) NOT NULL AUTO_INCREMENT ,
`title` text,
`post` text,
`date` datetime DEFAULT NULL ,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( `blogpost_id` )
) ;
INSERT
 INTO
 `blog_posts`
 VALUES
 (
1
,
'My New Title'
,
'This is a blog post'
,
'2009-07-01 00:00:00'
,
'2009-07-02 23:12:30'
)
;

这里我们创建了一张名为“blog_posts”的表,并填充了一条数据。

创建模型

要设置一个模型一共有以下四个步骤

  1. 启用模型
  2. 启用资源模型
  3. 在资源模型中添加实体(Entity)。对于简单的模型来说,实体就是数据表的名字
  4. 为资源模型设置读、写适配器

在进行这些步骤之前,我们先来看假设这些步骤已经做完了,我们怎么用一个模型。在Magento中,我们用以下的方式来实例化一个模型

$model
 =
 Mage::
getModel
(
'helloworld/blogpost'
)
;

和我们以前讲过的“Mage::getHelper()”的原理类似,这里Magento也是通过全局配置去查找模型的类名。模型的类名和我们以前讲过的 块类名一样,都是分组类名。这里参数的前半部分“helloworld”是组名(Group Name),后半部分“blogpost”是半类名(Class Name)【注:我将“Class Name”翻译成半类名是为了和类名区分开来】。具体步骤如下

  1. 从全局配置“/global/models/GROUP_NAME/class”获得基本类名“App_Helloworld_Model”
  2. 检查全局配置“/global/models/GROUP_NAME/rewrite/CLASS_NAME”是否设置,如果有那么这个节点的值将被作为类名实例化
  3. 否则,最终的类名将是基本类名加上半类名,也就是“App_Helloworld_Model_Blogpost”
启用模型

修改模块的config.xml

<global>


 
<!-- ... -->
<models>
<helloworld>
<class> App_Helloworld_Model</class>
<!--
need to create our own resource, can't just
use core_mysql4
-->
<resourceModel> helloworld_mysql4</resourceModel>
</helloworld>
</models>
<!-- ... -->
</global>

标签就是组名,也应该和模块名一致。标签的内容是基本类名,所有Helloworld模块的模型都用这个基本类名,命名方式如下

Packagename_Modulename_Model

标签指明了这个模块的模型要用哪个资源模型。这个标签的内容是组名加上“mysql4”我们将在后面详细介绍资源模型。

现在让我们来实例化一个模型看看,修改indexAction方法

public
 function
 indexAction(
)
 {
 
$blogpost = Mage:: getModel ( 'helloworld/blogpost' ) ;
echo get_class ( $blogpost ) ;
}

清空Magento缓存,刷新页面,你应该看到一个类似这样的异常(请先打开Magento的开发模式

include
(
App/Helloworld/Model/Blogpost.
php)
 [
<
a href=
'function.include'
>
function.
include</
a>
]
:
 failed to open stream:
 No such file
 or directory

原因很简单,就是Magento尝试去实例化“App_Helloworld_Model_Blogpost”,但是它在Helloworld模块的文件夹里面找不到这个类。所以我们现在来创建这个类

        File
:
 app/
code/
local/
App/
Helloworld/
Model/
Blogpost.
php 
class App_Helloworld_Model_Blogpost extends Mage_Core_Model_Abstract
{
protected function _construct( )
{
$this -> _init( 'helloworld/blogpost' ) ;
}
}

刷新页面,你应该看到页面上显示”App_Helloworld_Model_Blogpost”。所有的模型都必须继承 “Mage_Core_Model_Abstract”类。这个抽象类强制你实现一个方法“_construct”(注意:这个不是PHP的构造行数 “__construct”)。这个方法应该调用父类已经定义好的“_init”方法,参数是资源模型的URI,也就是我们要告诉模型使用哪个资源模型。 我们将在解释资源模型的时候再解释这个URI。

启用资源模型并添加实体

好了,我们设置好了模型,下面我们要为模型设置资源模型。资源模型才是真正和数据库对话的组件。在模型的配置中,有一段这样的代码

<resourcemodel>


helloworld_mysql4</resourcemodel>



的值将被用来实例化资源模型。我们不需要显式的调用资源模型,但是当一个模型需要访问数据库的时候,Magento会自动实例化一个资源模型来使用。

Mage::
getResourceModel
(
'helloworld/blogpost'
)
;

这里“helloworld/blogpost”就是我们给模型的“_init”传入的参数。“helloworld”是组名,“blogpost”是模 型的半类名。“Mage::getResourceModel”方法将以“helloworld/blogpost”为URI在全局配置中找到标 签的值,在这里是“helloworld_mysql4”。然后Magento会用URI“helloworld_mysql4/blogpost”去实 例化资源模型类。实例化的过程和我们前面讲的模型的实例化是一样的,所以我们也需要在config.xml中添加资源模型的声明

<
global>
 
<!-- ... -->
< models>
<!-- ... -->
< helloworld_mysql4>
< class> App_Helloworld_Model_Resource_Mysql4</ class>
</ helloworld_mysql4>
</ models>
</ global>

这里我们可以看到,资源模型的声明也是放在下面的。有点搞,但是也不必深究了,Magento就这么定义的。标签的值是所有资源模型类的基本类名,命名方式如下

Packagename_Modulename_Model_Resource_Mysql4

好了,我们已经配置了资源模型,我们来试试装载一些数据。修改indexAction如下

        public
 function
 indexAction(
)
 {
 
$params = $this -> getRequest ( ) -> getParams ( ) ;
$blogpost = Mage:: getModel ( 'helloworld/blogpost' ) ;
echo ( "Loading the blogpost with an ID of " . $params [ 'id' ] . "<br />" ) ;
$blogpost -> load ( $params [ 'id' ] ) ;
$data = $blogpost -> getData ( ) ;
var_dump ( $data ) ;
}

清空Magento缓存,访问下面的页面

http:
//127.0.0.1/Magento/helloworld/blog/index/id/1

你应该看到一个类似下面这样的异常

include
(
App/Helloworld/Model/Resource/Mysql4/Blogpost.
php)
 [
function
.
include
]
:
 failed to open stream:
 No such file
 or directory

我想你看到这里也明白了,我们要为模型添加一个资源类,添加如下文件

File
:
 app/
code/
local/
App/
Helloworld/
Model/
Resource/
Mysql4/
Blogpost.
php 
class App_Helloworld_Model_Resource_Mysql4_Blogpost extends Mage_Core_Model_Mysql4_Abstract{
protected function _construct( )
{
$this -> _init( 'helloworld/blogpost' , 'blogpost_id' ) ;
}
}

这里“_init”方法的第一个参数这个资源模型将要使用的数据表的URI,第二个参数是数据表中的列名。这个列的内容必须唯一,往往是数据表的主键。

为资源模型添加实体

刷新页面,你是不是得到下面的异常?

Can't retrieve entity config: helloworld/blogpost

那是因为我们的资源文件现在还是一个空壳,并没有和数据库联系起来。现在我们来把资源模型和我们的表联系起来,修改config.xml如下

<
global>
 
<!-- ... -->
< models>
<!-- ... -->
< helloworld_mysql4>
< class> App_Helloworld_Model_Resource_Mysql4</ class>
< entities>
< blogpost>
< table> blog_posts</ table>
</ blogpost>
</ entities>
</ helloworld_mysql4>
</ models>
</ global>

我们前面设置了资源模型使用的数据表的URI是“helloworld/blogpost”,那么Magento会把“helloworld”作为组名,“blogpost”作为实体名,也就是。在Magento的简单模型中(也就是继承Mage_Core_Model_Mysql4_Abstract的模型),一个实体对应一张数据表。我们的数据表是“blog_posts”,所以这里

标签的内容就是“blog_posts”。

清空Magento缓存,再次刷新页面,你应该看到以下内容

Loading the blogpost with an ID of 1
 
array ( 5 ) { [ "blogpost_id" ] => string( 1 ) "1" [ "title" ] => string( 12 ) "My New Title" [ "post" ] => string( 19 ) "This is a blog post" [ "date" ] => string( 19 ) "2009-07-01 00:00:00" [ "timestamp" ] => string( 19 ) "2009-07-02 23:12:30" }

来自: http://hi.baidu.com/190420456/blog/item/fe541b67a8a4d72baa184c08.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值