月度归档 2015年4月29日

通过清心醉

Magento开发实例:编写自己的模型(Model)并简单的提取数据

Magento 开发实例三(模型Model)

暂时将项目名称由Qxz改为Mage,数据库配置还挺麻烦的.

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

Magento自带的Zend框架提供了SQL抽象层,但是在大多数情况下我们将通过Magento自带的模型和我们自己的模型来进行数据访问。他和视图层(View)一样,Magento的模型层是一个高度灵活,高度抽象的甚至让人有点令人费解。

 

Magento模型分为两类:

第一类是基本的ActiveRecord类型,一张表一个对象的模型。

第二类是Entity Attribute Value(EAV)模型。

 

Magento自己定义了一个数据类型叫做模型集合(Model Collection)。顾名思义,模型集合就是一个对象里面包含了很多模型对象。Magento的创造者Varien团队实现了PHP类库的标准接口,“IteratorAggregate”,“Countable”。这样模型集合就能调用这些方法,这也是模型集合和数组的区别。

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

 

我们来为Mymodule模块创建多个Blog控制器

class Mage_Mymodule_BlogController extends Mage_Core_Controller_Front_Action
{
public function indexAction() #默认方法
{
$blog = Mage::getModel(‘mymodule/blog’); #获取模板实例
$params = $this->getRequest()->getParams();
#获取页面的/id/1
$blog->load($params[‘id’]);
$data=$blog->getData(); #获取表内的全部数据
var_dump($data); #输出
}
}

#现在我们如果执行,还不能进行输出

#我们先增加个表/字段

CREATE TABLE still_blog(id int primary key auto_increment,name varchar(128),phone int(16));

INSERT INTO still_blog(name,phone)VALUES(‘chenkuizong’,’13823819185′);

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

#由于考虑表前缀still_blog的关系,请修改下,如果没有表前缀直接使用blog

创建模型

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

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

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

 

$model = Mage::getModel(‘mymodule/blog’);

Mage::getModel有两个参数。分别为模块名字/操作的数据表段。

和Mage::getHelper()的原理类似,这里Magento也是通过全局配置去查找模型的类名。模型的类名和我前面讲过的块类名一样,都是分组类名。

我们来为Blog配置的模型config.xml,打开当前模块的config.xml,在</config>前面加入global/models节点:

<global>
<models>
<mymodule>
<class>Mage_Mymodule_Model</class>
<resourceModel>mymodule_resource</resourceModel>
</mymodule>
</models>
</global>

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

项目名称_模块名称_Model == Mage_Mymodule_Model

Blog控制器代码中:$blog= Mage::getModel(‘mymodule/blog’);

可以看出会尝试实例化Mage_Mymodule_Model_Blog

所以在模型中创建该文件并且创建这个类

app/code/local/Mage/Mymodule/Model/Blog.php

 

class Mage_Mymodule_Model_Blog extends Mage_Core_Model_Abstract

{

protected function _construct()

{

$this->_init(‘mymodule/blog’);

}

}

所有的模型都必须继承“Mage_Core_Model_Abstract”类。这个抽象类强制你实现一个方法“_construct”(注意:这个不是PHP的构造行数“__construct”)。这个方法应该调用父类已经定义好的“_init”方法,参数是资源模型的URI,也就是我们要告诉模型使用哪个资源模型。

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

<resourceModel>mymodule_resource</resourceModel>

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

Mage::getResourceModel(‘mymodule/blog’);

这里“mymodule/blog”就是我们给模型的“_init”传入的参数。 “Mage::getResourceModel”方法将以“mymodule/blog”为URI在全局配置中找到标签的值,在这里是“mymodule_resource”。

然后Magento会用URI“mymodule_resource/blog”去实例化资源模型类。实例化的过程和我们前面讲的模型的实例化是一样的,所以我们也需要在config.xml中添加资源模型的声明

在config.xml里的</models></global>节点里加入:

<mymodule_resource>
<class>Mage_Mymodule_Model_Resource</class>
<entities>
<blog>
<table>blog</table>
</blog>
</entities>
</mymodule_resource>

然后为模型添加一个资源类文件,添加如下文件

/app/code/local/Mage/Mymodule/Model/Resource/Blog.php

class Mage_Mymodule_Model_Resource_Blog extends Mage_Core_Model_Resource_Db_Abstract
{
protected function _construct()
{
$this->_init(‘mymodule/blog’,’id’);
}
}

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

这时候如果我们直接访问127.0.0.1/mymodule/blog/index

显示的是:array(0) { } 空值

我们再来看控制器:

