0

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

Posted by Alan on August 16, 2015 in Coding, Magento |

本节并没有太多新内容,更多的是对前面有关系统后台配置的补充。在我们创建新的系统配置路径时,Magento并没有存储默认值,甚至对于一些系统默认配置也是如此,这点可以通过查看core_config_data表来进行验证。 这张表仅存储在后台或基它程序中明确设置的值,而如果请求一个没有进行这个设置的系统配置值的话,Magento会到全局配置文件中去查看默认值。虽然不要求这么做,但为自添加配置变量设置一个默认值是一个不错的习惯。这样做很简单,也防止在获取到空值时产生一些意想不到的效果。 上面提到默认值存放在全局配置文件中,这可能与很多的想法大相径庭,因为大家可能会认为这默认值会存储在用于配置后台的system.xml文件中。为什么要这么做其实大可不必深究,我们可以理解为配置文件中存储常用的值,而stystem.xml中存储着用于修改这些值的界面的配置。 在模块配置文件config.xml里添加一个<default />代码块(如app/code/local/Packagename/Modulename/etc/config.xml) 这就是我们用于存储默认值的最上级节点,接下来将配置路径转化成XML格式的树形节点,比如我们为以下配置路径设置默认值: 那么在config.xml的代码就会是这样: 应用了这个配置后,请求design/header/welcome时,如果没有设定值,就会返回”Default welcome msg!”。这个例子是基本系统默认的配置,我们业看看design/header/welcome的真实配置(文件地址:app/code/core/Mage/Page/etc/config.xml): 这是所有design/*的默认配置,和我们例子中不同的时这里有一个translate属性: translate和module属性告诉系统哪些节点需要被translate,以及使用哪个模块的Data Helper来进行这一操作。在上例中,welcome节点将被转化为: 前面我们也提到过,如果调用helper类时URI没有传入第二部分,会默认使用data,也就是说下面两句代码是一样的: 如果想要转化多个子节点,可以在名称之间用逗号进行分隔,如: 写在后面 本系列更新到此结束,一共十二篇,大多数代码并非出自笔者之手,而是来自Magento资深大师Alan Storm,笔者只是用自己的理解丰富了一下内容,以有助于国内Magento学习者更为有效地掌握Magento开发相关知识。本系列的终结只是一个阶段性的符号,Magento作为一套强大的电商系统还有很值得探讨和学习的地方,需要大家共同努力去研究和分享,让我们一起努力吧!

Tags: , , ,

0

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

Posted by Alan on August 16, 2015 in Coding, Magento |

在Magento经常被鼓吹也常被滥用的功能就是重载core中的系统代码,而另一个开发者经常讨论的话题就是升级以及重载对升级的阻碍作用。本节我们就来一起看看重载给版本切换所带来的不便。 需要强调下我们这里的是修改Maento中core的业务逻辑,对于phtml模板文件的修改是非常普遍的。 不论是在Magento中还是其它系统中对升级最不友好的肯定是直接修改源代码,比如想要修改产品模型时,就直接编辑了如下文件: 一旦这么做,就直接修改Magento中的基础代码,因而在进行升级时就需要进行逐个文件的合并,这通常都会出问题。此外这种修改还可能返回系统无法识别的数据或者是得到计划外的数据。虽然我们不建议去修改源代码,但还是有很多开发者在刚开始时会去这么做。在开发新项目时可以从官网下载一份全新的系统文件,然后比对下lib和app/code/core文件夹内的代码,看看核心代码有没有被修改。 Magento或者说PHP会在下面的目录中搜索类文件 由于这个原因以及PHP构造时包含的顺序,在core/code/local中复制一个core文件系统就会先包含这个文件,所以如果想要修改产品模型的功能,就可以进行如下复制: 如果这里定义的是类而不是core文件,就无需包含核心文件,这也就避免了合并文件的麻烦,并且所有修改文件都会放在同一个目录结构中。这样虽然比直接修改核心源代码要好些,但还是有可能会修改掉一些重要方法,比如前面说到的产品模型中的getName方法 在对这个方法进行重载时,我们有可能不小心添加了代码导致重载后返回空 系统的其它部分可能会使用到这个方法并等待该方法返回一个字串,而我们的修改则会导致接下来的执行被中断。这里如果返回对象情况还会更糟,因为调用一个空方法会导致一个致命错误(Fatal)。 下面我们来看看同一模型中的validate方法 在修改时我们有可能不小心删除了dispatch事件 这时系统中其它依靠这一事件的部分都会停止运转。此外,在升级时同样存在着危险,如果升级中更新了类,而我们仍将使用旧的过时了的方法。也就是说我们还是需要在升级时进行手动的代码合并。 Magento中的类重载和系统重写依赖于创建模型、Helper和Block时使用的工厂模式,比如在执行如下代码时: 实际是在告诉Magento去查找catalog/product用到的类并进行实例化。接下来,Magento会付出查看系统配置文件,并在config.xml中查看针对catalog/product应该使用哪个类,然后Magento就会对类进行实例化并返回一个模型。 而当我们在Magento中重载一个类时,实际上修改了配置文件,在进行上述操作时,就会告诉系统:如果要实例化catalog/product模型的话,请不要使用core中的类,而使用我们定义的类Myp_Mym_Model_Product 同时,在定义我们自己的类时,需要继承原来的类 这样,我们的新类就会包含系统类中的功能,同时也就避免了在升级时还需要合并文件的功能,也不会在升级时包含过时的方法。但是在修改方法时还是存在问题,我们还是以getName和validate方法为例,我们还是会忘记返回值或返回错误的值,甚至是忘记添加方法中重要功能的代码块: 重载重写系统无法在这个层面上形成保护,但也提供了一些避免的方式。同于我们是继承了原来的类,因而可以在构造时使用parent::来调用原类中的方法: 通过调用原来的方法,就可以确保该进行的操作都会完成,并且也减少了返回非系统要求值的可能性。当然只能是减少,而非彻底消除,开发者还是需要负责在自建代码中返回和原方法相同的对象或其它值。也就是,即使应用了重载系统,系统还是可能会由于误操作导致崩溃。 鉴于此,我们在进行开时,应使重载最小化,重载时可以在最后添加如下代码: 如果重载时要求先运行原方法,可以使用如下方法: mymodule/immutable指向如下类 这样并不能保证$original_return不会被我们自己或其它人重写,但确实会在修改后更容易发现。如果在重载类的方法最后没有使用$original_return->getValue或parent::method,那么在debug时就很容易发现问题。 还有的时候我们会希望修改core方法中的返回值,在有这种需求时,定义一个新方法来调用原方法并在主题中调用新方法往往更为安全: 这样可以保证原方法的一些功能依然有用,原来的返回类型保持不变,而我们也可以在系统中的某些地方添加自己的逻辑。

Tags: , , , ,

0

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

Posted by Alan on August 15, 2015 in Coding, Magento |

早期PHP开发者如果想要将一组相关的变量放在一起,只能通过数组,虽然和C语言的内存地址数组同名,PHP的数组更多的是一个对象加序列索引的数组行为组成的通用字库。在其它语言中都有多种数据结构,每种结构在存储、速度和语法上有不同的优势。PHP语言的逻辑是减去这些选择而仅使用一种有用的数据结构即可。从PHP 5开始通过提供内置类和接口来让开发者允许创建自己的数据结构。 一些软件工程师肯定还不满足于此,因为没有获取到底层实现的细节,但已经获得包含特定功能的方法来创建类似数组的对象。也可以设定一定的安全规则来只允许某些类型的对象进行集合,Magento中包含一些这种集合,事实上每个遵循Magento接口的模型对象都会获得一个集合类型。要成为有效的Magento开发者,了解这些集合的工作机制也非常重要。本节我们就来看看Magento的集合,创建一个可以自由添加代码的控制器action。 第一步需要创建一些新的对象 Varien_Object类定义了所有Magento模型所继承的类,这面向对象的系统中这很常见,它可以保证可以轻易地为每个对象添加方法、功能而无需编辑每个类文件。每个继承Varien_Object的对象都会获得魔术方法getter和setter,这样就可以通过get和set来获取并设置数据。比如, 如果不知道要获取的属性名,可以将所有数据取出到一个数组中,如 上面的代码将返回下面这样的数组: 你可能会注意到last_name这个属性,中间是由下划线来划分的,如果想要使用getter和setter魔术方法,需要采用驼峰法来进行命名: 在较新版本的Magento中,可以使用数组形式的中括号来取得属性值: 这是PHP5中强大的功能,现在我们创建了一些对象,让我们一起来加入到集合中吧,要记得集合类似数组,但是是由PHP开发人员定义的: Magento中的数据集合通常都继承自Varien_Data_Collection,所有Varien_Data_Collection中的方法都可以被调用,对于集合我们可以用foreach函数来进行遍历 还可以通过以下方法取出集合中的第一项和最后一项: 如果想要以XML形式获取集合中的数据,可以使用如下方法 那如果只要取出指定的属性呢? Magento开发团队甚至还添加了过滤功能: 为什么要特别地讲这些东西呢?因为所有的内置数据集合都继承自这个对象,也就是说可以对产品集合等进行同样的操作,比如: Magento中大多数的模型对象都有一个getCollection方法,它可以实例化集合并返回所有系统中支持的对象类型。数据集合包含很多决定使用index还是缓存的复杂逻辑,还有针对EAV实体的一些逻辑。在同一个集合中连续多次调用同一方法可能会产生一些不可控的效果,因此下面所有的例子都是放在一个action方法中进行的,建议在独自测试时也这么做。另外var_dump对于对象和集合相当的有用,因为通常针对大规模递归的对象时,它也会很智能的显示出对象的结构。产品集合还有其它的一些Magento集合,还继承了Varien_Data_Collection_Db,这样就可以使用很有有用的方法,比如要查看集合的select语句: 输出结果如下: 看上去一头雾水,由于Magento使用了Zend数据抽象层,select也是对象,我们修改代码如下: 这次的输出结果可能是如下的这种简单SQL: 也有可能是更为复杂的语句: 这种区别主要取决于所select的属性,以及前所提到的index和cache的问题。如果学习过前面的章陈明,就知道Magento的很多模型包括产品模型使用EAV系统,默认情况下EAV集合不会包含所有对象属性,可以通过使用addAttributeToSelect方法来添加所有属性: 也可以只添加一个属性 或者多个属性: 很多刚接触Magento ORM系统的PHP开发者总是搞不清楚该在什么时候进行数据库调用。在书写SQL语句甚至是使用基础的ORM系统时,SQL调用都在实体化对象当时发生。 但在Magento中并不是这样,它使用了延时加载(Lazy Loading)的概念。简单地说,延时加载是指只有在客户端程序需要获取数据时才会执行SQL调用,也就是如果进行如下操作: Magento并没有操作数据库,因此你可以在后面再添加属性: 这里完全不用担心Magento会在每次添加属性时都去进行数据库查询,这些查询只有到了需要获取集合中的数据时才会进行。 数据库集合中最重要的一个方法是addFieldToFilter,这就添加了WHERE语句,可以使用自己的SKU也可以安装测试数据来进行如下测试: addFieldToFilter中的第一个参数就是我们想要过滤的属性,而第二个则是查询的值。本例中我们添加了sku作为过滤,值为n2610。第二个参数也可以用于指定想要过滤的类型,这个有些复杂,不过值得更深入地研究一下,所以默认情况下: 相当于 接下来运行一下如下语句: 将会得到如下结果: 注意一旦我们使用了EAV属性,就会变得更为复杂,下面添加一个属性: 输出会得到下面这样复杂的SQL语句: 那如果我们不只想要在查询中使用等号呢?比如大于、小于、不等于等等。addFieldToFilter中的第二个参数可以解决这一问题,在这里可以不传入一个字符串,而是传入一个数组。比如我们进行如下修改: 其中的过滤即为: 可以看出,第二个参数是一个数组,键为eq,表示equals(等于),而值为n2610,即为想要过滤的值。Magento中有很多半英文的过滤符号,和perl中的基本一致,下面是一些过滤方式及其对应的SQL语句: 基本上一看就能够明白,这里挑出几个特别的解释一下 in, nin in和nin条件语句中可以传入一组值,这里值的部分也可以使用数组。 notnull, null NULL类型在SQL中非常特别,不能通过等号运算符来过滤,通常使用null或notnull即可进行过滤,后面传入的值会被忽略掉 from – to 这是另外一个各其它语句不一样的格式,它传入的不是只有一对键值的数组,而是拥有两对键值,一个用于from,另一个用于to。从键名就可以猜它是用于限定一个范围的: 将会生成如下的SQL语句: 最后我们来看看布尔值操作符,我们很少会只过滤一个属性,Magento自然早已考虑到这一情况。可以通过调用多个addFiledToFilter生成AND查询 将生成如下SQL语句: 可以发现以上WHERE语句中有一个AND,当然,这条语句不会返回任何,因为sku不可能同时以a和b开头。那这种情况下我们应用使用OR语句,要这么做需要在addFieldToFilter的第二个参数处传一个过滤数组,通过定义变量来做为数组可能更为直观: […]

Tags: , , , ,

0

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

Posted by Alan on August 14, 2015 in Coding, Magento |

前面一节我们讨论了后台系统配置,本节我们将进行更深入的探讨,前面讲到了field内可以用到的一些标签: 本节将对这些标签进行更深度的剖析,首先查看<label />和<comment />标签,<label />标签中的内容将出现在文本框左侧,而<comment />标签则出现在文本框的下方 <show_in_default />, <show_in_website />,和<show_in_store /> 这几个标签内都使用布尔型的0或1,用于定义在defautl视图、website视图或store视图中是否显示所添加的field。同时通过这一配置也可以控制选项在哪个视图里是可编辑的,比如可以设定在store视图里不可用: 当然通过编辑还可以在store社图级别设定或获取其中的值,但我们不推荐这么去做。 <sort_order /> <sort_order />中传入的是数值,用于决定在分组中field的排序,数值越大,则会出现在越下面。 <frontend_type /> <frontend_type />用于定义在配置中field的类型,所支持的类型有: allowspecific export image import label multiselect obscure password select text textarea time 这些值会按照工厂模式实例如下格式的类: 其中的Type对应的就是<frontend_type />中的值,这个动作是在Varien_Data_Form_Abstract(lib/Varien/Data/Form/Abstract.php)类中addField方法内进行的 <frontend_class /> <frontend_class />不是一个类群的名称,该标签可用于修改给field生成的表单元素标签的class属性,也就是说可以通过这个配置可以为表单属性添加一个CSS的类。比如: 会在结果页面变成: <validate /> <validate />这个标签看上去会让人误解,它只是在标签中添加一个CSS类 上述代码会在结果页面变成: Magento中还有更多的配置,这个CSS会在客户端触发验证机制,比如上面的代码会调用javascript来对表单的输入内容进行email验证。如果验证失败的话,就无法完成配置表单的提交。可以在以下文件中查看验证规则: email验证规则如下: 这是一条功能很强大的正则表达式。 <can_be_empty /> <can_be_empty />标签针对多选框,也就是在提交时允许不选择任何选项。在设置can_be_empty为真时,实际上是在系统配置页面添加了一个hidden的input标签(文件地址:/lib/Varien/Data/Form/Element/Multiselect.php): 这样在执行的时候就可以允许不予选择。 <depends […]

Tags: , , ,

0

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

Posted by Alan on August 13, 2015 in Coding, Magento |

Magento系统中另一个强大的组件是后台Admin的系统配置部分,开发过程中需要让用户可以通过在后台配置系统和自建模块来进行设置。 首先创建一个app/code/local/Alanhou/Helloworld/etc/system.xml文件,和全局配置相似,系统配置信息将单独存储。如果想要查看系统配置文件 ,可以在任意控制器Action中添加如下 代码并执行(这里在前面创建的添加到Helloworld下的IndexController>indexAction方法内): loadModulesConfiguration方法会查找所有模块下的etc文件夹是否包含所传入的文件名称(这里传入的是system.xml)。Magento中实际上有很多配置文件如api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml等,开发者可以通过创建自己的配置文件来实现更多的功能。输出结果如下: 本例中我们首先将在系统配置中添加自己的选项卡,这里说的选项卡是指在后台System > Configuration下左边的导航,默认的有General, Catalog, Customers, Sales, Services和Advanced。我们将创建的选项卡名称为Hello Config,在system.xml中加入如下代码: 代码中的<helloconfig />标签名是任意选定的,但不应与其它选项卡重复,这用于标识配置应用于的选项卡。module=”helloworld”属性表示所属模块,<label>定义选项卡显示的名称。<sort_order>表示选项卡在左侧导航中显示的位置,此时访问后台System > Configuration,会出现如下报错: 和大多数流行的PHP MVC系统一样,Magento也会使用Helper类,主要用于处理一些不宜放在Model, View或Controller处理的任务。Helper类是一种抽象类群的名称,也就是说系统用户可以重载默认类,此外模块开发者也需要在config.xml中添加一个代码块来指定Helper的基类名称。 很多系统代码都会假定每个模块有个默认的Helper类,所以出现上面报错的原因是因为在Helloworld模块中并没有默认Helper类而系统尝试调用该类。所似接下来我们在config.xml里加入如下代码: 基中的<helloworld />标签就是模块名,<class />标签则包含的是Helper类的基础名称,通常按照Packagename_Modulename_Helper的方式命名。Helper通过全局Mage对象的静态方法helper来加载,以本例而言 会加载以下文件中的以下类 Magento中还有一个模块默认类的概念,比如只传入模块名时 会加载以下文件中的以下类 也就是说下面两个是等价的 下面我们在app/code/local/Alanhou/Helloworld/Helper/Data.php中加入如下代码 现在我们清除缓存重新访问System > Configuration报错就会消失,但是并不会显示新创建的选项卡。那么接下来我们就来查看为什么新的选项卡没有显示,每个选项卡中都有多个版块(Section),比如Advanced下有Admin, System, Advanced和Developer。那如果选项卡没有添加版块选项也是不显示的,下面我们就在system.xml中添加 代码段 与标签相似,<helloworld />标签也是任意命名用于标识新的section;标签定义在后台显示的名称;用于指定section添加到哪个选项卡下,这里使用了新创建的;在其它的section有着特别的作用,但在这里没有特别的意义,Core模块中的section会用到这个标签,所以建议也照旧添加这个标签;标签决定了这个版块在垂直方向上的显示顺序;<show_in_default />,<show_in_website /> ,<show_in_store /> 中传入的为布尔值1或0,表明section的作用范围。 重新访问System > Configuration,就会在左侧导航中显示新添加的选项卡和section: 如果点击左侧的Hello World Config Options,会出现空白页面,并且左侧的导航会消失,这主要是因为Adminhtml应用在ACL(Access Control […]

Tags: , , ,

0

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

Posted by Alan on August 13, 2015 in Coding, Magento |

前面关于ORM的章节我们讲述了在Magento中有两种模型,一种是普通模型,另一种是EAV(Entity Atrribute Value)模型。本节我们就来进一步的了解EAV模型。 在Magento中所有与数据库交互的模型都继承自Mage_Core_Model_Abstract, Varien_Object,而普通模型与EAV模型的区别在于模型资源。所有的资源都继承基础类Mage_Core_Model_Resource_Abstract,普通模型有一个继承自Mage_Core_Model_Resource_Db_Abstract的资源,而EAV模型则有一个继承自Mage_Eav_Model_Entity_Abstract的资源。 那么什么是EAV呢?维基百科上的解释是: Entity–attribute–value model (EAV) is a data model to describe entities where the number of attributes (properties, parameters) that can be used to describe them is potentially vast, but the number that will actually apply to a given entity is relatively modest. In mathematics, this model is known as a […]

Tags: , , ,

0

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

Posted by Alan on August 10, 2015 in Coding, Magento |

在任何高效的软件开发项目中,保持开发库和线上库同步都会是一件棘手的事情。Magento通过在系统中创建带有版本号的资源迁移脚本来让这种开发过程更加的顺畅。前面有关ORM的章节我们创建了一个weblog模型,那时我们使用CREATE TABLE语句直接在数据库中创建表格,今天通过对模块的资源配置(Setup Resource)来创建数据表。我们还会在模块中创建升级脚本来完成对已创建模型的升级。主要有以下几步: 在配置文件中添加Setup资源 创建资源类文件 创建安装脚本 创建升级脚本 我们还是在上一节创建的weblog模块中进行修改,在config.xml的<global />标签内添加以下代码: <weblog_setup>标签用于标识这个安装资源,通常也建议使用modelname_setup的命名机制。<module>Alanhou_Weblog</module>的内容应为模块的命名空间和模块名Packagename_Modulename。<class>标签中包含的是我们将要为Setup资源创建的类名,对于普通的setup脚本可以不自建类,但现在这么做会给以后的开发带来更大的灵活性。 添加完上面的代码后清除缓存并加载Magento中的任意页,会出现如下提示: 创建app/code/local/Alanhou/Weblog/Model/Resource/Setup.php并加入如下代码: 重新访问任意页,前面的报错会消失页面正常显示。 下面我们来创建安装脚本,这个脚本中将包含初始化模块时所需的CREATE TABLE及其它SQL语句。首先让我们来看一下config.xml文件 这段代码在所有的config.xml文件中都需要添加,主要用于确定模块及版本号。我们的安装脚本就需要用到版本号,本例将假设初使版本号为0.1.0。创建app/code/local/Alanhou/Weblog/sql/weblog_setup/mysql4-install-0.1.0.php文件并加入如下代码: 目录名weblog_setup需要与conifg.xml中的标签<weblog_setup />相同,而文件名称中的0.1.0则应与模块的版本号相同,刷新缓存并访问任意页面会得到如下提示: 注:如果看不到如上提示可能是由于之前访问过页面,执行如下语句再重新访问即可: 上面的提示说明升级脚本确实运行了,后面我们会加入SQL升级脚本,不过现在还是先了解下安装机制。删除die()语句,再次访问会在页面的头部出现Running this upgrade: Alanhou_Weblog_Model_Resource_Setup,重复再刷新一下提示就会消失而页面也显示正常。 Magento的安装资源让我们可以轻易地将安装或升级脚本放到服务器上,然后系统自动运行这些脚本,这样系统中所有的数据库迁移脚本都会保持连续性。 使用熟悉的数据库客户端输入如下语句查询core_table数据表: 这张表中包含所有已安装的模块及其版本号,在靠近下面的部分可以看到我们的模块 正是因为有这条记录,我们在第二次重新访问页面后安装脚本才没有运行,如果想要重新执行安装或升级脚本,比如在开发时想要查看效果,可以删除掉这条记录。那么现在我们就先删除掉这条记录并添加一条SQL语句来创建数据表,删除记录的代码为: 另外我们还要先删除在ORM一节中所创建的blog_post一表,执行如下语句 然后在安装脚本(mysql4-install-0.1.0.php)中添加如下代码: 删除缓存重新加载任意页就会创建blog_posts数据表并插入一行内容。 接下来我们就一起来分析一下上面代码的含义 这句代码中的this指的是什么呢?每个安装脚本都在Setup资源类的环境中运行,自然$this就指向这个类的实例化对象。习惯上我们都会像本例中那样在安装脚本中为$this取一个别名$installer,没有特殊原因建议你在开发过程中也照做。 紧接着的就是上面的代码段,如果查看app/code/core/Mage/Core/Model/Resource/Setup.php中的Mage_Core_Model_Setup类(也就是我们这个安装脚本所继承的类),会发现这些方法会进行了一些基本的SQL操作 查看Varien_Db_Adapter_Pdo_Mysql(lib/Varien/Db/Adapter/Pdo/Mysql.php)就可以找到上面用到的startSetup()和endSetup()方法 另外安装脚本中清空调用了run方法 该方法中传入了一个用于创建数据表的SQL语句,可传入多条SQL语句,只需使用分号进行分隔,可能大家还注意到了下面这条语句: 这个getTable方法中传入的是模型URI,并获取表名。虽然这里可以直接写入表名,但为避免因他人修改配置文件中的表名而导致脚本无法运行,建议养成使用这个方法的好习惯。Mage_Core_Model_Resource_Setup类中包含许多像这样有用的helper方法,最好的学习方法是去研究Magento中core模块的安装脚本。 从1.6开始,Magento就开始支持MySQL以外的数据库,既然我们的安装脚本中包含原生SQL语句,那有可能在其它的数据库系统比如MSSQL中无法执行。这也是为什么我们在文件名中添加了mysql4-作为前缀。 为确保安装脚本保持在多个数据库系统中兼容,Magento提供了一个DDL(Data Definition Language)数据表对象,以下我们对脚本进行修改来保证脚本能在所有Magento支持的关系型数据库中运行。 依然编辑app/code/local/Alanhou/Weblog/sql/weblog_setup/mysql4-install-0.1.0.php文件: 可以看到这里我们没有使用原生SQL语句,使用以上DDL形式的脚本可以保证咱们的模块在与各种数据库保持兼容。 现在我们已经掌握了如何通过脚本来创建数据表,可是如果我们想要对已有模块的数据表结构进行修改又该怎么做呢?Magento的安装资源允许我们通过版本号来自动运行脚本升级模块。一旦在Magento中运行了安装脚本,除非删除core_resource表中对应的记录,否则这个脚本就再也不会被运行。通过创建类似于安装脚本的升级脚本,我们就可以进行适当的升级操作。 创建app/code/local/Alanhou/Weblog/sql/weblog_setup/upgrade-0.1.0-0.2.0.php文件并加入以下代码: 升级脚本和安装脚本放在同一个文件夹内,文件名前面为upgrade,后面为升级前的版本号和升级后的版本后,中间用”-“来进行分隔。如果我们清除缓存重新访问页面这个脚本并不会运行,需要修改config.xml中的版本号都会运行升级脚本: 在这里我们的升级脚本也可以命名为mysql4-upgrade-0.1.0-0.2.0.php,当然这就表明了脚本针对的是MySQL。 在完善升级脚本前,还要一件需要注意的事情,先在同一个文件夹中创建app/code/local/Alanhou/Weblog/sql/weblog_setup/upgrade-0.1.0-01.5.php并加入代码:   重新访问页面会同时出现两条提示 这是因为当Magento发现模块的版本号发生变时,它会运行所有比当前版本号高的脚本,虽然我们并没有在模块配置文件中添加0.1.5,但该脚本依然会被执行。脚本的执行顺序是按版本号从低到高,此时再查看core_resource会得到如下结果: 可以看到版本号已经变成0.1.5了,这说明0.1.0到0.1.5的升级已经完成,并不是执行的0.1.0到0.2.0的升级。那么下面我们就来修改0.1.0-0.2.0的升级脚本:   重新刷新页面发现升级脚本并没有执行,post列依然允许使用空值,更重要的是die()语句并没有使用程序跳出运行,到底发生了什么呢?我们来一起捋一下前面的操作: 起初weblog_setup资源的版本号是0.1.0 […]

Tags: , ,

0

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

Posted by Alan on August 9, 2015 in Coding, Magento |

模型层级的应用在MVC框架中是一个非常重要的部分,它包含应用程序所需的数据。在Magento中,Model起的作用甚至还要更大,因为其中还包含业务逻辑,在其它的MVC框架中,业务逻辑通常是放在Controller或Helper方法中的。 注:在调试过程中如果没有出现我们所提到的报错,请开启报错,步骤如下: a> 打开根目录下的index.php文件并取消如下注释: b> 打开.htaccess文件并在最后添加 SetEnv MAGE_IS_DEVELOPER_MODE “true” MVC模型 首先我们来看看PHP传统的MVC模型,如果说MVC的定义不够清楚,那么模型的定义就更加模糊了。在PHP开发者大规模采用MVC框架前,数据是通过原生的SQL语句或SQL抽象层来获取的。这时开发者需要书写SQL语句并考虑为哪些对象建模。 如今很多人已不太愿意去书写原生SQL语句了,但很多PHP框架依然是在大量使用SQL。Model是提供抽象层的对象,但事实上程序员还是书写SQL语句或者通过抽象方法来读写数据以调用SQL。 也有一些框架避开SQL的使用而采用ORM(Object Relational Mapping)来完成相关操作。这种方法开发者通过对象设定属性,在调用对象中的save方法时,数据会被自动写入数据库。 我们再来看看Magento的模型,Magento是支持ORM的,同时Zend框架中的SQL抽象也可用。Magento中大多数的数据通过其内置的模型或自开发的模型来处理。Magento中Model的概念也是超级灵活、高度抽象的。 Magento中大多数的模型可以被划分为两类,一种是类似ActiveRecord的一个对象一张表的模型,另一种就是大名鼎鼎的EAV(Entity Attribute Value)模型。每个模型都有一个模型集合,集合(Collection)是用于包含一系列Magento模型实例的PHP对象。Magento开发团队在PHP标准库接口中加入了IteratorAggregate和Countable来让每个Model类型获取它自己的集合类型。如果你不太了解PHP标准库,可以把模型集合看作带有方法的数组。 Magento模型中没有代码去连接数据库,而是通过模型资源类来与数据库服务器进行交互(读或写adapter对象)。通过分离逻辑模型与数据库交互代码,理论上就可以在保持模型不变的情况下写一个新的资源类来操作不同类型的数据库。 首先我们要创建一个基本的Magento模型,按照传统我们来做一个weblog博客建模,步骤如下: 创建一个Weblog模块 为我们的Model创建一个数据表 在配置文件中添加一个Blogpost模型 在配置文件中为Blogpost模型添加模型资源信息 在配置文件中为Blogpost模型添加一个读适配器(Adapter) 在配置文件中为Blogpost模型添加一个写适配器 为Blogpost模型添加一个PHP类文件 为Blogpost资源模型添加一个PHP类文件 实例化该模型 那下面我们就按这个步骤来进行操作吧,通过前面的学习你应该对创建Weblog模块已经相当熟悉了,不过考虑到有些朋友没有从头开始看,这里再赘述一下,首先创建如下目录 创建app/code/local/Alanhou/Weblog/etc/config.xml文件并加入如下代码 接着创建app/etc/modules/Alanhou_Weblog.xml文件并加入如下代码 执行以下步骤 清除缓存 在后台中,点击System > Configuration > Advanced > Advanced 在Disable modules output面板中查看Alanhou_Weblog是否出现 模块添加成功后我们来创建一个Action方法名为testModel的index控制器,首先在config.xml里添加router即加入如下代码: 在app/code/local/Alanhou/Weblog/controllers/IndexController.php中加入如下代码: 清除缓存并访问http://localhost/magento/weblog/index/testModel页面上会输出Setup! Magento拥有一套可自动创建和修改数据库的系统,不过现在我们先手动为这个模型创建数据表,在phpMyAdmin或任何数据库客户端中进入数据库执行如下语句创建数据表blog_posts 接着执行如下语句手动插入一条数据 配置模型文件我们需要在配置文件中 在模块中开启Model 在模块中开启Model资源 为Model资源添加一个entity数据表配置 在实例化一个模型时需要进行类似下面这样的调用 […]

Tags: , , , ,

0

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

Posted by Alan on August 9, 2015 in Coding, Magento |

刚刚接触Magento开发的人经常会搞不清布局(Layout)和视图(View)之间的分别。那么本节就来剖析Magento的布局/块,以及它们在Magento的MVC架构中所起到的作用。 和很多主流的MVC系统不同,Magento的Action控制器不向视图传递数据对象,并且通常也不会去设定视图对象中的属性值。而是由视图组件直接引用系统模型来获取所需显示的信息。 采用这种设计方法直接导致视图被分割成两个部分:块文件(Blocks)和模板文件(Templates),其中块是PHP对象,模板是混合了HTML和PHP的原生PHP文件,后缀名采用.phtml。每个块文件对应着一个模板文件,在模块文件中通过$this关键词来引用块文件中的对象。 先看看代码,打开app/design/frontend/base/default/template/catalog/product/list.phtml文件,会看到如下代码 其中getLoadedProductCollection方法来自块文件的Mage_Catalog_Block_Product_List类,具体位置在app/code/core/Mage/Catalog/Block/Product/List.php 块文件中的_getProductCollection会实例化模型并读取其中的数据,并将结果返回给模板文件。 块文件内置 块和模板文件真正的强大之处在于getChildHtml方法的使用,使用这个方法可以包含一级块、模板文件内的二级块、模板文件。页面上的HTML布局正是通过块文件不断地调用内嵌的块文件来创建的。下面我们就来看一看app/design/frontend/base/default/template/page/1column.phtml这个文件: 模板文件本身并不长,但通过多次调用$this->getChildHtml()方法包含并显示了多个块文件,这些块文件又会使用getChildHtml方法去调用其它块文件。 布局文件 这么看起来块文件和模板文件确实不错,那么如何让Magento知道在页面中使用哪一个块文件?先从哪一个块文件开始处理?又如何在getChildHtml中指定一个块文件呢?毕竟里面的参数看起来不太像是个块文件的名称。 这就需要讲到布局对象了,布局对象是一个指定了页面上将包含块文件的XML对象,它同时也指定了先处理哪一个块文件。在上节中我们在Action方法中使用了echo指令输出了一些内容,本节我们将会为Helloworld模块创建一个简单的HTML模板文件。首先创建一个app/design/frontend/base/default/layout/local.xml文件,加入如下代码 然后再创建一个app/design/frontend/base/default/template/alanhou/helloworld/simple_page.phtml文件并添加如下代码: 完成了上面的操作后,最后需要通过Action控制器来调用整个布局,那么我们需要对之前创建的indexAction方法进行如下调整: 清除缓存重新加载http://localhost/mgt/helloworld/index/index,就会显示刚刚在simple_page.phtml里所添加的内容,也就是整个屏幕都显示红色的背景。 你一定很好奇这背后到底发生了什么呢?下面就让我们一起来揭开这神秘的面纱。为方便观察首先安装一下Layoutviewer模块: 链接: http://pan.baidu.com/s/1qHTd8 密码: 2dya 只需解压缩然后拷贝到app目录中即可完成安装,这个模块类似于我们这前面小节里提到的Configviewer。安装完成后请访问http://localhost/magento/helloworld/index/index?showLayout=page 输出内容即为page请求的layout.xml,它由<block />, <reference /> 和<remove />等标签组成,当我们在调用loadLayout方法时,Magento实际完成的操作有: 生成Layout布局XML文件 实例化各<block />标签中的Block类,通过标签属性查找类并作为全局配置路径保存到布局对象的_blocks数组中,在该数组中以标签名作为数据的键 如若标签中包含输出属性,其值就会被添加到布局对象的_output数组中 然后在Action控制器中调用renderLayout方法时,Magento会遍历_output数组中的所有Block,将输出属性的值作为一个回调方法,这通常都是toHtml,也就是从块模板文件开始处理。接下我们会谈谈Block是怎么被实例化的,layout文件又是如何生成并完成输出的? Block的实例化 在生成的布局XML文件中,包含type属性的实际上是一个类群URI,比如 这些URI都引用全局配置文件中的一个地方,URI的前半部分(上例中都是page)会用于在全局配置文件中查询page的类名,而第二部分(分别是html和template_links)会被加到前面查询到的类名最后并形成Magento将要实例化的类。 以page/html为例,Magento会首先去依次查找全局配置文件中的global > blocks > page节点(参见Magento开发系列之二 配置文件) 查找到的结果即是上图中的 这里我们就得到了类名的前一部分Mage_Page_Block,然后将第二部分添加到后面就构成了将要实例化的类名Mage_Page_Block_Html。假如我们创建了一个和现有block同名的块文件,新的block会替换原来的实例,我们在前面创建的local.xml就做了这样的替换 名为root的block就被我们的创建的block所替换,指向了一个新phtml模板文件。 Reference标签 标签会将会将内部包含的所有XML声明以指定的名称放到现在的block中,它内部包含的节点会被作为所引用的父级block的子block 放在不同的layout文件中: 即便root block是在一个单独的布局XML文件中声明,新添加的block还是作为一个子block。Magento先创建一个名为root的page/html块,之后如果再遇到有对root的引用(reference),就会将新的块some.other.block.name作为root的子block。 Layout文件的生成过程 现在我们对于Layout XML文件已经有了更进一步的了解,但这个XML文件是从哪里来的呢?要解释这个问题就需要引入两个新的概念:指针(Handle)和安装包布局(Package Layout)。 Magento中的每个页面请求都会生成一些指针,我们前面创建的Layoutview模块将有助于形象化的展示这些指针,只需要访问http://localhost/magento/helloworld/index/index?showLayout=handles就会看到类似下面的结果(根据个人配置会略有差别) 以上输出的每一个都是指针,指针可以在Magento系统中的很多地方进行设置,这里我们着重讨论的是default和helloworld_index_index这两个。default指针在每个Magento的请求中都会出现,而helloworld_index_index是拼接了Router名称(helloworld)、Action控制器名称(index)和Action控制器方法名(index)所形成的一个字符串。这也就是说Action控制器中的每个方法都会对应一个指针。 […]

Tags: , , , , ,

0

Magento开发系列之三 控制器

Posted by Alan on August 7, 2015 in Coding, Magento |

MVC结构可以追溯到Smalltalk编程语言和Xerox Parc时代,从那时起很多系统都自称采用了MVC结构。这些系统又都与其它有着些许差别,不过总体而言都会将获取数据、业务逻辑和用户界面的代码进行分离。PHP中常见的MVC框架如下图所示: 一个称为前台控制器的PHP文件获取到URL 该PHP文件检测URL并获取控制器名和Action名(这一步常被称为routing) 实例化所获取到的控制器 与获取的Action名相匹配的方法将会被调用 这个Action方法会根据请求的变量实例化/调用model中的方法 该Action方法准备好数据结构然后传送给view 视图根据从控制器那里获取的数据结构生成HTML 这种模式显然比早期的一个页面对应一个PHP文件要先进了很多,但软件工程师们在工作中会经常抱怨: 前台控制器在全局命名空间中工作 配置的规则只能实现少量的模块化 URL routing不太灵活 即便系统允许重载默认方法,如果不进行大规模重构,这种模式会很难添加新的模型、视图或控制器。 基于此,Magento团队创建了更为抽象的MVC模式 由一个PHP文件获取到URL 该PHP文件实例化一个Magento应用 Magento应用实例化一个前台控制器对象 前台控制器实例化一到多个Router对象(通过全局配置文件指定) Router检测请求的URL是否匹配 如果发现到匹配,会获取到Action控制器和Action 实例化Action控制器并调用与Action名称相匹配的方法 Action方法根据请求实例化模型及调用方法 该Action控制器实例化Layout对象 Layout对象根据请求对象和系统属性(也称作指针)创建一系列Block对象 Layout还会在某些Block对象(启动内层渲染)上调用输出方法 每个Block都有一个对应的模板文件,Block中包含PHP逻辑,模板中包含HTML和PHP输出代码 Block从模型中调取数据,也就是说Action控制器并不会传输数据结构。 我们会逐步揭开层层面纱,不过本节我们主要讨论前台控制器 > Router > Action控制器几部分。 这么多理论,想必大家多年的失眠症都已经治愈了…(⊙_⊙;)… 还是老规矩,下面用实例来进行说明,主要有以下几步: 创建一个Hello World模块 使用Router配置该模块 为Router创建Action控制器 首先为Helloworld模块创建目录: 到这里大家估计已经是轻车熟路了,先创建app/code/local/Alanhou/Helloworld/etc/config.xml并加入如下代码: 紧接着创建app/etc/modules/Alanhou_Helloworld.xml文件来激活这个模块,加入如下代码: 使用老方法确认一下模块是否配置成功 过上面基本的框架已经搭建好了,执行以下步骤 清除缓存 在后台中,点击System > Configuration > Advanced > Advanced 在Disable modules […]

Tags: , , ,

Copyright © 2012-2018 记录点滴生活 | Alan Hou的个人博客 All rights reserved.