30天备战Magento认证考试二

Day 2 Continued

Explain how Magento loads and manipulates configuration information

Magento的配置基本上散布在很多个.xml文件中,那么很自然地就有一个疑问,Magento是如何操作这些文件又从而为每个插件找到相应的配置文件的呢?下面我们先来梳理一下Magento结构的核心要点:

• Magento是一个模块化系统,功能分布在各个模块中;

• 有三个代码池,分别是local, community和core;

• 每个模块中包含app/code/[codePool]/Namespace/Modulename/config.xml (该文件 中存放基本模块配置)和app/etc/modules/Namespace_Modulename.xml (该文件存放代码池信息以及插件激活标记);

• Magento安装时的全局配置(包括数据库连接系统和后台地址)存放在app/etc/config.xml和app/etc/local.xml文件中;

如是我们从index.php开始追踪代码的话,会看到如下内容(在1.9.*的index.php中未找到这部分内容,使用的是Mage::run($mageRunCode, $mageRunType)):

Mage::run()
        self::$_config = new Mage_Core_Model_Config($options); (in CE 1.6.* and previous versions)
        self::_setConfigModel($options); (in СE 1.7.*)
        self::$_app    = new Mage_Core_Model_App();
        self::$_app->run(…);

或者

Mage::app()
        self::$_app    = new Mage_Core_Model_App();
        self::$_app-> init (…);

之后在两个版本中都有相似的类方法加载顺序。在Mage::run()中所有处理配置加载的内容都在Mage_Core_Model_App中并引用Mage_Core_Model_Config方法。调用Mage::app()会立即调用Mage_Core_Model_Config::init(),其中包含配置加载的进程。
最后会到达Mage_Core_Model_Config, 继承自Mage_Core_Model_Config_Base和Varien_Simplexml_Config。在这个层面调用方法无关紧要,让我们一起来看看Mage_Core_Model_Config:: init()方法(app/code/core/Mage/Core/Model/Config.php):

<?php /** * Initialization of core configuration * * @return Mage_Core_Model_Config */ public function init($options=array()) { // lets skip cache init and non-standard options stuff $this->loadBase();
        $cacheLoad = $this->loadModulesCache();
        if ($cacheLoad) {
            return $this;
        }
        $this->loadModules();
        $this->loadDb();
        $this->saveCache();
        return $this;
    }

让我们来逐行分析一下这个方法吧

$this->loadBase();

    /**
     * Load base system configuration (config.xml and local.xml files)
     *
     * @return Mage_Core_Model_Config
     */
    public function loadBase()
    {
        $etcDir = $this->getOptions()->getEtcDir();
        $files = glob($etcDir.DS.'*.xml');
        $this->loadFile(current($files));
        while ($file = next($files)) {
            $merge = clone $this->_prototype;
            $merge->loadFile($file);
            $this->extend($merge);
        }
        if (in_array($etcDir.DS.'local.xml', $files)) {
            $this->_isLocalConfigLoaded = true;
        }
        return $this;
    }

在最前面定义了一具app/etc目录的绝对路径,然后获取了此目录下的.xml文件列表,读取其中的内容并并入一个simpleXmlElement对象中。如果local.xml文件被载入了的话(也就意味着Magento已经完成了安装),则设置$this->_isLocalConfigLoaded = true;这会在后面用于实例化店铺并加载模块设置脚本。

只要这个方法不限制名称和载入文件数量,我们就可以在需要时载入app/etc中的自定义.xml文件。在开发服务器上不通过local.xml文件来指定数据库连接信息会比较有帮助,只使用该文件包含生产服务器的信息

<?php $cacheLoad = $this->loadModulesCache();
        if ($cacheLoad) {
            return $this;
        }

这部分代码不言自明,如果配置中激活了缓存并包含所要求的内容,就加载整个配置。我们还会用这一配置替换app/etc中已载入的配置,从缓存中载入(Mage_Core_Model_Config:: loadCache())并返回到Mage_Core_Model_App。