$blog = Mage::getModel(‘mymodule/blog’); #获取模板实例
$params = $this->getRequest()->getParams();
#获取页面的/id/1
$blog->load($params[‘id’]);
$data=$blog->getData(); #获取表内的全部数据
var_dump($data); #输出

我们需要有两个参数

127.0.0.1/mymodule/blog/index/id/1

Url里加多个id/1 就行了.

如果我们/id/2 那么就会根据主键(一般都是用id) 提取第二行的数据,依此类推.

magento_model

 

magento_model1

 

附个写好的config.xml配置,作者一开始写的时候因为配置写错N次,导致无法提取数据,文章所说的也只一一增加,会让人混淆加错位置:

<?xml version=”1.0″?>
<config>
<modules>
<Mage_Mymodule>
<version>0.1.0</version>
</Mage_Mymodule>
</modules>

<frontend>
<routers>
<mymodule>
<use>standard</use>
<args>
<module>Mage_Mymodule</module>
<frontName>mymodule</frontName>
</args>
</mymodule>
</routers>
</frontend>

<global>
<models>
<mymodule>
<class>Mage_Mymodule_Model</class>
<resourceModel>mymodule_resource</resourceModel>
</mymodule>
<mymodule_resource>
<class>Mage_Mymodule_Model_Resource</class>
<entities>
<blog>
<table>blog</table>
</blog>
</entities>
</mymodule_resource>
</models>
</global>
</config>

通过清心醉

Magento开发实例:编写自己的视图-布局(Layout)、块(Block)和模板(Template)

上一篇开发实例中作者讲过了Magento的MVC分层中C(控制器)层的规则。Magento的M(模型)和V(视图)层和传统的MVC有很大的改进。

传统的MVC分层是通过执行控制器内的方法,控制器的方法内获取不同的模型数据,然后传递给视图。

Magento却不同了,Magento是从视图中直接引用模型中的数据,这样就导致视图被拆成块(Block)和模板(Template)两部分,块是PHP对象,而模板是原始PHP文件,混合了XHTML和PHP代码(也就是把PHP作为模板语言来使用了)。每一个块都和一个唯一的模板文件绑定。在模板文件phtml中,“$this”就是指该模板文件对应的块对象。

 

比如:app/design/frontend/base/default/template/catalog/product/list.phtml文件中的

<?php $_productCollection=$this->getLoadedProductCollection() ?>

这里“getLoadedProductCollection”方法可以在这个模板的块对象“Mage_Catalog_Block_Product_List”中找到

 

我们看看块(Block)文件

app/code/core/Mage/Catalog/Block/Product/List.php

public function getLoadedProductCollection()

{

return $this->_getProductCollection();

}

块的“_getProductCollection”方法会实例化模型,并读取数据然后返回给模板。

 

块的嵌套::

 

Magento把视图分离成块和模板的真正强大之处在于“getChildHtml”方法。这个方法可以让你实现在块中嵌套块的功能。顶层的块调用第二层的块,然后是第三层……这就是Magento如何输出HTML的。

我们可以看到这个模板里面很多地调用了“$this->getChildHtml(…)”。每次调用都会引入另外一个块的HTML内容,直到最底层的块。

布局对象::

看到这里,你可能有这样的疑问

Magento怎么知道在一个页面上要用那些块?

Magento怎么知道哪一个块是顶层块?

“$this->getChildHtml(…)”里面的参数是什么意思?块的名字吗?

Magento引入了布局对象(Layout Object)来解决上面的那些问题。布局对象(或者说布局文件)就是一个XML文件,定义了一个页面包含了哪些块,并且定义了哪个块是顶层块。

在上一节在执行方法(Action Method)里面直接输出了HTML内容。现在我们要为我们的Mymodule模块创建一个简单的HTML模板。首先我们要创建如下布局文件

app/design/frontend/default/default/layout/local.xml

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

</layout>

 

然后我们在模板内创建个mymodule模块(小写)的目录,新增一个home.phtml文件并且写入

<head>

<title>Untitled</title>

<style type=”text/css”>

body {

background-color:#f00;

}

</style>

</head>

<body>

<h4>Hello Word</h4>

</body>

</html>

最后,我们要在执行控制器里面调用布局文件,开始输出HTML。

app/code/local/Qxz/Mymodule/controllers/IndexContrllers.php

修改function indexAction()的方法:

$this->loadLayout();

$this->renderLayout();

 

清空缓存并刷新。访问127.0.0.1/mymodule,就可以看到纯红色背景的页面。

我们看到执行控制器的indexAction方法里调用了loadLayout和renderLayout

Magento是如何处理的呢?

