也说Solar自定义Filter
@life在Solar自定义Filter过滤器一文中讲述了如何在Solar中添加自己的过滤器,讲得很不错。呵呵:), @life和@libear加入Solar 中国没多长时间,但贡献却非常突出,给Solar 中国注入了更有活力的思想。
回到正题,本文也是讨论在Solar中自定义Filter,那么为什么要写一篇同样主题的文章呢?看完你就知道了。
讲这个之前我认为有必要先讲一下life提到的自定义Filter如何实现的。那么之前又还要再讲一下Solar\_Sql\_Model\_Record这个类。 关于这个类,相信大家不会陌生,当我们每次从对象注册表中获取模型目录对象后,再利用模型对象获取的就是Record对象。
$this->_model = Solar_Registry::get('model_catalog');
// $this->item就是模型记录对象
$this->item = $this->_model->currentProducts->fetchNew();
$this->form = $this->item->newForm(array(
'digs_out' => array('label' => '请输入免单需顶数:',),
'discout' => array('label' => '请输入折扣:','invalid' => array('hello, libear', 'hello, life')),
'product_id' => array('type' => 'hidden',),
'period_id' => array('type' => 'hidden',),
));
这就创建了大家非常熟悉的form对象,之后怎么做大家都知道的。那么filter是在什么时候验证的呢?如何保证Solar能找到我们自定义的Filter呢?
filter事件是在$this->item->save()方法调用的时候触发的,来看代码:在Solar\_Sql\_Model\_Record::save()方法又调用了Solar\_Sql\_Model\_Record::\_save()方法,在\_save()方法中判断当前的保存操作是插入还是更新:
// insert or update based on newness
if ($this->isNew()) {
$this->_insert();
} else {
$this->_update();
}
在Solar\_Sql\_Model\_Record::\_insert()和Solar\_Sql\_Model\_Record::\_update()方法中分别调用了Solar\_Sql\_Model\_Record::filter()方法。当参数为空时,filter方法直接调用Solar\_Sql\_Model\_Record::newFilter()方法,获得当前的filter对象,进行验证并准备好invalid消息:
// apply filters
$valid = $filter->applyChain($this);
// retain invalids
$invalid = $filter->getChainInvalid();
// ...省略部分代码
// was it valid?
if (! $valid) {
// use custom validation messages per column when available
foreach ($invalid as $key => $old) {
$locale_key = "INVALID_" . strtoupper($key);
$new = $this->_model->locale($locale_key);
if ($new != $locale_key) {
$invalid[$key] = $new;
}
}
$this->_invalid = $invalid;
throw $this->_exception('ERR_INVALID', $this->_invalid);
}
那么Solar这样就能找到我们自定义的Filter么?还是不行,还要继续看Solar\_Sql\_Model\_Record::newFilter()方法, newFilter()方法的主要工作是实例化当前的Filter对象,
// create a filter object based on the model's filter class
$filter = Solar::factory($this->_model->filter_class);
大家肯定想了解下$this->\_model->filter\_class的内容吧?:) 还要麻烦大家查看一下Solar\_Sql\_Model::\_fixFilterClass()方法。这个方法设置了当前的Filter类。
$this->_filter_class = $stack->load('Filter');
接着,Solar\_Sql\_Model\_Record::newFilter()把filter规则加入Filter对象,最后把本地字符串的对象设置为当前过滤器。filter规则来自几个方面:
- 在模型文件中定义的, i.e., $this->\_addFilter()
- 手动使用$this->addFilter定义的
- 表中定义为非空的及自动增长的字段
// set filters as specified by the model
foreach ($this->_model->filters as $key => $list) {
// skip table cols that are not part of the fetch cols
if (in_array($key, $skip)) {
continue;
}
$filter->addChainFilters($key, $list);
}
// set filters added to this record
foreach ($this->_filters as $key => $list) {
$filter->addChainFilters($key, $list);
}
// set which elements are required by the table itself
foreach ($this->_model->table_cols as $key => $info) {
if ($info['autoinc']) {
// autoinc are not required
$flag = false;
} elseif (in_array($key, $this->_model->sequence_cols)) {
// auto-sequence are not required
$flag = false;
} else {
// go with the col info
$flag = $info['require'];
}
// set the requirement flag
$filter->setChainRequire($key, $flag);
}
// tell the filter to use the model for locale strings
$filter->setChainLocaleObject($this->_model);
这一部分算是讲完了,但是如果仅仅是这样处理的话当我们使用Solar\_Form创建表单并加入filter规则的时候,系统会提示找不到filter规则,因为Solar仅在Solar\_Filter\_名字空间下查找我们自定义的Filter对象,而我们自定义的Filter对象在Admin\_Filter\_名字空间下,也就是说系统根本没有实例化Admin\_Filter类。在上面的解决方案中,Solar\_Sql\_Model\_Record实例化了Admin\_Filter,并使用Admin\_Filter进行filter操作,因为这里没有用到模型,所以我们只能手动操作。
首先,在config.php文件中加入Solar\_Filter的配置项,把Admin\_Filter\_名字空间加入Solar\_Filter::\_stack中:
$config['Solar_Filter'] = array(
'classes' => array('Admin_Filter'),
);
这样的话系统就能找到我们自定义的filter了,不过local string仍然不行,我们还需要手动设置当前的filter local object,有两种方法:
- 通过Solar\_Fomr::setFilterLocaleObject方法手动设置filter local object
$filter = Solar::factory("Admin_Filter");
$this->form->setFilterLocaleObject($filter);
- 在实例化Solar\_Form时指定local filter object
$this->form = Solar::factory("Solar_Form",
array('filter' => Solar::factory('Admin_Filter')));
可以看到不管用哪种方法都需要手动实例化Admin\_Filter类。
下一篇讲讲Solar\_Form、Solar\_Sql\_Model\_Record和Solar\_Filter三者交织在一起的复杂关系。