Joomla 2.5 MVC剖析

Joomla整个系统,由core, component, module, plugin组成,而component是唯一拥有数据结构特征的部分,所以joomla把它设计为MVC结构,让数据结构表现更清晰。并且component是joomla扩展开发中最复杂的部分。

Joomla提供了MVC的基类:JView, JModel, JController, JTable。一个完整的joomla MVC,必须从这四个类或者其派生类继承,而Joomla2.5有更丰富的派生类,来满足joomla2.5更多的新特征。可以阅读com_content的代码来了解这个关系。

JView: 视图,包括模板与数据输出逻辑。典型的view.html.php就是JView的一个实现,它的工序是从Model中得到数据,并输出到模板中。

JController: 控制器,一个组件可以有多个控制器,每个控制器会有多个task,它是程序的入口,想要joomla为你做什么,就得给它一个task.例如user.edit, user.save。

JTable: 数据表,它直接与数据库打交道,把数据库表抽象为一个JTable对象。它给Model提供可操作数据,并可以对表操作进行预处理。例如在写入表时title不很空值的判断。一般情况下,它只与Model交互,其它部分最好不要直接使用JTable。

JModel:模型,为系统提供更抽象的数据管理,它的存在,可以使开发人员不必关心数据库操作。

MVC类命名规则

默认情况下,主控制器AController -> 子控制器AControllerB关联(AModelB,TableB,AViewB)

而TableB这个命名容易与其它组件名称冲突,所以一般会在AModelB中给它指定前缀,把TableB改为ATableB。

MVC之类的关系是自动建立的,不需要额外声明。例如在AViewB中使用getModel,系统会自动获取AModelB,在AModelB使用getTable,会自动获取TableB。刚接触Joomla开发的人,可能会因为写错了类名而出现报错。

从零架构一个组件是比较头痛的,因为架构代码也十分多,幸好有在线组件生成器:

http://www.notwebdesign.com/joomla-component-creator/component/combuilder/components

使用它可以根据你定义的表结构生成组件安装包,安装后就能立即拥有后台功能,省去大量的架构时间。 

MVC之间的关系

table是数据结构,它是数据库上存储数据的结构原型。它只能代表一个表。joomla的每个表都必须拥有对应的JTable继承,它给model提供表的细节。只要JTable继承类建好,一般只有在model中会操作它,其它地方不必操作JTable实例。

在JModel中要得到一个JTable:

$table = $this->getTable('Users', 'UsersTable');

如果有必要域跨组件访问table,可以使用以下方法加载其它table路径

JTable::addIncludePath(JPATH_ADMINISTRATOR . DS . 'tables');

model是数据模型,有了它,用户不必了解数据存储的细节,只告诉model你要怎么操作数据,例如你要得到一个users列表;或者删除一个user,告诉它,它会完成你想要的操作。一般要得到某个组件的数据,你先要找到它的JModel继承类,直接与它交互。

Controller与Model有直接关系,所以JController中得到一个JModel有捷径:

$model = $this->getModel('Active', 'UsersModel');

在model中,可能需要使用其它组件的model,例如content与category,model内部得到其它model的方法

JModel::addIncludePath(JPATH_ADMINISTRATOR .DS . 'components' . DS. 'com_content' . DS . 'models');

$model = JModel::getInstance('Articles', 'ContentModel', array('ignore_request' => true));

PS:由于PHP很简单很灵活,可以很多PHPer都不注重开发规范,这样长期下去的结果是项目质量的下降。例如在joomla中想操作数据库,大多数人会直接写SQL,读取写入。这在Joomla1.5中或许没有多大关系,因为joomla1.5的表关联不太紧密。但在Joomla2.5中关联表就很多,例如ACL功能、User group,都有大量的关联表,单纯写入一个表,系统有可能识别不了。在MVC的体系中,Model是专门写数据库打交道的部分,所有SQL应该写在Model,要使用数据时,就调用Model的方法。

调用model例子:

$model = JModel::getInstance('Articles', 'ContentModel', array('ignore_request' => true));

$model->setState('filter.state', 1);

$model->setState('list.ordering', 'publish_up');