首先调用“loadLayout”时,Magento会生成这个布局文件。

为每一个block和reference标签实例化一个块对象。

注:在local.xml的layout布局文件中

块对象的类名是通过标签的name属性来查找的。这些块对象被存储在布局对象的_blocks数组中

如果block标签包含了output属性,那么这个块的名字和output属性的值会被添加到布局对象的_output数组中

然后,当你在执行方法中调用“renderLayout”方法时,Magento会遍历_output数组中所有的块名字,从_blocks数组中获得该名字的块,并调用块对象中使用output属性的值作为名字的函数。这个函数往往是“toHtml”。这个output属性也告诉Magento这里就是输出HTML的起点,也就是顶层块。

#更多可以查看app/code/core/Mage/Core/Model/Layout.php文件

那么对象是如何被实例化的,这个布局文件时如何被生成的,最后我们来实践下。

实例化块对象

在布局文件中,block和reference标签有一个“type”属性,这个属性其实是一个URI

<block type=”page/html” …

<block type=”page/template_links”…

Magento就是通过这个URI是用来查找块对应的类名。这个URI分为两部分,第一部分“page”是用来在全局配置中查找一个基本类名,第二部分“html”或者“template_link”将被添加到基本类名后面生成一个具体的将被实例化的类名。

我们以“page/html”为例。首先Magento在全局配置中找到节点

/global/blocks/page

有以下内容

<page>

<class>

Mage_Page_Block

</class>

</page>

这里我们拿到了一个基本类名“Mage_Page_Block”,然后添加URI的第二部分“html”到基本类名后面,我们就得到最终的块对象的类名“Mage_Page_Block_Html”。块的类名在Magento中被称为“分组类名”(Grouped Class Names),这些类都用相似的方法被实例化。

block和reference的区别

我们上面提到block和reference都会实例化块对象,那么它们究竟有什么区别呢? reference在布局文件中是用来表示替换一个已经存在的块。

<block type=”page/html” name=”root” output=”toHtml” template=”page/one.phtml”>

</block>

<reference name=”root”>

<block type=”page/someothertype” name=”root” template=”page/two.phtml” />

</reference>

Magento首先创建了一个名叫“root”的块。然后,它有发现了一个引用(reference)的名字也叫“root”,Magento会把原来那个“root”块替换成reference标签里面的那个快。在这里,块“root”被我们用reference替换了,指向了一个不同的模板文件。

 

布局文件是如何生成的

现在我们对布局文件已经有所了解了,但是这个布局文件是那里来的呢?要回答这个问题,我们得引入Magento中的另外两个概念,操作(Handle)和包布局(Package Layout)。

 

我们来试下给Mymodule模块的IndexController.php文件增加个blog的方法

function blogAction()

{

$this->loadLayout();

$this->renderLayout();

}

同样我们调用布局

 

然后修改local.xml文件

红色为新加的,注意书写方法包含在<layout>里,对称包含。

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

<mymodule_index_blog>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/blog.phtml”/>

</reference>

</mymodule_index_blog>

</layout>

这时候我们如果访问

127.0.0.1/mymodule/index/index

127.0.0.1/mymodule/index/blog

会输出不同的视图页面。

 

 

开始输出和getChildHtml方法

