JController及其子类的用法概述

From Joomla! Documentation

This page is a translated version of the page JController and its subclass usage overview and the translation is 100% complete.

Other languages:
English • ‎español • ‎français • ‎Nederlands • ‎中文(中国大陆)‎

在阅读本文前,你应该先熟悉 Joomla! MVC设计模式。

介绍

我们在Joomla! 2.5和3.x中,加入了大量的MVC优化。这使得开发变得更高轻松。在Joomla! 1.5时,只有一个Controller,那就是JController。在Joomla! 2.5中,我们除了有一个JControllerLegacy外,又添加了两个JControllerLegacy的子类,即:JControllerAdminJControllerForm。当然了,既然是三个类,使用起来肯定也不一样。我们在Joomla!的核心组件中,大量的使用了这种新的模式,比如: com_contentcom_banners

Joomla 1.5 Joomla 2.5 Joomla 3.0 及以上版本
JController JController

2.5.5以后,为了兼容性,使用JControllerLegacy

JControllerLegacy
JControllerAdmin JControllerAdmin
JControllerForm JControllerForm
JControllerBase (new MVC)

如果你查看后台管理组件com_content的核心代码,就不难发现:在两个地方出现了controller,分别是组件的根目录及controllers文件夹。在根文件夹中,存在一个名为'controller.php'的文件,它是当前组件的入口文件。在这个文件中,有一个直接继承于JControllerLegacy的类。在controller文件夹中,则存在很多个文件,这些文件均以入口关键字命名,比如:article和articles.而这些文件中的类,要么继承了JControllerAdmin,要么继承了JControllerForm

主控制器

JControlerLegacy默认的task是display(译者注:task是个参数,通过GET方法传递,display是JControllerLegacy中的一个方法) , 在根目录中的主控制器(controlelr)是响应task的唯一文件。我们找到com_content/content.php去查看里面的JControllerLegacy::getInstance方法,不难发现,这个方法中,模块名成为了唯一的参数。在LControllerLegacy中,使用task变量(从request中获取,一般为GET)来确定下一步,要去加载哪个类。如果在task变量中,包括一个英文的句话(点),即(.),则 点 前的为controller,点后的为task或是method。即controller.task 或 controller.method。 我们应该知道task变量,直接决定了后台执行哪个控制器(controller)中的哪个方法(method)。此例中(指task=controller.task),将加载controllers文件中的controller.class类,然后再重写task变量值为真正的task。如果task变量中没有 点(.) ,JControllerLegacy 则将加载根目录下的主控制器文件。简单来说,我们可以认为在controllers文件夹中的控制器是子控制器,只有当task中包括有 点 号时,才会调用。 在主控制器中,还指定了一个默认的视图(view),我想这点你已经注意到了。变量VIEW的值,也是由URL请求来传入的,如果URL中并未传入VIEW,那么我们在主控制器中设置的视图,将做为默认视图。一般而言,我们可以这样认为:

  • 如果需要调用主控制器,那么直接在URL请求中,传入view值即可。未传入view值,主控制器虽然也会被调用,但将使用默认视图。
  • 如果要调用子控制器,那么需要在请求的task变量中,加入 点 号.比如CONTROLLER_NAME.CONTROLLER_METHOD。此时,将调用子控制器CONTROLLER_NAME中的CONTROLLER_METHOD方法。

我们可以把显示(display)总结为两种:1.数据列表,即显示一页数据。2.某条数据的详情(比如:"edit form")。我们用普通后台用户登陆后,打开文章管理,根据用户的不同,后台显示的按钮也不同。

$JOOMLA_INSTALL/administrator/components/com_content/views/articles/view.html.php

 protected function addToolbar()
 {
   ...

   if (($canDo->get('core.edit')) || ($canDo->get('core.edit.own'))) {
     JToolBarHelper::editList('article.edit');
   }

   ...
  }

比如说:当我们编辑一篇文章时,task变量的值应该设置为article.edit。这将加载article子类中的edit方法。这时候,你可能要问了,这意味着我们将为用户显示一个编辑的表单。是的,的确如此!一般情况下,我们的确需要这样做,但是在joomla! 2.5的核心组件中,我们需要做的是,将要编辑的article id 存入session,同时,将URL指向为&view=article&layout=edit就可以了。此URL将直接交给主控制器处理, 同时编辑表单也会显示给用户。在这个实例中,我们发现,所以的显示(display)都会按view变的值来交给主控制器处理。

  • 如果在URL中未设置view,那么view将被设置为主控制器的默认值,并执行默认的display(即:task="display")方法。比如:index.php?option=com_content.
  • 如果定义了view,但是task没有定义,那么主控制器将加载传入的view,并执行特定VIEW中的display方法。这种方法同样适用于显示数据列表,比如:index.php?option=com_content&view=articles.
  • 如果即定义了view,又定义了task(task中没有 点 号),那么主控制器加加载定义的view,并执行了view中的task方法。这种情况适用于显示编辑表单或显示某条记录。比如:index.php?option=com_content&view=article&layout=edit.

当主控制器创建一个VIEW时,它将自动去加载当前VIEW的同名MODEL,并将此MODEL推向VIEW。接着,主控制器将继续调用view的display方法。在VIEW中,我们可以使用GET方法来获取数据,比如$this->get("Items")。这条语句的作用是调用model中的getItems方法。通过这种方式,我们可以仅仅使用一个控制器来显示组件中的所有信息(即把显示数据与处理数据相分离)。当然了,虽然控制器可以使用了一个,但VIEWS还是需要多个的。这样将明显减少控制器的数量及编码工作量。

子控制器

子控制器承接了所有的CRUD任务(tasks)。保存(save),删除(delete),发布(publish)都是直接触发修改数据库,因而是不需要VIEW的,子控制器中,直接完成数据删除或是更新操作后,再重定向就可以了。在刚刚的举例中,还需要一个前提,就是需要选择一条数据,然后在进行操作。通常,我们喜欢这样命名这些task,比如"articles.delete", "articles.publish_up" or "articles.publish_down"。考虑到并不需要显示信息的实际情况,我们在JControllerAdmin(类似于artilces的子类继承于此)禁用了display()方法。

其它类型的CRUD,比如add 、edit,乍一看我们需要先从数据库取数据,然后在把数据组织好后展现给用户。但有了Joomla 2.5,一切都被改变了。以ContentControllerArticle为例,它继承了JControllerForm,可我们无论在ContentControllerArticle并没有看到返回表单信息。在实际的处理过程中,我们仅仅是子类中对将ID加入SESSION。然后重定向到主控制器(即:只要是显示给用户信息,肯定是主控制器来完成的)。由于没有设置task变量的值,所以将调用主控制器的display方法。

举例:子控制器接收请求:task=article.edit and cid[]=3。接收后,子控制器先将cid[]=3放入session,然后创建一个这样的URL:"index.php?option=com_content&view=article&layout=edit",将在内部调用该URL。