您可能会问如果所有的配置都能从缓存中载入,为什么不在扫描app/etc目录前就进和这一验证呢?因为Magento的缓存不仅可作为文件存放在var/cache中,也可以存放在apc, memcached和xcache中。从app/etc中载入的步骤允许设定用于存储缓存的类型和配置。

接下来是加载最为广泛的配置部分-模块配置。

$this->loadModules();

    /**
     * Load modules configuration
     *
     * @return Mage_Core_Model_Config
     */
    public function loadModules()
    {
        Varien_Profiler::start('config/load-modules');
        $this->_loadDeclaredModules();
 
        $resourceConfig = sprintf('config.%s.xml', $this->_getResourceConnectionModel('core'));
        $this->loadModulesConfiguration(array('config.xml',$resourceConfig), $this);
 
        /**
         * Prevent local.xml directives overwriting
         */
        $mergeConfig = clone $this->_prototype;
        $this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
        if ($this->_isLocalConfigLoaded) {
            $this->extend($mergeConfig);
        }
 
        $this->applyExtends();
        Varien_Profiler::stop('config/load-modules');
        return $this;
    }

Day 3

$this->_loadDeclaredModules();

_getDeclaredModuleFiles(): 首先扫描app/etc/modules目录获取指向系统所有模块的.xml文件路径列表。建立一个以base, mage和custom为键名的关联数组,仅有Mage_All.xml路径指向base版块,而Magento的基础包(core代码池app/code/core/Mage下)指向mage版块,custom版块涵盖其它的模块。最终会将所有内容并入一个数组,由于前面按键名拆分,最终数据的存储顺序是: Mage_All.xml, Mage命名空间里的模块,其它所有模块。

如果还没有明白Mage_All.xml的重要性的话,现在应该查看其中的内部结构了。Mage_All.xml包含了所有保证系统正常运行需要加载的模块。

然后collected.xml文件会加载到Mage_Core_Model_Config_Base $unsortedConfig。就会获得一个$moduleDepends数组,它是基于<depends>, <active>标记和模块名称。

$this->_sortModuleDepends($moduleDepends)在查看现存模块间的依赖性时会用到,在验证后会形成一个按照模块依赖关系排序的新的数组。

在_loadDeclaredModules()的最后会再次创建一个simpleXmlElement对象,并合并入前面创建的app/etc/*.xml中。

下面我们再加到loadModules()方法中:

<?php $resourceConfig = sprintf('config.%s.xml', $this->_getResourceConnectionModel('core'));
        $this->loadModulesConfiguration(array('config.xml',$resourceConfig), $this);

$resourceConfig中包含 config.mysql4.xml内容,因而下一步会载入config.mysql4.xml的配置以及config.mysql4.xml文件本身,目前尚不清楚config.mysql4.xml具体有什么作用。

这个方法首先会检测是否可以从local代码池中加入模块(注意app/etc/local.xml中false的值是否为true)。如果只允许使用community和core中的模块,Magento也会相应地修改include_path()。

<?php
        if ($disableLocalModules && !defined('COMPILER_INCLUDE_PATH')) {
            set_include_path(
                // excluded '/app/code/local'
                BP . DS . 'app' . DS . 'code' . DS . 'community' . PS .
                BP . DS . 'app' . DS . 'code' . DS . 'core' . PS .
                BP . DS . 'lib' . PS .
                Mage::registry('original_include_path')
            );
        }

通过这个简短的验证,Magento确保有一些simpleXmlElement设置(没有的话Magento会自动创建),然后会删除载入的配置为false和local的模块。
接着config.xml中剩余的模块以及config.mysql4.xml文件会被加载,然后loaded .xml会被加入到现有的文件中。如果最后加载的文件包含老的xpath, 系统会使用最后的值。

以前用$this->applyExtends();的调用配合自定义插件来改变/重载配置中的数据,但后续版本中并未采用。如果您已看到这部分的话,请仔细阅读一下下面的代码吧:

<?php /** * Prevent local.xml directives overwriting */ $mergeConfig = clone $this->_prototype;
        $this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
        if ($this->_isLocalConfigLoaded) {
            $this->extend($mergeConfig);
        }

