< 返回 6.3 组件的MVC执行流程 - E计划

在这一节我们将学习Joomla组件的MVC结构,了解其各个部分是如何组合在一起的。

1,本节目标


了解Joomla的MVC部分是如何组合在一起的

2,基本的认同


在开始正式说明之前,再次说一下MVC各个部分的功能。

  • M就是model 代表了模型,这一部分主要负责同数据库进行交互。也就是我们的SQL语句应该写在模型中
  • V就是view 代表了视图。这一部分主要负责数据的输出渲染。也就是我们的HTML代码,CSS代码,JS代码应该写在视图中
  • C就是controller 代表了控制器,这一部分主要负责逻辑的处理。也就是我们的控制逻辑应该写在控制器中。比如接受用户的输入,然后调度适当的模型和视图

基本上所有的框架都是这么安排。大家带着这个基本认同来阅读代码就会好理解很多。 

3,页面的执行流程


  1. 用户点击 "ZMAX图书管理组件"进入组件。实际上用户点击的是一个链接,地址为index.php?option=com_zmaxbook.
  2. 因为我们在后台,所以系统会执行administrator下面的index.php文件
  3. 在index.php文件中通过读取option参数的值,决定将控制权交给哪一个组件。因为option=com_zmaxbook.所以,系统会将控制权交给com_zmaxbook组件。
  4. 进入com_zmaxbook组件后,系统会自动的执行组件的入口点文件zmaxbook.php.

入口点文件:

为了使用MVC架构,现在的入口点文件内容如下:

defined('_JEXEC') or die;

//STEP 0:注册辅助的帮助类
JLoader::register('zmaxbookHelper', __DIR__ . '/helpers/zmaxbook.php');

//STEP 1:得到主控制器
$controller = JControllerLegacy::getInstance('zmaxbook');

//STEP 2:得到需要执行的任务
$task = JFactory::getApplication()->input->get('task');

//STEP 3:将任务交给控制器执行
$controller->execute($task);

//STEP 4:控制器将页面重定向
$controller->redirect();

上面的代码非常的经典,几乎所有的组件的入口点文件都是这几行(你只需要将组件的名字改一下就可以用了)。首先加载需要使用的辅助类,然后得到组件的主控制器,得到需要执行的任务,控制器执行完任务后将用户重定向适当的页面。 

说明一下,如果没有其他的类文件需要加载,下面这一行是可以删除的。

JLoader::register('zmaxbookHelper', __DIR__ . '/helpers/zmaxbook.php');

JLoader的register方法有两个参数,一个是需要注册的类的名称,一个是这个类的实现文件。其本质就是引入一个类文件。其实我们可以使用include_once(文件的路径)来代替。

4,控制器


主控制器文件: 

//STEP 1:得到主控制器
$controller = JControllerLegacy::getInstance('zmaxbook');

主控制器文件和入口点文件一样,一个组件只能有一个主控制器文件,其文件名为 controller.php.在组件的文件结构中如图:

得到主控制器,实际上现在执行的就是controller.php这个文件了。在主控制器中我们定义了一个类,这个类的名称也是固定的。

默认格式为: 组件的名称 + Controller 。并且继承 JControllerLegacy类
class zmaxbookController extends JControllerLegacy
{
	/**
	 * 默认的视图.
	 *
	 * @var    string
	 */
	protected $default_view = 'items';
}

这个类非常的简单,没有定义任何的方法,只定义了一个$default_view属性,这个属性决定了组件的默认视图是什么。由于这个类派生自JContollerLegacy类,因此,它也拥有了JContollerLegacy的所有方法。

在接下来的STEP 2中,我们尝试去找task参数

$task = JFactory::getApplication()->input->get('task');

因为请求的URL为index.php?option=com_zmaxbook 并没有指定task参数。因此,在STEP2中的task实际值为空。

