扩展Joomla!的MVC架构
在开发Joomla!扩展时,你是否经常感到自己在重复同样的任务?这在开发任何框架时都是一种常见的感受,但所有框架的共同之处在于,它们使创建可重用代码块变得极其容易。
如果你是Joomla!扩展开发者,你现在能做的最好的事情就是停止将Joomla!视为一个内容管理系统。就在这里,现在,将你脑海中关于为CMS开发扩展的所有想法都抛诸脑后。完成了吗?太好了。
在Joomla!中创建网络应用时,我们很容易仅从内容管理的角度来思考,而忘记了Joomla!框架有多么强大。诚然,该框架是专门为创建一个强大的内容管理系统而开发的。但你可以利用它的力量来创建与内容管理无关、与网络应用开发有关的复杂程序。
作为一名内部开发者;我的本职工作是为我公司基于Joomla!的网站套件创建扩展。这些自定义扩展本身就是完整的网络应用,为我们网站中最繁忙、最复杂的领域提供动力。所有这些都在Joomla!框架内完成。
在我开发的早期,我开始注意到我反复执行一些相同的任务。以下是我记录的列表,不分先后
- 附加JavaScript和CSS文件。
- 创建表单。
- 验证用户输入。
- 访问网络服务。
- 获取文件路径。
- 处理Ajax请求。
在开发应用时,总有一些标准活动会重复出现。例如,我经常需要从提供我们数据跟踪系统访问权限的网络服务中请求数据。不久,我就开始寻找一种方法,将这个繁琐的过程抽象成只需要一个函数就能执行的操作。
那么我们如何确保自己不会重复操作呢?
首先,让我澄清一下修改Joomla!核心类的想法。虽然这很有吸引力。请相信我,我知道。但修改Joomla!核心类是你绝对不应该做的事情。这可能看起来是一个快速的解决方案,但一次操作你就打破了系统所有的未来升级。请让核心类保持原样。
最好是,在Joomla!安装的libraries文件夹中创建自己的库。对于你们开发面向公众的独立扩展的人来说,我明白这可能不是一个选择。但请继续阅读。在打下一些基础之后,我们将解决这个问题。
模型-视图-控制器
Joomla!扩展围绕模型-视图-控制器开发范式,特别是JModel、JView和JController类。几乎所有在屏幕上显示的内容都是以某种方式由这三个核心类处理的。其他类也扮演着一定的角色,但这些都是三个主要角色,是让事情发生的关键类。遗憾的是,它们的用途也有限。
请别误解,这些类在它们被设计要做的任务上做得非常好。然而,你的需求并不等同于Joomla!开发团队的需求。这些类是根据核心扩展的需求来设计的,而且让我们面对现实,你并不是在重新制作核心扩展。你需要一些目前不存在的东西。这也是你开发扩展的原因!
为了说明我在说什么,让我们做一些常见的事情——将JavaScript文件附加到文档标题中。这并不困难,但它可以很快变得重复。这是我如何将JavaScript文件附加到我的组件视图类中的方法。
php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view' );
class TestViewExample extends JView
{
public function display($tpl = null)
{
$document = JFactory::getDocument();
$document->addScript('/components/com_test/assets/javascript/popup_ads.js');
parent::display($tpl);
}
}
检索当前文档实例,并使用其方法之一来附加你组件中定位的JavaScript文件(这是个人喜好——我更喜欢将特定于扩展的脚本和样式表分组在一起)。但是,如果我们需要十个JavaScript文件,再加上几个CSS文件呢?
php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view' );
class TestViewExample extends JView
{
public function display($tpl = null)
{
$document = JFactory::getDocument();
$document->addScript( '/components/com_test/assets/javascript/popup_ads.js' );
$document->addScript( '/components/com_test/assets/javascript/grid.js' );
$document->addScript( '/components/com_test/assets/javascript/maphighlight.js' );
$document->addScript( '/components/com_test/assets/javascript/email.js' );
$document->addScript( '/components/com_test/assets/javascript/validate.js' );
$document->addScript( '/components/com_test/assets/javascript/tokenizer.js' );
$document->addScript( '/components/com_test/assets/javascript/tooltips.js' );
$document->addScript( '/components/com_test/assets/javascript/ajaxlib.js' );
$document->addScript( '/components/com_test/assets/javascript/header.js' );
$document->addStyleSheet( '/component/com_test/assets/css/main.css', 'text/css');
$document->addStyleSheet( '/component/com_test/assets/css/grid.css', 'text/css');
$document->addStyleSheet( '/component/com_test/assets/css/ui.css', 'text/css');
parent::display($tpl);
}
}
这不是一个不可预见的情况。高度交互的网页(想想全功能的Web 2.0)通常有多个JavaScript/CSS文件。然而,这却是只有微小差异的信息被重复了十次。不仅如此,假设你开发的每个扩展都使用了相同的assets/javascript/file.js基本结构。如果你能简单地输入tokenizer.js并完成,那岂不是很好?你可以做到!
创建一个中心位置并开始构建
如果你还没有,在你的Joomla!安装的/libraries文件夹中创建一个新的目录。这将成为你创建的任何自定义类的中心位置。
注意:这将使你在工作时导入文件变得更容易。通过使用这种结构,你将能够使用jimport函数快速包含类,但你也可以选择使用更高级的JLoader类,这将使你从必须将库放在Joomla!文件树中解放出来。
我的库将命名为Custom,尽管你当然可以使用你想要的任何名字。在这个新目录中创建一个名为customview.php的文件,并将以下代码放在其中。
php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view');
class CustomView extends JView
{
public $_assetpath; //path to the asset folder of the component
public $_document; //shortcut to the JDocument instance
public function __construct($config = array())
{
//Automatically include the JDocument instance
$this->_document = JFactory::getDocument();
//Save the path to our asset folder
$this->_assetroot = JURI::base(true).'/components/' . JRequest::getCmd('option') . '/assets/';
parent::__construct($config);
}
/**
* Attaches a Javascript file in the assets/javascript folder of the component
* @param $filename
*/
public function addScript($filename)
{
$this->_document->addScript($this->_assetroot . 'javascript/'.$filename);
}
}
我们刚刚做了什么?我们创建了一个继承JView所有功能的类,并添加了我们自己的方法 addScript,这将使我们能够轻松地将存储在com_mycomponent/assets/javascript/ 中的JavaScript文件附加到项目中。由于这是一个通用的类,与任何特定组件无关,我们创建并定义的 $_assetroot 将适应任何继承此类的组件。只要该组件遵循您定义的标准目录结构,附加文件的过程就变得简单多了。
请注意,我们已经定义了魔法方法 __construct()。如果你看看 JView 类,你会发现它定义了 __construct() 并执行了许多对请求操作至关重要的任务,而这些任务我们无法没有。这里你有几个选择——你可以自己重新定义所有这些操作,或者可以将责任交给 JView,这正是我们在代码行 parent::__construct(); 中所做。这允许我们在不重复JView已经为我们处理的事情的情况下执行自己的工作。
注意:这是一个重要的概念,要记住:在扩展核心MVC类时,你几乎总是需要将控制权交回父类。在扩展它们之前研究JModel、JView和JController的工作是一个好主意。
现在我们有了自己的定制视图类,我们实际上该如何使用它呢?如果你还没有,请创建一个新的组件并创建一个视图。使用CustomView类,我们的第一个示例将如下所示。
php
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'Custom.customview' );
class TestViewExample extends CustomView
{
public function display($tpl = null)
{
$this->addScript( 'popup_ads.js' );
parent::display($tpl);
}
}
代码量明显减少,对吧?事实上,如果你将其应用到我们之前提到的十个文件示例中,这个过程就变成了一个相对简单的循环(或者编写一个接受文件数组的方法)。
我希望你开始看到这里的潜力。诚然,这只是一个非常简单的示例,展示了你可以利用的众多可能性,但正如我之前所指出的,你的需求将与每个人不同。
一旦你养成了抽象重复性任务的习惯,你会发现你的开发工作变得更加流畅,打字的工作量也会减少。考虑探索JController和JModel,并尝试思考如何通过扩展它们来节省时间。
发表在Joomla社区杂志上的一些文章代表了作者对特定主题的个人观点或经验,可能并不与Joomla项目的官方立场一致
通过接受,你将访问由 https://magazine.joomla.net.cn/ 外部的第三方提供的服务
评论