不操作模块的话可以通过修改app/etc/local.xml中的数据,最后,调用$this->loadDb();方法

<?php /** * Load config data from DB * * @return Mage_Core_Model_Config */ public function loadDb() { if ($this->_isLocalConfigLoaded && Mage::isInstalled()) {
            Varien_Profiler::start('config/load-db');
            $dbConf = $this->getResourceModel();
            $dbConf->loadToXml($this);
            Varien_Profiler::stop('config/load-db');
        }
        return $this;
    }

这个方法使用了和core_config_data table相关的Mage_Core_Model_Resource_Config model模型资源,在这步我们从core_config_data载入数据到配置中:

1. 向站点中加入数据(查看core_website table)
2. 为现有站点加入各商店(store)数据(查看core_store table)
3. 根据域(scope)向core_config_data中加入数据
a. 先创建<default>块
b. 再创建<websites>块
c. 最后创建<stores>块
d. 每次迭代把域中的基本数据替换成更具针对性的数据 (还记得后台中的«use default», «use website»和«configuration scope» 吗?)
4. 自身配置 (如果遇到与现有网站不相关的数据,会进行删除)。

紧接着如果使用了缓存的话就会向缓存中写入配置。现在配置已经生成,但除了编译.xml文件外,我们还经常要从中读取数据,那么让我们回到Mage.php中查看相关方法:

<?php /** * Retrieve config value for store by path * * @param string $path * @param mixed $store * @return mixed */ public static function getStoreConfig($path, $store = null) { return self::app()->getStore($store)->getConfig($path);
    }
 
    /**
     * Retrieve config flag for store by path
     *
     * @param string $path
     * @param mixed $store
     * @return bool
     */
    public static function getStoreConfigFlag($path, $store = null)
    {
        $flag = strtolower(self::getStoreConfig($path, $store));
        if (!empty($flag) && 'false' !== $flag) {
            return true;
        } else {
            return false;
        }
    }

两个方法的唯一差别是 getStoreConfig() 会返回具体的值,而getStoreConfigFlag() 仅返回布尔值true或false。两个方法最终都调用Mage_Core_Model_Store::getConfig()方法:

<?php /** * Retrieve store configuration data * * @param string $path * @return string|null */ public function getConfig($path) { if (isset($this->_configCache[$path])) {
            return $this->_configCache[$path];
        }
 
        $config = Mage::getConfig();
 
        $fullPath = 'stores/' . $this->getCode() . '/' . $path;
        $data = $config->getNode($fullPath);
        if (!$data && !Mage::isInstalled()) {
            $data = $config->getNode('default/' . $path);
        }
        if (!$data) {
            return null;
        }
        return $this->_processConfigValue($fullPath, $path, $data);
    }

如果请求的信息无法在本地缓存中找到,该方法会使用stores/[store code]/[requested path]路径查找,如果依然没有结果,会使用另一个路径default/[requested path]在加载的配置中搜索。如果未查找到,则返回null。

查找到的数据由_processConfigValue()方法来进一步处理:

• 如果返回的是子节点,数据会循环存入本地缓存中。用户在当前会话再次调用时无需重新到配置中查找数据。
• 如果节点包含backend_model, 这个模型应按照指定格式获取数据。
• {{unsecure_base_url}}, {{unsecure_base_url}}, {{base_url}}的变量将由对应的数据进行替换。

最后总结一下

1. 所有.xml文件会汇集到一个大的simpleXmlElement 对象中

2. 数据首先从app/etc/*.xml中载入然后是app/etc/modules/*.xml。基于需加载模块的信息,会载入各模块etc目录下的config.xml。如果载入后台检测ACL权限并创建菜单元素,同时还会加载adminhtml.xmlsystem.xml。最后一步才是从数据库中载入配置数据。

3. 除开app/etc/local.xml中的其它所有参数都可以在自建模块的config.xml中进行重载。

P.S. 虽然Magento中提供了便捷的Mage:: getStoreConfig()Mage:: getStoreConfigFlag()方法,我们还是可以通过Mage::getConfig()->getNode($path, $scope, $scopeCode);来获取配置树中的任意元素。

可通过在根目录下运行如下代码来查看Magento安装后的最终配置信息:

<?php header("Content-Type: text/xml"); define('MAGENTO_ROOT', getcwd()); $mageFilename = MAGENTO_ROOT . '/app/Mage.php'; require_once $mageFilename; umask(0); /* Store or website code */ $mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : ''; /* Run store or run website */ $mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store'; Mage::app($mageRunCode, $mageRunType); $config = Mage::getConfig()->getNode()->asXml();
//file_put_contents('config.xml', $config);
echo $config;

