Day 1
使用Magento有挺长一段时间,但一直都限于泛泛的一些见招拆招的小功能,之前也参照Alan Storm的博客写过有关Magento开发的系列教程,不过在开发上实在没有什么更进一步的发展。于是决定通过备考Magento认证考试来进一步了解Magento的结构,从业余向专业过渡。
这次的计划是在年底前参加考试,大约一个月的准备时间,于是有了30天备战Magento认证考试的标题,难度还是挺大的,不管成功或者失败,都希望在本文中进行真实的记录为更多参加Magento认证考试的人们所参考。
由于一直没有机会接触Magento的Enterprise版,所以本次计划参加的考试为Magento Certified Developer Exam而不是Plus,官方的大纲如下:
链接: http://pan.baidu.com/s/1jGCnR8a 密码: sw6u
Basics
Describe Magento codepools
代码池在Magento根目录的app/code目录下,通常有系统自带的core代码池(可以拷贝到local文件夹中再进行相应的更改),通常不建议直接修改core代码池中的代码;第三方开发、共享插件(如Magento Connect)等使用的community代码池以及本地开发的local代码池。
那么系统是如何与各代码池进行交互的呢?
可以查看一下app/Mage.php文件中如下代码:
/** * Set include path */ $paths = array(); $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core'; $paths[] = BP . DS . 'lib'; $appPath = implode(PS, $paths); set_include_path($appPath . PS . Mage::registry('original_include_path')); include_once "Mage/Core/functions.php"; include_once "Varien/Autoload.php";
从这段代码中我们可以看出Magento中的加载顺序,即先是local代码池,然后community代码池,最后才是core代码池,也正是因为如此,我们可以在开发时通过重载来修改core中的类。
Describe typical Magento module structure
在Magento中通常一个模块会包含 Controller, Model, Helper, Block等目录,比如app/code/core/Mage/Checkout模板下的文件夹结构:
Block
Block文件夹对应MVC中的View,块文件通过模板文件调整模型,该目录下的文件载入数据库的数据并传给主题中的.phtml模板文件。
Controllers
控制器代表给定请求(如dispatch(), preDispatch(), postDispatch()等方法)的所有业务逻辑动作,并向系统其它部分传递命令。
etc
etc文件夹中包含所有声明和配置模块行为的xml文件,每个模块都至少要包含一个config.xml文件,在这里可以声明所有的model, router, block和helper等,该文件类似:
<config> <modules> <Namespace_Modulename> <version>0.1.0</version> </Namespace_Modulename> </modules> </config>
Helper
Helper包含一些在整个系统常用到的一些工具方法,在helper中声明的方法,可以在模板文件或block, model, controller类中通过如下方式调用
Mage::helper('modulename/helpername')->methodName();
每个模块都有一个默认的Data帮助类(Modulename/Helper/Data.php),可以通过如下方式调用:
Mage::helper('modulename')->methodName();
Model
在传统的MVC中,Model用于连接数据库并从中读取或写入数据。在Magento中却并非如此,刚开始用时可能会不明就里,官方如是说:
Most Magento Models can categorized in one of two ways. There’s a basic, ActiveRecord-like/one-object-one-table Model, and there’s also an Entity Attribute Value (EAV) Model. Each Model also gets a Model Collection. Collections are PHP objects used to hold a number of individual Magento Model instances. The Magento team has implemented the PHP Standard Library interfaces of IteratorAggregate and Countable to allow each Model type to have it’s own collection type. If you’re not familiar with the PHP Standard Library, think of Model Collections as arrays that also have methods attached. Magento Models don’t contain any code for connecting to the database. Instead, each Model uses two modelResource classes, (one read, one write), that are used to communicate with the database server (via read and write adapter objects).
sql
处理所有在模板中使用的自定义数据表以及所有插件的升级。
etc/modules/Namespace_Modulename.xml
想要知道应使用哪些模块以及它们的位置,需要在所有xml文件的etc/modules/文件夹中创建一个xml文件
<?xml version="1.0"?> <config> <modules> <Namespace_Modulename> <active>true</active> <codePool>local</codePool> </Namespace_Modulename> </modules> </config>
还可以在模块config.xml中指定depends, version和platform等参数:
Depends
<depends> <Mage_Catalog /> </depends>
Version
<version>0.1.0</version>
Platform
<platform>сe</platform> <!-- (ce=community edition,pe=professional etc.) -->
Day 2
Describe Magento templates and layout files location
一个主题通常包含如下元素
layout文件夹中包含用于定义主题布局的XML文件,这些文件就如同连接module(app/code目录下)和模板文件的胶水一样。
由于Magento的模块特性,默认主题的所有XML文件都存储在以模块名命名的单独文件夹中。而非默认主题,则会存放在所有布局更新所使用的local.xml文件中。
template文件夹中存放显示在前台的各Magento block用到的.phtml文件,该文件中包含php和html代码
locale文件夹中按语言存放.csv文件,命名规则为languagecode_COUNTRYCODE/translate.csv,如en_US或en_UK/translate.csv
Describe Magento skin and JavaScript files location
skin文件夹中包含模板文件夹下.phtml文件所使用到的Javascript, CSS和图片文件,也就是说这个文件夹下的内容每个主题都是不同的。从下图中可以看到其中包含三个文件夹,CSS文件夹中存放主题用到的层叠样式表,images文件中存放主题使用的媒体文件,JS文件夹中存放模板用到的Javascript文件。
js文件夹存放在前台和后台中使用的js文件,库文件和框架文件。如果要添加一个新的Javascript/AJAX库或者local代码池中要用到一些特殊的脚本,那么就都放到这里。
Identify and explain the main Magento design areas (adminhtml and frontend)
Magento模板系统都由三个组件构成,有存储在叫做Block的模块文件夹中的php类,它们从数据库中加载数据并传输到主题PHP/HTML模板文件中(.phtml)。也有构建页面结构和组成部分的XML配置文件。
所有的前台文件都存放在图示design目录下的三个的文件夹中。
install 此文件夹存放安装过程中需使用到的内容
adminhtml 登录admin后台所看到的所有内容都放在这里。也就说如果模块需要用到任何与admin面板有关的内容,都可以在这里找到对应的模板和布局文件。
frontend 所有访客在前台看到内容都存放在这里。
那么完整的主题结构是什么样的呢?
Package
安装完Magento社区版后,会有两个包:base和default(后续版本中还有rwd),企业版中的名称为base和enterprise。
Themes
主题由一系列的layout, template, locale和skin文件组成,也就是网站的对外展示部分。Magento中可以加载多个主题,而主题可以分类两大类:
- Default theme
每个包都会有一个叫做default的主题,Magento会自动搜索default主题并载入到前台中使用。要想要改变前台,可以个性化default主题或开发非默认主题,显然后者更为可取。
- Non-default theme
非默认主题在default基础上进行修改或者通过CSS, 布局文件等形成完全不同的展现。
Explain class naming conventions and their relationship with the autoloader
Magento是在Zend框架的基础上进行开发的,所以其类的命名规则也取自Zend Framework。Magento中根据文件位置来对类名进行标准化,这样有助于类的自动加载(autoloader),而无需逐一require_once和include_once来包含文件。由于/在类名中属于非法字符,会使用下划线_来进行替代。
比如说Mage_Catalog_Model_Product类就在app/code/core/Mage/Catalog/Model/Product.php文件当中,Magento的autoloader将路径中的斜杠/全部替换成了下划线_,并在下面的文件夹中进行查找
app/code/core
app/code/community
app/code/local
lib/
注:app/code/local可通过将app/etc/local.xml文件中的如下字段设置为true来取消使用:
<disable_local_modules>false</disable_local_modules>
关于分类的搜索顺序,前面有提到是通过app/Mage.php文件中的如下代码来实现的
/** * Set include path */ $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community'; $paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core'; $paths[] = BP . DS . 'lib'; $appPath = implode(PS, $paths); set_include_path($appPath . PS . Mage::registry('original_include_path')); include_once "Mage/Core/functions.php"; include_once "Varien/Autoload.php";
Varien_Autoload类用于自动加载(lib/Varien/Autoload.php):
class Varien_Autoload { ... /** * Register SPL autoload function */ static public function register() { spl_autoload_register(array(self::instance(), 'autoload')); } /** * Load class source code * * @param string $class */ public function autoload($class) { ... $classFile = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $class))); ... $classFile.= '.php'; return include $classFile; }
在Magento中创建对象
Magento提供了特别的方法用于创建model, helper和block,使用缩短了类名的Mage全局类。例如,获取Mage_Catalog_Model_Product模型,常会使用Mage :: getModel (‘catalog / product’)。
catalog – Mage_Catalog_Model的缩写
product – 用于决定用到的类
类名与缩写的名称的关联发生在模块的配置文件中(…/etc/config.xml)
<!--?xml version="1.0"?--> <!-- a shortened name --> Mage_Catalog_Model <!-- a shortened name --> Mage_Catalog_Block <!-- a shortened name --> Mage_Catalog_Helper
Describe methods for resolving module conflicts
首先需要确定是什么类型的错误,然后才能找到相对应的方案。一般有三种模块兼容性错误。
1) Conflicts in configuration files
2) Conflicts with the software part
3) Conflicts in a module display
Conflicts in configuration files
我们来讨论一下配置文件错误产生的原因以及解决方法。第一步查看位于app/etc/modules文件夹下的模块定义文件。在该文件中会设置模块是否active以及所属的代码池,另外还可以通过<depends></depends>标签对来设置依赖关系。
比如有两个模块使用同样的类依赖关系的话,可能会由于类构造器的不当使用而产生冲突。这类错误与后面会讲到的软件部分错误有着紧密的关联。如果遇到因<depends>的不当使用产生错误,可以通过设置其中一个依赖于另一个类,并在稍后的类继承中使用该依赖关系。方法为:
a) 将如下代码:
Namespace_OtherModulename.xml
<config> <modules> <Namespace_OtherModulename> <active>true</active> <codePool>community</codePool> <depends><Mage_Something/></depends> </Namespace_OtherModulename> </modules> </config>
Namespace_Modulename.xml
<config> <modules> <Namespace_Modulename> <active>true</active> <codePool>community</codePool> <depends><Mage_Something/></depends> </Namespace_Modulename> </modules> </config>
b)替换为如下代码:
Namespace_OtherModulename.xml
<config> <modules> <Namespace_OtherModulename> <active>true</active> <codePool>community</codePool> <depends><Mage_Something/></depends> </Namespace_OtherModulename> </modules> </config>
Namespace_Modulename.xml
<config> <modules> <Namespace_Modulename> <active>true</active> <codePool>community</codePool> <depends><Namespace_OtherModulename/></depends> </Namespace_Modulename> </modules> </config>
Conflicts with the software part
前面提到过产生模块错误的主要原因能过是依赖关系和类rewrite造成的。这应该查看模块配置文件 (/Namespace_Modulename/etc/ config.xml), 这里可以通过<rewrite></rewrite>标签对来进行类重写,比如:
<customer> <rewrite> <form_edit>Namespace_Modulename_Block_Rewrite_BlockClass</form_edit> </rewrite> </customer>
Namespace_Modulename/etc/config.xml
<customer> <rewrite> <form_edit>Namespace_Modulename_Block_Rewrite_BlockClass</form_edit> </rewrite> </customer>
Namespace_OtherModulename/etc/config.xml
<customer> <rewrite> <form_edit>Namespace_OtherModulename_Block_Rewrite_BlockClass</form_edit> </rewrite> </customer>
1) 第一步删除第一个模块中的重写,代码如下:
<customer> <rewrite> <form_edit>Namespace_Modulename_Block_Rewrite_BlockClass</form_edit> </rewrite> </customer>
2) 使用第一个类继承第二个类:
Class Namespace_Modulename_Block_Rewrite_BlockClass extends Namespace_OtherModulename_Block_Rewrite_BlockClass
尽管这一方法非常灵活,但却有着一些缺点,比如需要仔细查看这两个类中的相同函数,可能会存在返回值和parent::functionName();方法使用的问题。但这仍是在代码层面解决模块错误的重中之重。
Conflicts in a module display
在使用多个模块时最常见的错误是在前端显示模块的错误,发生这一错误有几个原因:在布局设置中的block重载,对同一block应用不同的模板,删除另一个模块中要内嵌的block。那么让我们来进一步看看会发生模块错误的地方:
主题配置文件:app/design/frontend/default/your_theme/layout
模板文件:app/design/frontend/default/your_theme/template
如果模块在前端不展示或者显示错误,极有可能错误就发生在这些地方。
首先查看你的文件和其它模块用于前台显示设置的模块文件,位于app/design/frontend/default/your_theme/layout。如果多个模块使用相同的block却应用了不同的模板,就需要修改为只使用一个模板。可在这个模板文件中并入其它去除掉的模板的代码。
另一个常见错误是把模块标准block的名称给修改了,这时其它通过<reference></reference>标签对使用这一block的模块就会出错。还有一些情况,模块使用了自己的模板却与其它模块不太兼容,这时就要具体情况具体对待了。
How does the framework interact with the various codepools?
我们在前面已经不止一次的提到,Magento会先包含local代码池,其次community,最后才是core代码池。通过这一顺序可以让开发人员在不直接修改core中的文件的情况下实现系统类的重载。
Core代码池
这个文件夹中存放着所有实现Magento强大、灵活的功能的核心代码,强烈建议不要修改其中的代码。
Community代码池
该文件来为第三方开发者所提供,所有第三方开发的插件代码默认都会存放在app/code/community文件夹中。
Local代码池
如果您想要自己对网站进行调整、想要修改某些逻辑或者重载系统中的类,都可以在local代码池中实现。
What constitutes a namespace and a module?
命名空间或者说工厂名请首字母大写这样有助于Autoloader的加载
What does the structure of a complete theme look like?
主题文件夹结构:
skin文件夹结构
Explain how Magento loads and manipulates configuration information