当mint满足不了你的需求时,你可以很方便地扩充它。
新建组件可以分为两步
新建组件类,必须实现接口 IMintComponent ,它定义了四个方法。现在不必直接实现它,只须实现抽象类IAbstractMintComponent就可以了,这个抽象类含有很多有用的方法,可以帮助我们轻松处理DOM节点。
添加组件类,并给它命名,让mint知道该组件的存在。
完成这两步之后就可以直接在模板中使用了。
让我们先创建一个简单的组件。
例 5.4. MyComponent - 自定义的组件类
class MyComponent extends IAbstractMintComponent {
//定义支持的参数
public function getSupportedParameters() {
return array("i", "j");
}
//处理组件
public function processComponent() {
$params = $this->getParameters();
if (!isset($params["i"]) || !isset($params["j"])) {
return false; // 不执行任何操作
}
$i = $params["i"];
$j = $params["j"];
$this->addFirstChildText($i + $j); // 在节点的第一个子元素前加一个数字
return true;
}
}
该组件实现了IAbstractMintComponent定义的两个抽象方法 getSupportedParameters 和 processComponent,前者定义了我们的组件可以接受的参数名列表(i和j),后者处理组件,只是简单的获取参数值,并将结果附加到当前节点的第一个子节点之前。现在添加组件,并使用IModelAndTemplate视图方案:
public function appIndex() {
IMint::setOptions(array("template-dir"=>"./template", "compile-dir"=>"./compile-dir", "mode"=>"debug"));
//添加组件
IMint::addComponentProcessor("@my", "MyComponent");
return new IModelAndTemplate($this, "test");
}
我们把组件命名为@my,以@开头只是我们的习惯,并不是必须的。
这里我们使用了$this作为数据模型传入了IModelAndTemplate,这是为了很方便地加入新的对象,无需再新建一个对象容器。
现在在模板中使用组件:
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<title>test</title>
</head>
<body>
<span com="@my" i="2" j="1.6"></span>
</body>
</html>
分析结果为:
<span>3.6</span>
正好符合我们的期望。使用
<span com="@my" i="20" j="1.6"></span>
得到的结果是
<span>21.6</span>
在这个例子中,我们的i和j两个参数都是固定的,如果换成变量会怎么样?你可能期望也能正常工作,但事实上不是的,mint在第一次编译之后,除非在debug模式下,否则就不再调用任何组件,因为我们已经从模板中编译出一个已经能工作的.php文件,无需再次分析。也就是说组件只在第一次分析模板的时候是有用的,processComponent方法对同一个组件来说只被调用一次,所以即时你多次传入不同的变量也只能得到第一次的结果。庆幸的是,我们可以在processComponent中给编译文件加入一些PHP代码,让编译文件在运行期决定怎么处理变量。现在改造上面的例子
例 5.5. MyComponent2 - 升级版
class MyComponent2 extends IAbstractMintComponent {
//定义支持的参数
public function getSupportedParameters() {
return array("i", "j");
}
//处理组件
public function processComponent() {
$params = $this->getParameters();
if (!isset($params["i"]) || !isset($params["j"])) {
return false; // 不执行任何操作
}
$i = IMintVariable::getDefinition($params["i"]); // 这时候得到的是变量名
$j = IMintVariable::getDefinition($params["j"]);
$this->addFirstChildText("<?php echo {$i}+{$j};?>"); // 哇,我们加入了PHP代码 。。。
return true;
}
}
修改appIndex方法
public function appIndex() {
IMint::setOptions(array("template-dir"=>".", "compile-dir"=> "./compile-dir", "mode"=>"debug"));
//添加组件
IMint::addComponentProcessor("@my", "MyComponent");
IMint::addComponentProcessor("@my2", "MyComponent2");
$this->i = 2;
$this->j = 1.6;
return new IModelAndTemplate($this, "test");
}
修改模板
<span com="@my2" i="$i" j="$j"></span>
原来的常量变成了i和j两个变量,并可以由appIndex方法传入,现在的分析结果同样是
<span>3.6</span>
现在你就可以在appIndex方法中随意改变$this->i和$this->j的值了,每一次浏览器上将输出不同的值。
正如我们上面所说,任何系统函数和用户自定义函数都可以作为修饰,它把mint变量当作第一个参数传入。
对于程序
$this->string = "abcdefg";
$this->array = array(1, 2, 3, 4);
可以使用
{$string|strlen}
{$array|count}
{$array|array_sum}
可以分别得到7、4和10三个数字。我们可以随意再定义一个针对数组的处理函数:
function myjoin(array $array, $char) {
return implode($char, $array);
}
然后在模板中使用它:
{$array|myjoin('a')}
传入了一个参数“a”作为连接字符,分析结果为:
1a2a3a4
当然了,你可以让myjoin接受更多的参数,只需在使用的使用用分号分隔开来即可。
还可以通过使用OO的方式加入一个新的修饰,先定义MyJoinModifier类,它继承自IAbstractMintModifier,并实现了IMintModifier接口定义的__construct和execute两个方法:
class MyJoinModifier extends IAbstractMintModifier {
public function __construct() {
//do nothing
}
public function execute() {
$arguments = $this->getArguments();
$char = isset($arguments[0])?$arguments[0]:" ";
return implode($char, $this->getVariable());
}
}
然后在使用它之前调用
IMint::addModifierProcessor("myjoin", "MyJoinModifier");
添加一个修饰并把它命名为myjoin即可。