Describe class group configuration and use in factory methods

Magento通过工厂方法来实例化..

 

注:考虑到时间的紧迫性,决定内容在后续补入,目前仅录入学习进度,上班族伤不起啊!!!

Describe the process and configuration of class overrides in Magento

Register an Observer

Identify the function and proper use of automatically available events, including *_load_after, etc.

Day 4

Set up a cron job

Describe how to plan for internationalization of a Magento site

Describe the use of Magento translate classes and translate files

Describe the advantages and disadvantages of using subdomains and subdirectories in internationalization

Day 5

Describe the steps for application initialization

Describe the role of the system entrypoint, index.php

Describe the role of the front controller

Identify uses for events fired in the front controller

Day 6

Describe URL structure/processing in Magento

Describe the URL rewrite process

Describe request routing/request flow in Magento

Describe how Magento determines which controller to use and how to customize route-to-controller resolution

Day 7

Describe the steps needed to create and register a new module

Describe the effect of module dependencies

Describe different types of configuration files and the priorities of their loading

Identify the steps in the request flow in which

1. Design data is populated

2. Layout configuration files are parsed

3. Layout is compiled

4. Output is rendered

30天备战Magento认证考试一

Day 1

使用Magento有挺长一段时间,但一直都限于泛泛的一些见招拆招的小功能,之前也参照Alan Storm的博客写过有关Magento开发的系列教程,不过在开发上实在没有什么更进一步的发展。于是决定通过备考Magento认证考试来进一步了解Magento的结构,从业余向专业过渡。

Magento开发系列之一 基础知识

Magento开发系列之二 配置文件

Magento开发系列之三 控制器

Magento开发系列之四 布局、块和模板

Magento开发系列之五 模型和ORM基础

Magento开发系列之六 安装、升级脚本

Magento开发系列之七 EAV-更高级的ORM

Magento开发系列之八 后台配置开发

Magento开发系列之九 后台开发进阶

Magento开发系列之十 Varien数据集合

Magento开发系列之十一 数据重载和升级

Magento开发系列之十二 默认系统配置

这次的计划是在年底前参加考试,大约一个月的准备时间,于是有了30天备战Magento认证考试的标题,难度还是挺大的,不管成功或者失败,都希望在本文中进行真实的记录为更多参加Magento认证考试的人们所参考。

由于一直没有机会接触Magento的Enterprise版,所以本次计划参加的考试为Magento Certified Developer Exam而不是Plus,官方的大纲如下:
链接: http://pan.baidu.com/s/1jGCnR8a 密码: sw6u

Basics

Describe Magento codepools

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模板下的文件夹结构:

Magento Checkout模块下面我就来一一了解Magento中的模块组成

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文件。

Magento下skin文件夹内容结构

js文件夹存放在前台和后台中使用的js文件,库文件和框架文件。如果要添加一个新的Javascript/AJAX库或者local代码池中要用到一些特殊的脚本,那么就都放到这里。

Magento根目录js文件夹下文档结构

Identify and explain the main Magento design areas (adminhtml and frontend)

Magento模板系统都由三个组件构成,有存储在叫做Block的模块文件夹中的php类,它们从数据库中加载数据并传输到主题PHP/HTML模板文件中(.phtml)。也有构建页面结构和组成部分的XML配置文件。

Magento的design目录结构

所有的前台文件都存放在图示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?

主题文件夹结构:

Magento主题文件夹结构

skin文件夹结构

Magento skin文件夹结构

Explain how Magento loads and manipulates configuration information