$items = $model->getItems();

PS: 如果有ignore_request,就不会调用populateState,即不会从前端提供中得到state。

State

跟model进行交互,最标准的方法就是用state,它是一种类内置的数据结构。

$model = $this->getModel('Active', 'UsersModel');

$model->setState('limit', 5);

$model->getItems();

子控制器

joomla2.5支持一个组件多个子控制器

调用方法:task=控制器后缀名.方法名,即task=user.save, task=users.delete, task=user.edit

如有一子控制器UsersControllerUser,有方法save,调用就为task=user.save

拥有管理功能的控制器

JControllerForm主要用于编辑页面

JControllerAdmin主要用于管理列表页面

列表页使用JControllerAdmin,编辑页使用JControllerForm

子控制器的task表达:task=控制器名.方法名,即task=user.save, task=users.delete, task=user.edit

JControllerForm主要的task有edit, add, save

JControllerAdmin主要的task有delete, publish, saveorder

假如有一个JControllerForm派生类UserController,那它的添加地址是:index.php?option=com_user&task=user.add

修改地址是:index.php?option=com_user&task=user.edit&id=1

它的Edit Form中必须有task=user.save

同理,JControllerAdmin的派生类UsersController,就有task=users.delete, task=users.publish

注意:不要试图使用其它访问地址,如果不使用JControllerForm的task,系统将认为操作来源不可信,会禁止你的操作

拥有管理功能的模型类

JModelAdmin是JModelForm的派生类,对于实现一个完善的管理功能,可以只使用JModelAdmin

使用JModelForm至少需要重写save,getItem,loadFormData与getForm

save: 数据存取时的操作

getItem: 用于提取Item数据用于Form

getForm: 得到表单对象,一般做法是返回loadForm结果,loadForm会读取生成的jform数据,即form目录下的xml文件

loadFormData: 用于生成JForm的默认值,用于Edit Form的数据

使用JModelAdmin只需要重写getItems,loadFormData与getForm

注意:form需要必须带有token, <?php echo JHtml::_('form.token'); ?>

拥有管理功能的模型类

JModelAdmin是JModelForm的派生类,对于实现一个完善的管理功能,可以只使用JModelAdmin

使用JModelForm至少需要重写save,getItem,loadFormData与getForm

save: 数据存取时的操作

getItem: 用于提取Item数据用于Form

getForm: 得到表单对象,一般做法是返回loadForm结果,loadForm会读取生成的jform数据,即form目录下的xml文件

loadFormData: 用于生成JForm的默认值,用于Edit Form的数据

使用JModelAdmin只需要重写getItems,loadFormData与getForm

注意:form需要必须带有token, <?php echo JHtml::_('form.token'); ?>

另外,介绍几个Joomla新增的派生类:

JModelList

在大多数CMS中,分页与排序列表已经是标配功能,开发人员不必浪费时间在分页与排序上,JModelList都已经实现这两项功能。

getItems:得到列表数据,一般Model都用它来得到列表,继承自JModelList就不必对它重载。

getListQuery:抽象方法。查询字串或查询器,这是JModelList独有的方法,供getItems查询数据,order的查询语句必须写在此方法内,limit与pager就不用写。

populateState:在getState时被调用,用于处理前端提交数据,实现用户交互。JModelList已经对它扩展了排序和分页的交互,如需要更多的交互性,可以再重载它。

PS:如果使用model前没有调用getState,将无法接收用户提交的state。

JModelForm

优化model的form能力

loadForm:加载form。(这里的form是joomla2.5的jform,一种用XML定义一个form的技术,所以这个XML文件必须先建好)

getForm:抽象方法。得到一个form实例,通常是通过调用loadForm来得到form实例,再对它进行加工。

loadFormData:抽象方法。给Edit Form提供数据,可以直接使用getItem的数据。

PS:form需要必须带有token, <?php echo JHtml::_('form.token'); ?>,token是一个form的认证签名,为了防止form被跨域提交。

JModelAdmin

功能很丰富的用于管理数据的model,继承自JModelForm,有form与save, delete,publish,saveorder,batch,checkin,checkout等功能

欢迎加入Joomla...