在STEP 3中,我们已经知道了$controller实际上就是zmaxbookController类。zmaxbookController并没有实现execute这个方法,因此,执行的是父类的JControllerLegacy的execute方法。

在JControllerLegacy类的execute方法中,如果$task指定了值,那么就会执行该类一个对应的同名方法,如果$task为空,那么就会执行display方法。在STEP 2中,我们得到的$task为空,所以最终执行的是display方法。

在display方法中,会检查url中是否存在view参数,如果没有view参数,那么就会显示默认的视图。

因为我们请求的URL为index.php?option=com_zmaxbook 并没有指定view参数。因此,控制器会使用$this->default_view 的值作为默认的视图。在主控制器类中我们设置 default_view = items。因此,此时系统加载items视图。

当控制器知道需要加载的是哪一个视图的时候,就会自动的引入这个视图的实现文件以及其对应的模型文件,并且执行视图的display方法。

5,视图


joomla的视图文件存放在组件的views目录下面。一个视图对应一个文件夹,且文件夹的名称为视图的名称。在上面已经确定了控制器将执行items这个视图,所以此时系统加载views/items/view.html.php这个文件,并且确定这个文件中定义了类zmaxbookViewItems。如果没有定义,或者找不到这个文件,此时都会提示找不到视图的错误。

请一定要记住约定优于设计,Joomla的MVC之间的自动绑定关系都是依赖约定完成的。当系统需要执行items视图的时候,那么就会默认items视图的实现文件在 views/items/view.html.php中,并且假设视图类为zmaxbookViewItems。没有为什么,这是约定好的。对于初学者最容易出问题的地方就是没有严格的按照约定来命名文件或者类名,最后出现无法理解的错误。

在开发中,对于需要展示一系列的项目的时候(就是需要展示列表的时候),我们一般会将视图的名称以s结尾,比如items。如果在查看一个记录的详情的时候,我们会将视图命名为item(注意没有s) .这样一目了然。

joomla中视图类的命名规则如下:

组件的名称(zmaxbook)  + View  + 视图的名称(Items) .并且所有的视图需要继承 JViewLegacy这个类 
class zmaxbookViewItems extends JViewLegacy
{
	public function display($tpl = null)
	{
		$this->items         = $this->get('Items');
		zmaxbookHelper::addSubmenu('items');
		$this->sidebar = JHtmlSidebar::render();
		
		$this->addToolbar();
		parent::display($tpl);
	}
	
	/**
	 * 添加页面的工具栏.
	 *
	 * @return  void
	 */
	protected function addToolbar()
	{
		JToolbarHelper::title('ZMAX图书管理系统 - 书本管理', 'list');
	}
}

上面是items视图的实现文件,非常的简洁,也非常的经典。大家只需要关注上面高亮的第5行代码。

$this->items         = $this->get('Items');

这行代码的作用是从模型中拿到数据。 按照约定,Items视图默认会绑定一个Items模型(模型和视图的名称是一致的)。调用 $this->get('Items'); 实际上就是调用Items模型的getItems方法。

6,模型


joomla的模型文件存放在组件的models目录下面。一个模型对应一个文件,且文件的名称为模型的名称。模型一般由控制器或者视图自动进行绑定和加载.在items视图中,系统会默认该视图的模型为items模型,该模型实现文件为 models/items.php,并且确定这个文件中定义了类zmaxbookModelItems。如果没有定义,或者找不到这个文件,在一些情况下是允许的。

joomla中模型类的命名规则如下:

组件的名称(zmaxbook)  + Model  + 视图的名称(Items) 

由于模型的情况有多种,比如获取列表的模型,显示一条记录详情的模型,他们的实现是完全不同的。因此,模型的派生类也是不同的,对于列表模型,一般可以派生子JModelList类。 如我们的Items模型就是这种情况。

/**
 * 图书列表的管理模型类.
 *
 * @since  2.0
 */
class zmaxbookModelItems extends JModelList
{
	