在Magento默认的配置下,HTML输出是从名为“root”的块开始(其实是因为这个块拥有output属性

注:任何一个拥有output属性的块都是顶层块,在拥有多个顶层块的情况下Magento将按照块定义的先后顺序输出HTML。

我们覆盖了“root”块的模板template=”mymodule/home.phtml”

模板文件的查找路径是当前主题(theme)的根目录,Magento默认设置是在

app/design/frontend/base/default 目录里的template目录

1.9后的版本为app/design/frontend/rwd/default

 

我们为执行控制器IndexController.php增加一个注册的方法;

function registerAction() #注册方法

{

$this->loadLayout();

$this->renderLayout();

}

既然用到了布局,布局文件肯定也要修改了,修改local.xml,添加个mymodule_index_register块

<mymodule_index_register>

<reference name=”root”>

<block type=”customer/form_register” name=”register” output=”toHtml” template=”customer/form/register.phtml”/>

</reference>

</mymodule_index_register> </mymodule_index_register>然后我们在mymodule模板目录里增加个register.phtml文件哦

写入下面代码:

<?php

echo $this->getChildHtml(‘register’);

#在这里会直接调用block块的name=register的模板

?>

 

这里“getChildHtml”的参数就是要引入的块的名字,使用起来相当方便。

清空Magento缓存并刷新,重新访问127.0.0.1/mymodule/index/register就可以看到:

2-1

“getChildHtml”的参数一定要是当前页面的布局文件中声明过的块。这样的话Magento就可以只实例化需要用到的块,节省了资源,我们也可以根据需要为块设置不同的模板文件。

布局,块和模板构成了Magento MVC架构中的View,这是Magento的特色。

 

针对部分块没有template模板属性的,可能是块的类中定义了默认的模板

比如$this->setTemplate(‘page/template/links.phtml’);

 

总结:

我们看看coloa.xml布局文件的数据:

<?xml version=”1.0″ encoding=”UTF-8″?>

<layout version=”0.1.0″>

<mymodule_index_index>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/home.phtml”/>

</reference>

</mymodule_index_index>

<mymodule_index_blog>

<reference name=”root”>

<block type=”page/html” name=”root” output=”toHtml” template=”mymodule/blog.phtml”/>

</reference>

</mymodule_index_blog>

<mymodule_index_register>

<reference name=”root”>

<block type=”customer/form_register” name=”register” output=”toHtml” template=”customer/form/register.phtml”/>

</reference>

</mymodule_index_register>

</layout>

作者用3种不同的颜色来区分了。至于这里的type=”customer/form_register”,应该是引用客户的注册表单吧。作者也是自学开发,以后更精通了再跟进。

 

通过清心醉

Magento开发实例:编写自己的控制器

简介:

Magento配置系统是支撑Mangeo运行的关键。配置系统掌管着所有的module/model/class/template/etc等文件。它把整个Magento系统抽象出来,用一个配置文件来描述。这里的“配置文件”并不是一个物理上存在的文件,而是Magento根据当前的系统状态动态生成的一段XML。这样的抽象提供了无与伦比的灵活性,允许你覆盖几乎任何系统的默认行为。

实例写个来看看,首先先从控制器方面写起。

首先来创建一个模块:

注:Magento的插件叫module,就是模块的意思。比如我们看到app/code/core/Mage目录里的很多文件夹,其实每一个文件夹目录对应的就是一个module模块,这是Magento的核心代码。通常我们需要对核心代码进行修改,都会新建一个app/code/local/项目/模型名称文件夹。

比如我们要修改Magento的核心Checkout功能。

原核心代码的目录为/app/code/core/Mage/Checkout

复制到/app/code/local/Mage/Checkout 然后修改该目录下的Checkout代码进行二次开发等。就可以不影响到核心的Mage,这么说吧,叫代码重写。因为Magento默认是会使用/app/code/local里面的源代码。同时核心代码没去修改,升级后因为修改过的是以插件的形式重写,就不用进行再次修改了。

创建模块需要一个项目,你可以用Mage,即/app/code/local/Mage,由于作者实际测试开发,所以项目名称为Qxz

目录为:/app/code/local/Qxz/Mymodule 模块名称为:Mymodule

创建以下目录:

app/code/local/Qxz/Mymodule/Block

app/code/local/Qxz/Mymodule/controllers

app/code/local/Qxz/Mymodule/etc

app/code/local/Qxz/Mymodule/Helper

app/code/local/Qxz/Mymodule/Model

app/code/local/Qxz/Mymodule/sql

#以上6个目录为插件基本需要存在的,为了以后开发方便一次创建好

然后我们需要创建两个配置文件:(配置文件都在etc目录内)

1是告诉Magento有某个模块的存在

2是模块自身的配置

首先系统模块的位置:注:这是全局的系统配置。

app/etc/modules/

创建配置文件的命名规则为:项目名称_模块名称,前面已经说到了。所以我们的系统配置文件的命名为:Qxz_Mymodule.xml

写入下面的配置:

<config>

<modules>

<Qxz_Mymodule>

<active>true</active>

<codePool>local</codePool>

</Qxz_Mymodule>

</modules>

</config>

然后我们创建模块自身的配置:config.xml

自身模块位置:app/code/local/Qxz/Mymodule/etc/

写入下面配置代码:

<config>

<modules>

<Qxz_Mymodule>

<version>0.1.0</version>

</Qxz_Mymodule>

</modules>

</config>

 

我们现在进入Magento后台,清/刷新缓存

然后系统配置高级禁用模块输出

1

我们可以看到,最后面已经Qxz_Mymodule的模块了,Magento已经知道该模块的存在,但现在这模块并不能做任何事情。

来给他增加点功能吧,就编程界的开始输出“Hello word吧。

#前提,你得对MVC有一定的理解。

我们要配置一个路由。路由是用来把一个URL请求转换成一个执行控制器和方法。和传统的PHP MVC不同的是,我们需要在Magento的全局配置中显式的定义自己的路由。

 

我们先来修改模块自身的配置文件app/code/local/Qxz/Mymodule/ect里的。注意系统配置和当前模块的配置。

 

红色部分为增加的:

 

 

<config>

<modules>

<Qxz_Mymodule>

<version>0.1.0</version>

</Qxz_Mymodule>

</modules>

<frontend>

<routers>

<mymodule>

<use>standard</use>

<args>

<module>Qxz_Mymodule</module>

<frontName>mymodule</frontName>

</args>

</mymodule>

</routers>

</frontend>

</config>

 

 

什么是frontend

frontend标签指向一个Magento区(Area),比如frontend”就是指网站的前台,admin”是指网站的后台,install”是指Magento的安装程序。【注:这个有点像磁盘分区,区和区之间是相互独立的,但是都归操作系统能够管理,在这里归Magento管理。默认的Magento安装没有install”这个区,frontend区接管了,全局配置中的以下代码可以解释这一点

<frontend>

<install>

<use>standard</use>

<args>

<module>Mage_Install</module>

<frontname>install</frontname>

</args>

</install>

</frontend>

什么是routers

Phil Karlton有一句很著名的话在计算机领域只有两件事是困难的:缓存和命名Magento引入了很多新概念,无疑存在很多命名问题,这里就是一个例子。routers标签有时候包含的是路由对象的定义,有时候包含的是路径的定义。路由对象是进行路由操作的实体,而路径仅仅是路由对象的一个参数。【注:如果你仔细看过那个全局配置xml的话,你会发现有两处地方出现routers,一处是web -> routers”,另外一处是frontend-> routers”。你再仔细看看会发现两处routers包含的内容不一样。第一处包含的是路由对象的定义,第二处包含的是路径的定义。】

什么是module

这个标签的内容应该是一个模块的全名,项目_模块名,在这里是Qxz_Mymodule”Magento用这个名字来定位你的模块文件。

什么是frontname

当一个router解析一个URL的时候,它是按照如下规则进行的

http://example.com/frontName/actionControllerName/actionMethod/

所以,当我们在frontname标签里定义了mymodule”以后,Magento会把如下的URL请求交给我们的模块Qxz_Mydoule”来处理

http://example.com/mymodule/*

有些人容易把frontname和前端控制器(Front Controller)混淆起来。它们是两个不同的概念,frontname只跟路由相关,学过Zf的人都知道,其实就是个模块名。【注:根据我们前面讲过的MagentoMVC流程,前端控制器是用来实例化所有路由的,而这里的frontName”只是路由过程中的一个参数】

什么是mymodule

这个标签的名字应该是模块名字的小写版本。我们的模块名字是Mymodule”,所以这里我们用mymodule”。你应该也已经注意到我们定义的frontName”也是和我们的模块相匹配的。这是一个不成文的规定,但不是强制要求。事实上,一个模块可以定义多个,也就是可以有多个frontName”

 

为路由创建执行控制器

MagentoMVC流程中路由会把控制权交给执行控制器。上面我们定义了路由,现在我们来定义我们的执行控制器。首先创建文件

app/code/local/Qxz/Mymodule/controllers/IndexController.php

模块的控制器应该放在模块的子目录controllers”(小写c)里面。这是规定,Magento会在这个目录寻找模块的控制器文件。我们的第一个控制器包含以下内容

#Qxz项目Mymodule模块的执行控制器

class Qxz_Mymodule_IndexController extends Mage_Core_Controller_Front_Action {

public function indexAction() {

echo ‘Hello World!’;

}

}

清空Magento缓存,请求如下URL

http://127.0.0.1/ mymodule /index/index

或:127.0.0.1/mymodule

2

到此为止,我们的小插件的第一个控制器已经完成了。

执行控制器的命名规则:

还记得config.xml的标签吗?

<module>Qxz_Mymodule</module>

执行控制的名字的构成如下

以标签的内容开始Qxz_Mymodule

紧接一个下划线Qxz_Mymodule_

加上我们给控制器取的名字Index”(Qxz_Mymodule_Index)

最后加上关键词Controller” Qxz_Mymodule_IndexController

自己定义的属于frontend区的执行控制器都应该继承Mage_Core_Controller_Front_Action

 

URL里面的index/index是什么

我们刚访问的http://127.0.0.1/mymodule /index/index

或:127.0.0.1/mymodule

第一个里index/index是什么意思呢?

其实Magento默认的路由规则是:

http://127.0.0.1/frontName/actionControllerName/actionMethod/

所以在我们请求的URL

http://exmaple.com/mymodule /index/index

其中mymodule”frontName”,第一个index”是执行控制器(Action Controller)的名字,第二个index”是执行方法的名字。对比我们写的执行控制器代码,我们不难发现执行方法的定义是执行方法名字加上Action”关键字

publicfunction indexAction(){}

Magento根据命名规则找到执行控制器文件并实例化,然后再根据命名规则调用指定的执行方法。如果URL没有给出执行控制器名字或者执行方法,Magento会用默认的index”来替代,所以下面三个URL是等价的

http://exmaple.com/mymodule/index/index

http://exmaple.com/mymodule/index/

http://exmaple.com/mymodule/

好了,MagentoMVC架构的C层大概就是这样了。它比传统的PHP MVC的控制器要复杂一点,但是Magento的这个高度灵活的MVC架构能让你创造出几乎所有你能想到的URL结构。

 

通过清心醉

Magento自定义属性筛选

上文作者说了前台调用自定义属性的方法。

前台属性显示出来了,可筛选也得跟上。

首先我们在自定义的属性里有个“使用分层导航”,选择->可筛选(有结果)。

接着我们需要在分类里看看

打开分类-Display Settings

有个Is Anchor,选是即可。

然后重建索引,刷新缓存。

#针对部分属性不需要筛选的,可在不同的分类目录里进行设置

系统默认是使用全部可用的属性。

通过清心醉

Magento前台调用自定义属性

通过查看分类模板里的view.phtml文件可以看到。

有个$_product数组,里面包含了所有的产品信息

通过var_dump($_product)就可以看到了。

比如我们创建了一个文本属性,文本属性代码为Mytext,用于上传产品的时候填写文字。

这时候我们需要在分类/产品详细页里调用出来。可以直接使用

echo $_product->getMytext();

如果是下拉或者多选的话

使用AttributeText的方法:即:echo $_product->getAttributeText(‘Mytext’);

更多的作者使用到了的时候一一更上。

#注:可直接在list.phtml等分类页面调用$_product,不需要再去配置xml

通过清心醉

Magento关闭用户注册功能

最近再用Magento开发一个二手信息交易网站

由于信息非全部公开,使用判断用户是否登录来进行数据的输出。

Magento系统配置里有个Mage_Customer模块,如果关闭了会导致需要登录的账户无法登录。这时候我们就需要考虑从源代码文件里下手了。

customer/account/create/

#分别为客户模快/帐号控制器(包含登录和退出)/创建方法

目录为:app/code/core/Mage/Customer/controllers/AccountController.php

很简单,找到create()的方法

作者使直接echo “网站已经关闭创建用户功能”;exit;

至于网站前台还有显示注册的,可以自己写个方法让他不显示出来即可。

通过清心醉

Magento删除产品同时删除产品的图片

修改核心文件:app/code/core/Mage/Catalog/Model/Product.php

#注:当然你也可以重写个local

找到Delete()方法然后最前面增加一下代码即可。

foreach ($this->getMediaGallery('images') as $image) {
            $image_path = $this->getMediaConfig()->getMediaPath($image['file']);
            if (file_exists($image_path)) {
                @unlink($image_path);
            }
        }
通过清心醉

17-js单击html指定元素时触发事件

<!–
长按触发事件:
onmousedown, onmouseup 以及 onclick 构成了鼠标点击事件的所有部分。首先当点击鼠标按钮时,会触发 onmousedown 事件,当释放鼠标按钮时,会触发 onmouseup 事件,最后,当完成鼠标点击时,会触发 onclick 事件。
–>
<div onmousedown=”mDown(this)” onmouseup=”mUp(this)” style=”background-color:green;color:#ffffff;width:90px;height:20px;padding:40px;font-size:12px;”>点我变颜色</div>

<script>
function mDown(obj)
{
obj.style.backgroundColor=”red”;
obj.innerHTML=”我变红色拉.”;
}

function mUp(obj)
{
obj.style.backgroundColor=”green”;
obj.innerHTML=”你不点了我又变绿色了.”;
}
</script>

通过清心醉

16-js鼠标移至HTML元素上方或移出元素时触发事件

<h1><div onmouseover=”mOver(this)” onmouseout=”mOut(this)” style=”background-color:green;width:320px;height:120px;padding:40px;color:#ffffff;”>想要知道密码鼠标移过来</div></h1>

<script>
function mOver(obj)
{
obj.innerHTML=”密码没有哦,真对不起,因为是空!”;
}

function mOut(obj)
{
obj.innerHTML=”想要知道密码鼠标移过来”;
}
</script>

<!–
onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数。
–>

通过清心醉

15-js判断手机号码

<script>
function mynumber()
{
var x=document.getElementById(“number”).value; //一定要加.value 不然无法获取值的哦
if(isNaN(x)) //判断是否非数字
{
alert(“您输入的是非数字”);
}
else
{
if(x.length!=11) //判断是否有11个字符
{
alert(“请输入11位数的手机号”);
}
else
{
var myreg = /^(((13[0-9]{1})|159|153|158)+\d{8})$/; //定义一个正则表达判断手机号
if(!myreg.test(x))
{
alert(“您输入的手机号有误”);
}
else
{
document.getElementById(“numbertext”).innerHTML=(“您输入的号码为:”+x);
}
}
}
}
</script>
<p>请输入手机号码:<input type=”text” id=”number” onchange=”mynumber()”></p>
<p id=”numbertext”></p>

通过清心醉

14-js-onchange离开输入字段触发事件

<head>
<script>
function myFunction() //定义个函数
{
var x=document.getElementById(“fname”); //获取表单id=fname的值给x
x.value=x.value.toUpperCase(); //更新表单id=fname的值,利用toUpperCase()内置方法大小写转换.
//如果需要大写转小写.可写成:x.value=x.value.toLowerCase();
}
</script>
</head>
<body>
请输入英文字符:<input type=”text” id=”fname” onchange=”myFunction()”>
<p>当您离开输入字段时,会触发将输入文本转换为大写的函数。</p>

<br /> <br />
</body>

通过清心醉

13-js-用户进入或离开页面触发事件

<body onload=”checkCookies()”>
<script>
function checkCookies()
{
if (navigator.cookieEnabled==true)
{
alert(“已启用 cookie”)
}
else
{
alert(“未启用 cookie”)
}
}
</script>
<p>提示框会告诉你,浏览器是否已启用 cookie。</p>
</body>
<!–
onload 和 onunload 事件会在用户进入或离开页面时被触发。
onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。
onload 和 onunload 事件可用于处理 cookie。
定义和用法
cookieEnabled 属性可返回一个布尔值,如果浏览器启用了 cookie,该属性值为 true。如果禁用了 cookie,则值为 false。
语法
navigator.cookieEnabled
–>

通过清心醉

12-js-onclick利用button(按钮)调用函数

<p>点击按钮就可以执行 displayDate() 函数。</p>
<button onclick=”displayDate()”>点击这里</button>
<script>
function displayDate()
{
document.getElementById(“demo”).innerHTML=Date();
//更新id=demo的显示内容为Date()函数值. 注:Date为内置时间函数
}
</script>

<p id=”demo”></p>
<!–
当点击了<button onclick=”displayDate()”>点击这里</button>这一行时
最后一行会显示数据,
–>

/*********第二种方法*********/
<br /> <br />
<p>点击按钮就可以执行 <em>displayDate1()</em> 函数。</p>
<button id=”myBtn1″>点击这里</button>
<script>
document.getElementById(“myBtn1”).onclick=function(){displayDate1()};
//在这已经根据ID获取单击事件,响应的函数->displayDate1()
function displayDate1() //函数体
{
document.getElementById(“demo1″).innerHTML=Date();
}
</script>
<p id=”demo1”></p>

通过清心醉

11-js-onclick单击事件改变文本

<h1 onclick=”this.innerHTML=’我是第一行,颜色不改!'”>修改这一行的内容</h1>
<h2 onclick=”this.innerHTML=’我是第二行,带个红色’;this.style.cssText=’color: red'”>修改这一行的内容</h2>

通过清心醉

10-js判断邮箱是否已写并且格式是否正确

<!– 10-js判断必填项是否已写–>
<html>
<head>
<script type=”text/javascript”>
function validate_email(field,alerttxt)
{
with (field) //with主要用于对一个对象的多个属性进行操作时,使代码更简洁易读,在这里对用户输入的eail进行操作
{
/*
邮箱输入的表单验证。
value.indexOf(@)返回字符串@在输入的邮箱地址中首次出现的位置,从零开始计算,apos<1是为了避免首字母出现@,
value.lastIndexOf(“.”)返回“.”在邮箱地址中最后出现的位置,dotpos-apos<2是确保@后面至少有一个“.”且@与“.”之间至少间隔一个字符。
*/
apos=value.indexOf(“@”);
dotpos=value.lastIndexOf(“.”);
if (apos<1||dotpos-apos<2)
{
alert(alerttxt);
return false; //返回假
}
else
{
return true; //返回真
}
}
}

function validate_form(thisform) //定义个表单判断方法,带个参数来明确是哪个表单
{
with (thisform) //获取了表单的数据即<input type=”text” name=”email” size=”30″>,由用户点击<input type=”submit” value=”邮件格式查询”> 触发
{
if (validate_email(email,”邮箱格式不正确!”)==false)
//调用vilidate_eamil函数,并且带上两个参数,第一个email是<input type=”text” name=”email” size=”30″> 注意这有个name=”email”,传递的是这个参数.
{
email.focus();
return false;
}
}
}
</script>
</head>

 

<body>
<form action=”post页面” onsubmit=”return validate_form(this);” method=”post”>
<!–如果return返回的值为真,把参数传递到post页面–>
Email: <input type=”text” name=”email” size=”30″>
<input type=”submit” value=”邮件格式查询”>
</form>
<!–
form是一个表单,这里首先给表单设置个onsubmit事件.
当用户点”邮件格式查询”时
会先调用validate_form(this)函数的返回值.
至于onsubmit=”return validate_form(this);里面的this是指当前的表单
–>
</body>

</html>

通过清心醉

9-js自定义try catch输出异常错误

<!– 9-js自定义try catch输出异常错误–>
<html>
<body>

<script>
function myFunction()
{
try
{
var x=document.getElementById(“demo”).value; //获取<input id=”demo” type=”text”>代码块的输入值
if(x==””) throw “值为空”; //首先判断是否为空
if(isNaN(x)) throw “不是数字”; //判断是否为数字 isNaN有个返回值
if(x>10) throw “太大”; //判断值是否大于10
if(x<5) throw “太小”; //判断值是否小于5
if(x>=5&&x<=10) throw “数字范围内”; //如果值 (大/等于)5并且(小/等于)10
}
catch(err)
{
var y=document.getElementById(“mess”); //<p id=”mess”></p>这一行显示出throw输出的信息
y.innerHTML=”错误:” + err + “。”; //更新的内容,其中err变量就是try里throw的参数.
}
}
</script>

<h1>我的第一个 JavaScript 程序</h1>
<p>请输入 5 到 10 之间的数字:</p>

<input id=”demo” type=”text”>
<button type=”button” onclick=”myFunction()”>测试输入值</button>
<p id=”mess”></p>

</body>
</html>

通过清心醉

8-js通过try catch输出异常错误

<!– 通过try catch输出异常错误–>
<head>
<script>
var txt=””;
function message()
{
try
{
error_main(“Welcome guest!”); // error_mail方法是不存在的. 到这时会抛出一个异常.
}
catch(err)
{
txt=”本页有一个错误。\n\n”;
txt+=”错误描述:” + err.message + “\n\n”;
txt+=”点击确定继续。\n\n”;
alert(txt);
}
}
</script>
</head>

<body>
<input type=”button” value=”查看消息” onclick=”message()” />
</body>

通过清心醉

7-js-continue 语句中断循环中的迭代

<p>点击下面的按钮来执行循环,该循环会跳过 i=3 的步进。</p>
<button onclick=”myFunction()”>点击这里</button>
<p id=”demo”></p>

<script>
function myFunction()
{
var x=””,i=0;
for (i=0;i<10;i++)
{
if (i==3)
{
continue;
}
x=x + “The number is ” + i + “<br>”;
}
document.getElementById(“demo”).innerHTML=x;
}
</script>

通过清心醉

6-js对象

<script>
var duixiang={
name : “清心醉”,
tel : “138238”,
id : 5566
};
document.write(“名字是:”+duixiang.name + “<br />”);
document.write(“电话是:”+duixiang[“tel”] + “<br />”);
</script>

<p>/*************对象的说明二:***************/</p><br />
<script>
person=new Object(); // 创建一个对象
person.firstname=”Bill”; //对象的firstname值
person.lastname=”Gates”; //对象的lastname值
person.age=56; //对象的age值
person.eyecolor=”blue”; //对象的eyecolor值
document.write(person.firstname + ” is ” + person.age + ” years old.”);
</script>

通过清心醉

5-js创建数组

<script>
var i; //
var cars = new Array();//创建数组,并且写入3组数据
cars[0] = “我是数组的第1个数据”;
cars[1] = “我是数组的第2个数据”;
cars[2] = “我是数组的第3个数据”;
for (i=0;i<cars.length;i++)
{
document.write(cars[i] + “<br>”); //循环输出数组的每一个数据.
}
/*
//也可以这么定义
var cars=[“我是数组的第1个数据”,”我是数组的第2个数据”,”我是数组的第3个数据”];
*/
//这和php的for差不多的,只是cars.length
//他类似于判断cars里面有多少个元素
</script>