Magento开发文档(一):Magento入门
开始之前,首先声明下,Magento开发者手册由Alan Storm发表在Magento官方网站上。总共分八个部分,由浅入深的介绍了Magento的MVC架构及Magento中使用的比较特殊的EAV模型。
虽然英文文档读起来没有问题,但是真想看一遍能有一定深入的了解,还是中文看着比较舒服。并且在网上搜索了下,大部分都是Magento的模板开发手册以及没有纠错的原文翻译(因为版本问题,Magento官方网站上的一些例子已经无法正常运行),所以决定把这写文章翻译成中文,一来对于自己更深入的把握程序有好处,二来对于想学习Magento的朋友们有个帮助。
需要点到的一个地方,翻译不易,请尊重作者Alan Storm的劳动,同时也请尊重我的劳动,转载请注明出自本站,并注明作者英文地址。十分感谢!废话到此为止。
翻译名词对照:
Modules->模块
Controller->控制器
Model->模型
Magento是这个星球上最强大的购物车网店平台。当然,你应该已经对此毫无疑问了。不过,你可能还不知道,Magento同样是一个面向对象的PHP框架。你可以配合Magento购物车程序强大的功能,开发动态WEB应用程序。
这是Magento中文开发手册的开篇,我们会在整个手册中介绍绝大部分Magento的开发框架特性。不要想在这片文章中立刻掌握所有的特性。这仅仅是个开始,但是足够让你在同行中鹤立鸡群了。
在这片文章中,你将了解到:
- Magento模块(Magento Modules)代码组织形式
- 配置型MVC架构
- Magento控制器(Magento Controllers)
- 基于URI的模型实例化(Context-based URI Model Loading)
- Magento模型(Magento Models)
- Magento助手(Magento Helpers)
- Magento布局(Magento Layouts)
- 事件监听(Observers)
- Magento类重写(Class Overrides)
- 总结
开始之前,你可以试着看下Magento MVC模式的一个图形化直观体现。Magento_MVC.pdf
Magento模块中的代码组织形式
Magento通过将代码放入独立的模块进行组织。在一个典型的PHP MVC应用中,所有的控制器会被放在一个文件夹中,所有的模型会被放在另外一个文件夹里,等等。而在Magento中,文件是基于功能进行分组的,这种分组后的代码块叫做模块。
Magento的代码:
举例来说,如果你想寻找Magento中关于付款的功能,你仅仅需要找到下面代码中的文件夹,就能获取所有的控制器,模型,助手,Blocks等。
app/code/core/Mage/Checkout
如果你想寻找Magento中关于Google Checkout的功能,也仅仅需要找到如下文件夹,即可获取所有你想要的信息。
app/code/core/Mage/GoogleCheckout
你的代码:
如果你想扩展Magento,千万不要想当然的去修改core文件夹中的文件,也不要将你自己的控制器,模型,助手或者Blocks放在Core文件夹中。所有对于Magento的扩展,都将在local文件夹中进行。
app/code/local/<Package>/<Modulename>
Package(也可称为命名空间,当然这不是PHP手册中提到的命名空间)是唯一的命名,通过Package来标识你的公司,组织或个人。通过Package,世界范围内的Magento社区在创建模块扩展时,能够使用他们自己的Package名称,以避免与其他开发者有命名冲突。
创建一个新的模块时,你需要告诉Magento新模块的相关信息。可以通过添加一个XML文件在下面的目录中。
app/etc/modules
在这个目录中有两类xml文件,第一种用来开启独立的模块,以下列方式命名:
Packagename_Modulename.xml
第二种文件用来从一个Package中开启多个模块,以下列方式命名:
Packagename_All.xml
配置型MVC系统
Magento是一个配置型MVC(Configuration-based MVC)系统。另外一种MVC系统则是大部分PHP框架使用的,约定性MVC(convertion-based MVC)。
在约定型MVC系统中,如果你添加一个控制器,或者一个模型,只需要根据约定的内容,创建这个文件以及类即可,系统会自动识别它。
而在配置型MVC系统中,比如Magento,除了需要添加相应的文件及类之外,还需要明确的告诉系统该类的存在。在Magento中,每个模块都有一个config.xml文件。这个文件中包含了一个模块相关的配置信息。在运行时,所有模块的配置文件,都会被加载到一个巨大的配置文件树中(后面的文章会介绍如何查看这个配置树)。
比如,想在模块中使用模型。你需要添加类似下面的代码,来告诉Magento你会在这个模块中使用这个模型。
<
models
>
<
packagename
>
<
class
>Packagename_Modulename_Model</
class
>
</
packagename
>
<
models
>
当然,这种配置不仅限于模型,对于控制器,助手,Blocks,路由,事件句柄等都需要在该模块的config.xml中进行相关的配置。
Magento控制器(Magento Controllers)
在任何PHP系统当中,核心文件肯定是PHP文件。Magento也不例外,index.php是Magento的核心文件。
不过,永远不要编辑index.php中的任何代码。在MVC系统中,index.php的左右大概有以下几项:
- 检测URL地址。
- 根据路由规则,将访问的URL地址分发到控制器类中的方法。
- 初始化控制器,并调用相应的动作方法。这一步骤叫做分发。Dispatching。
这意味着Magento(或任何MVC系统)每一个有效的entry point都是控制器文件中的一个方法。一起来看下面这个URL:
http://example.com/catalog/category/view/id/25
上述域名后URL地址可以被分拆为以下几个部分。
Front Name – catalog
该URL的第一部分被称为Front Name。它用来指示Magento应该在哪个模块中寻找URL中的控制器。在这个例子中,catalog就是Front Name,对应于catalog模块。
Controller Name – Category
第二部分指示Magento应该匹配的控制器。每个拥有控制器的模块都包含一个‘controllers’的文件夹,用来存放该模块下的所有控制器。上述URL地址,匹配了下面这个控制器文件。
app/code/core/Mage/Catalog/controllers/CategoryController.php
其中的类定义格式大概为:
class
Mage_Catalog_CategoryController
extends
Mage_Core_Controller_Front_Action
{
}
在Magento中,所有的控制器都继承自Mage_Core_controller_Front_Action类。
Action Name – view
第三部分是一个action方法的名称。在此URL中,view便是一个action方法的名字。
class
Mage_Catalog_CategoryController
extends
Mage_Core_Controller_Front_Action {
public
function
viewAction() {
}
}
Paramater/Value – id/25
任何位于action方法名之后的路径,都会被认为是key/value形式传递的GET变量。那么在我们的例子当中,’id/25′表示有一个值为25的$_GET[‘id’]变量。
如前所述,如果你想让自定义模块使用控制器,你必须对它进行配置。下面是在模块中开启控制器的代码。
<
frontend
>
<
routers
>
<
catalog
>
<
use
>standard</
use
>
<
args
>
<
module
>Mage_Catalog</
module
>
<
frontName
>catalog</
frontName
>
</
args
>
</
catalog
>
</
routers
>
</
frontend
>
现在不清楚上述内容都是什么意思还没关系,但是注意<frontName>catalog</frontName>。这是用来关联模块与URL地址中frontname的。Magento核心代码选择将一个模块的名字与frontname一致,但这不是强制规定的。
Multiple Routers
上面提到的路由规则主要是针对Magento购物车程序(即你所能看到的前端)。如果Magento在URL中无法匹配到正确的控制器/动作,它会尝试使用针对Admin程序(后台管理端)的另一套路由规则。如果依旧无法正确匹配,它会使用一个特殊的控制器Mage_Cms_IndexController。
CMS控制器会检查Magento内容管理系统中是否有内容需要输出,如果有内容输出,则读取该内容,如果找不到,则输出404页面。
例如,Magento默认的首页就是在使用CMS控制器。
Context-Based URI 模型读取
目前为止,我们已经建立了一个控制器以及一个方法,到实例化一个类做点什么的时候了。Magento提供了一种特殊的方式去实例化模型,助手以及Blocks,即使用Mage全局类提供的静态工厂方法。例如:
Mage::getModel(
'catalog/product'
);
Mage::helper(
'catalog/product'
);
‘catalog/product’字符串被称为Grouped Class Name。通常叫做URI。Grouped Class Name的第一部分用来指示该类存在于哪个模块当中。第二部分用来决定哪个类将被调用。
那么,上述例子中,‘catalog’对应于app/code/core/Mage/Catalog模块,也就意味着我们的类名将以Mage_Catalog开头,然后根据调用的类型,将product类名加入到最后一部分。即:
Mage::getModel(
'catalog/product'
);
Mage_Catalog_Model_Product;
Mage::helper(
'catalog/product'
);
Mage_Catalog_Helper_Product;
Magento 模型
和现在的多数框架一样,Magento也提供ORM支持。ORM让你能够专注于数据,而非无尽的SQL语句。例如:
$model
= Mage::getModel(
'catalog/product'
)->load(27);
$price
=
$model
->getPrice();
$price
+= 5;
$model
->setPrice(
$price
)->setSku(
'SK1231414'
);
$model
->save();
在上面这个例子中,我们调用了“getPrice”和“setPrice”方法。然而,在Mage_Catalog_Model_Product类中并没有此方法。那为什么上面这个例子能够使用这些方法呢?因为Magento的ORM系统中使用了PHP的_get和_set魔术方法。
调用$product->getPrice()会获取模型属性price,而调用$product->setPrice()会设置price属性。当然,所有的这些都假设模型类没有getPrice和setPrice方法。如果它们存在于模型类中,PHP魔术方法会被忽略。如果你有兴趣知道这是如何实现的,可以参考Varien_Object类,所有的模型类都继承自该类。
如果你想获取模型当中所有的数据,可以直接调用$product->getData()方法,它会返回包含所有字段的一个数组。
你可能已经注意到上例中的方法存在使用->符号链接的形式:
$model->setPrice($price)->setSku(‘SK12312542′);
能够使用这种方式调用方法,最主要的原因是所有的set方法都会返回一个模型的实例。 你会经常在Magento的核心代码中看到此类调用方法的形式。
Magento的ORM系统中还包含一种通过Collections接口查询多个对象的方式。下例会读取系统中所有5美元的产品。
$product_collection
= Mage::getModel(
'catalog/product'
)
->getCollection()
->addAttributeToSelect(
'*'
)
->addFieldToFilter(
'price'
,
'5.00'
);
这里我们又一次看到了链接调用方法的形式。Collections use the PHP Standard Library to implement Objects that have array like properties.(这句超出理解范围)。
foreach
(
$products_collection
as
$product
)
{
echo
$product
->getName();
}
在上面的一个例子当中,你可能注意到了addAttributeToSelect方法。这里单独提到此方法,是因为它代表了Magento模型中的一个类别。Magento拥有两种形式的模型对象。一种是传统的“一个对象,一张表”的Active Record模型。当你实例化这些模型的时候,所有的属性都会被自动选取。
Magento中第二种模型叫做Entity Attribute Value(EAV)模型。这种模型会按照一定的规律将数据分散存储在数据库不同的表中。EAV模型的高级特性,让Magento不用在增加一种产品属性的时候改变数据库模型(一般的购物车系统在增加新的属性时,有两种方式,一种是增加数据库字段,一种是使用预留的空字段。),从而保证了Magento系统的高度扩展性。当创建一个EAV模型的collection时,Magento会conservative in它会查询的字段数,所有你可以使用addAttributeToSelect来制定你想获取的列,或者使用addAttributeToSelect(*)来获取所有列。
Magento Helpers 助手
Magento的助手类包含一系列实用的方法,通过这些方法可以对对象及变量做日常性的操作。例如,
$helper
= Mage::helper(
'catalog'
);
是否注意到这里舍弃了Grouped Class Name的第二部分?每个模块都有一个默认的data助手类。下面的语句与上面的作用是相同的,即默认使用模块下的data助手类。
$helper
= Mage::helper(
'catalog/data'
);
大部分的助手类继承自Mage_Core_Helper_Abstract,默认提供了很多使用的方法。
$translated_output
=
$helper
->__(
'Magento is Great'
);
if
(
$helper
->isModuleOutputEnabled()) {
}
Magento Layout 布局
目前为止,我们已经介绍了控制器,模型以及助手。在典型的PHP MVC系统当中,在操作模型之后,一般会
- 传递变量到视图中。
- 系统会自动读取默认的外层布局
- 接着将视图读取到外层布局中
不过,如果你仔细观察Magento 控制器动作方法,你不会看到这些步骤,
public
function
galleryAction() {
if
(!
$this
->_initProduct()) {
if
(isset(
$_GET
[
'store'
]) && !
$this
->getResponse()->isRedirect()) {
$this
->redirect(
''
);
}
elseif
(!
$this
->getResponse()->isRedirect()) {
$this
->_forward(
'noRoute'
);
}
return
;
}
$this
->loadLayout();
$this
->renderLayout();
}
不同于典型PHP MVC形式的是,控制器动作方法,以两个输出布局的方法结束。所以说,Magento MVC系统中的V视图部分可能与你经常使用的大相径庭。因为,你必须在控制器中明确的输出布局。
并且,Magento的布局本身也区别与你经常使用的MVC系统。Magento布局是一个包含嵌套或者树状的Block对象的对象。每一个Block对象输出一部分HTML,输出HTML的环节包含两个部分,PHP代码组成的Block以及.phtml模板文件。
Blocks对象负责与Magento系统交互并从模型中获取数据,而phtml模板文件则为页面生成必须的HTML代码。
例如,页面头部Block文件app/code/core/Mage/Page/Block/Html/Head.php使用与其对应的page/html/head.phtml模板文件。
换种方式说的话,Blocks类就像迷你控制器,而.phtml文件就是视图文件。
默认的,当你调用,
$this
->loadLayout();
$this
->renderLayout();
Magento will load up a Layout with a skeleton site structure(此段能够理解,但想不到最佳翻译,大概意思是Magento会读取网站的布局框架)。这些结构Blocks用来输出head,body以及设定单栏或多栏的布局。另外,还有一些内容Blocks负责实际输出像导航,产品分类等。
“结构”和“内容”Blocks在布局系统中是随意设置的。一般不会在代码中刻意添加代码,从而区分一个Block是结构还是内容,但是Blocks要么属于“结构”,要么属于“内容”。
为了添加一个内容Blocks到布局中,你需要告诉Magento系统
“Magento,快把这几个Blocks添加到内容Block 里”
或者
“Magento,把这边几个Blocks放到“左边栏”结构Block里”
这些可以通过控制器中的代码进行控制,
public
function
indexAction() {
$block
=
$this
->getLayout()->createBlock(
'adminhtml/system_account_edit'
);
$this
->getLayout()->getBlock(
'content'
)->append(
$block
);
}
但是更常用的方式(至少在前台购物车应用中)是使用基于XML文件的布局系统。
在一款风格中,基于XML文件的布局 允许你删除正常输出的Blocks或者添加默认的skeleton区域(即Structure Blocks)。例如下面这个XML布局文件,
<
catalog_category_default
>
<
reference
name
=
"left"
>
<
block
type
=
"catalog/navigation"
name
=
"catalog.leftnav"
after
=
"currency"
template
=
"catalog/navigation/left.phtml"
/>
</
reference
>
</
catalog_category_default
>
上面这段代码的作用是,在catalog模块的category控制器的默认动作方法中,将catalog/navigation Block插入到左边栏结构Block中,并使用catalog/navigation/left.phtml模板文件。
关于Blocks还有一个比较重要的特性。在模板文件中,你会看到很多类似下面的代码,
$this
->getChildHtml(
'order_items'
)
这是Block输出套嵌Block的方式。但是,只有在XML布局文件中明确声明一个Block包含另一个子Block时,才能在模板文件中通过getChildHtml()方法调用子Block的模板文件。
例如,在XML布局文件中,
<
catalog_category_default
>
<
reference
name
=
"left"
>
<
block
type
=
"catalog/navigation"
name
=
"catalog.leftnav"
after
=
"currency"
template
=
"catalog/navigation/left.phtml"
>
<
block
type
=
"core/template"
name
=
"foobar"
template
=
"foo/baz/bar.phtml"
/>
</
block
>
</
reference
>
</
catalog_category_default
>
那么从catalog/navigation Block中,我们才可以调用$this->getChildHtml(‘foobar’);
Observers 观察者
和许多优秀的面向对象系统一样,Magento通过实现观察者模式给用户作为钩子。对于在页面请求时(模型存储,用户登录等)调用的特定动作方法,Magento会生成一个事件信号。
当创建新的模块时,你可以“监听”这些事件。比如说,你想在特定用户登录商店的时候发一封邮件到管理员信箱里,可以通过“监听”customer_login事件做到。
<
events
>
<
customer_login
>
<
observers
>
<
unique_name
>
<
type
>singleton</
type
>
<
class
>mymodule/observer</
class
>
<
method
>iSpyWithMyLittleEye</
method
>
</
unique_name
>
</
observers
>
</
customer_login
>
</
events
>
接下来是当用户登录时应该运行的代码:
class
Packagename_Mymodule_Model_Observer
{
public
function
iSpyWithMyLittleEye(
$observer
)
{
$data
=
$observer
->getData();
//code to check observer data for out user,
//and take some action goes here
}
}
Class Overrides 类的复写
最后,Magento系统还提供了类的复写功能,你可以通过自己的代码覆盖核心代码里的模型,助手,和Blocks类。
下面举些例子帮助你更容易理解这个功能。产品的模型类是Mage_Catalog_Model_Product.无论何时,下面的代码被调用时,就会生成一个Mage_Catalog_Model_Product对象。
$product
= Mage::getModel(
'catalog/product'
);
这是工厂模式。Magento的类复写系统运作模式大概是这样,
“Magento! 如果有请求对应catalog/product,不要实例化Mage_Catalog_Model_Product,让Packagename_Modulename_Model_Foobazproduct接手”
在模型中,类的覆盖方式及命名规则如下,
class
Packagename_Modulename_Model_Foobazproduct
extends
Mage_Catalog_Model_Product
{
}
通过这种方式,你可以改变父类中方法的行为,并且完全继承父类的所有功能。
class
Packagename_Modulename_Model_Foobazproduct
extends
Mage_Catalog_Model_Product
{
public
function
validate() {
//添加一些自定义的验证功能
return
$this
;
}
和之前所说的一样,复写同样需要在config.xml配置文件中进行配置。
<
models
>
<!-- tells the system this module has models -->
<
modulename
>
<
class
>Packagename_Modulename_Model</
class
>
</
modulename
>
<!-- does the override for catalog/product-->
<
catalog
>
<
rewrite
>
<
product
>Packagename_Modulename_Model_Foobazproduct</
product
>
</
rewrite
>
</
catalog
>
</
models
>
转载自技安后院
Magento开发文档(一):Magento入门的更多相关文章
- Mego开发文档 - 索引
Mego 开发文档 Mego 快速概述 主要特性 获取Mego 使用流程 模型 查询 保存数据 入门 Mego 快速开始 创建项目 安装Nuget包 创建连接字符串 创建模型及数据上下文(添加引用) ...
- 微信小程序 开发文档
官方开发文档: 小程序公众平台 小程序开发者指南 小程序开发者文档 学习资源: 微信:官方入门教程 微信:WeUI 是一套同微信原生视觉体验一致的基础样式库 微信:微信小程序示例 视频: 学堂在线:学 ...
- 《转》CXF WebService 开发文档-目录索引
CXF WebService 开发文档-目录索引 上次介绍了Axis的WebService,现在我们来看看CXF是怎么完成WebService的. Axis1 WebService 在线博文: htt ...
- jssip中文开发文档(完整版)
jsSip开发文档 (官网地址:http://www.jssip.net/) 完整案例demo下载地址: http://download.csdn.net/download/qq_39421580/1 ...
- Android官方开发文档Training系列课程中文版:目录
Android官方开发文档Training系列课程中文版:目录 引言 在翻译了一篇安卓的官方文档之后,我觉得应该做一件事情,就是把安卓的整篇训练课程全部翻译成英文,供国内的开发者使用,尤其是入门开 ...
- [翻译]开发文档:android Bitmap的高效使用
内容概述 本文内容来自开发文档"Traning > Displaying Bitmaps Efficiently",包括大尺寸Bitmap的高效加载,图片的异步加载和数据缓存 ...
- Net通用进销存管理系统 + 开发文档+ 使用说明
通用进销存管理系统 + 开发文档+ 使用说明Net源码下载 包括下面的模块基础资料模块采购管理模块库存管理模块商务管理模块营业管理模块维修管理模块会员管理模块财务管理模块 Net通用进销存管理系统 + ...
- C#微信开发文档
C#微信开发文档 开发前准备 微信公众平台链接: https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN 开发初期我们使用测 ...
- 在线API,桌面版,jquery,css,Android中文开发文档,JScript,SQL掌用实例
学习帮助文档大全 jquery,css,Android中文开发文档,JScript,SQL掌用实例 http://api.jq-school.com/
随机推荐
- ORACLE 中KILL session
我们知道,在Oracle数据库中,可以通过kill session的方式来终止一个进程,其基本语法结构为: alter system kill session 'sid,serial#' ; 被kil ...
- Android设计模式之策略模式
今天介绍下策略模式,直接先上UML图 策略模式的概念 The Strategy Pattern defines a family of algorithms,encapsulates each one ...
- python-socket.error[10054]:对象的复制
1.socket.error[10054],对方强制关闭了连接 在用socket.recvfrom时,若事先没有bind时, 先使用socket.sendto,socket.recvfrom 有时会出 ...
- Java文件下载的几种方式
public HttpServletResponse download(String path, HttpServletResponse response) { try { // path是指欲下载的 ...
- hdu 4643(计算几何)
题意:容易理解 分析:切换的地点为两个基站所在直线的中垂线与两座城市所在直线的交点. 代码实现: #include <cstdio> #include <cmath> #inc ...
- 有关loading share object file libjvm.so: xxxxx 的那些问题
今天在跑一个有关postgresql产品的测试,要测试postgresql的有关Mirroring Controller的功能. 在执行mc_ctl命令的时候,报错:error while loadi ...
- 怎样为EXCEL2010添加下拉列表
注意,下面是Excel2010的步骤和截图,其他版本的Excel类似. 首先用鼠标左键点击你要添加下拉列表的单元格. 如果你只想部分区域有下拉列表,也可以选择部分区域. 下面图片是选择的整个列都是 ...
- 【Linux】Mutex互斥量线程同步的例子
0.互斥量 Windows下的互斥量 是个内核对象,每次WaitForSingleObject和ReleaseMutex时都会检查当前线程ID和占有互斥量的线程ID是否一致. 当多次Wait**时就 ...
- 如何配置仿真器DM8127+SEED-XDS560v2PLUS和连接不上的问题的解决
1 根据配置焊接JTAG电路转接板.我用的是14pin的. 2 安装仿真器驱动.安装完如下图 我安装的时候没有自动装上,第一次显示问号,后来手动的. 3 设置ccs工程 4 最后调试是这个样子 5 查 ...
- (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...