	protected function getListQuery()
	{
		//STEP 1:得到数据库的链接对象
		$db = JFactory::getDBO(); 
		$query = $db->getQuery(true);
		$query->select("*")->from("#__zmaxbook_item");
		return $query;
	}
}

在视图中调用 $this->get('Items'); 实际上就是调用Items模型的getItems方法。 我们发现zmaxbookModelItems这个类并没有实现getItems方法,因此,实际上调用的是JModelList类的getItems方法。在JModelList类中,Joomla已经为我们做了很多操作,我们唯一需要做的就是实现getListQuery方法。getListQuery方法要求我们返回一个SQL查询语句。

在Joomla框架中,系统对数据库的链接和查询做了大量的封装,我们只需要使用工厂模式调用 JFactory::getDBO()方法得到数据库对象,就完成了数据库的链接。

		$query = $db->getQuery(true);

 这个代码从数据库中得到一个查询对象JDatabaseQuery,请一定要注意设置它的参数为true.表示拿一个新的查询对象,否则系统会返回上一次的查询对象,造成错误。Joomla的查询对象封装了常用的SQL关键词作为方法。

一个常规的SQL查询语句

SELECT * FROM #__zmaxbook_item

Joomla的方法的查询语句

$query->select("*")->from("#__zmaxbook_item");

更多的关于Joomla数据库的相关操作大家可以查看对应的API.在此不再赘述 

7,布局(layout文件) 


当我们在视图中拿到模型的数据之后,剩下的工作就是最终的渲染出页面了。在Joomla中,我们将最终的渲染页面的代码称之为布局(就是这个页面该怎么布置的意思)。一个视图至少必须有一个布局文件,可以有多个。布局文件存放在对应视图的tmpl文件夹中,如图:

我们可以通过在URL参数中执行layout=XXXX来告诉视图需要使用哪一个布局,如果没有指定layout参数,那么系统默认会使用default布局。进入到default.php中,你就会看到熟悉的PHP,HTML写页面的代码了。

<?php
/**
 *	description:ZMAXBOOK组件 Items视图 布局文件
 *  author:min.zhang
 *  Email:zhang19min88AT163.com
 *	Url:http://www.zmax99.com
 *  copyright:南宁市程序人软件科技有限责任公司保留所有权利
 *  date:2020-10-29
 *  version:v2.0.0
 *  @license GNU General Public License version 3, or later
 */

defined('_JEXEC') or die;
?>
<div id="j-sidebar-container" class="span2">
	<?php echo $this->sidebar; ?>
</div>
<div id="j-main-container" class="span10">
	<table class="table table-striped">
		<thead>
			<tr>
				<th >标题</th>
				<th >作者</th>
				<th >价格</th>
				<th >ID</th>
			</tr>
		</thead>
		<tbody>
		<?php foreach ($this->items as $i => $item) :?>
			<tr>
				<td><?php echo $item->title; ?></td>
				<td><?php echo $item->author; ?></td>
				<td><?php echo $item->price; ?></td>
				<td><?php echo $item->id; ?></td>
			</tr>
		<?php endforeach; ?>
		</tbody>
	</table>
</div> 

8,尾声


至此整个页面就完成了输出。这篇文章写了2天,感觉写的有点长,但也不好切割,不然MVC就不连贯了。希望整个的调用过程给说清楚了,如果大家在看的时候有疑惑或者不明白的地方,可以和我联系。

Email:zhang19min88AT163.com. 请将邮件的主题写为 JOOMLA组件开发 

E计划

第11章:支持多语言
第12章:前台展示组件
第13章:组件开发FAQ
第14章:高级功能
第15章:使用分类
第16章:让组件支持插件
  • 内容提要
  • 留言讨论 (0)
  • 视频教程
在这一节我们将学习Joomla组件的MVC结构,了解其各个部分是如何组合在一起的。

评论 (0)

  • 最新在前
  • 最佳在前

内容待完善

该课程提供视频版,可以观看完整的视频教程