我实际上找到了一种很好的方法来做我所寻找的。
该方法非常具有侵入性,但效果很好,并且可以在不同情况下重复使用。
1.为了尽可能清楚,首先我根据一般用例重新表述我的问题:
在渲染过程中,如何允许模块在格式化程序(如果有)完成自己的工作之前更改一个或多个字段的值(给定字段id,给定字段类型......)?
2. 完成这个的问题:
我们不能让模块定义一个新的格式化程序,因为同一字段只能同时定义一个
3. 导致我达到预期结果的策略:
- 用于
hook_field_formatter_info_alter()
运行现有的格式化程序并将我的模块“移植”到我希望干预的那些内部
(请参阅下面的 4 下的详细信息)
- 用于
hook_field_formatter_prepare_view()
:
(a)在字段值中执行所需的更改
(我的模块打算执行的工作:在这里它可以完成或不完成,在给定类型的所有字段或精确识别的字段等上,取决于任何详细的需求) (b) 再次运行格式化程序列表,并在涉及时
触发自己的格式化程序 (请参阅下面 5 下的详细信息)hook_field_formatter_prepare_view()
- 执行与上述 (b) 相同的工作,依次为任何其他可能涉及的任何格式化程序的钩子:
hook_field_formatter_view()
hook_field_formatter_setting_form()
hook_field_formatter_setting_summary()
4. 过程中如何嫁接我的模块:
hook_field_formatter_info_alter(&$info)
我们面临以下 $info 结构:
$info = array(
['formatter machine name'] = array(
['label'] => 'Human readable formatter description',
['field types'] => array(
[0] => 'a_field_type,
[1] => 'another_field_type',
# ...
),
['settings'] => array(
['option A'] => 'option A value',
['option B'] => 'option B value',
# ...
),
['module'] => 'formatter_module_name',
),
['formatter machine name'] = array(
# ...
),
# ...
);
我们可以轻松地浏览格式化程序列表并查看“字段类型”索引以选择我们需要关注的那些。
然后对于每一个涉及的,我们可以:
- 将我们自己的模块名称替换为“模块”索引中的格式化模块名称
- 在“设置”索引中添加一个新的子索引(比如“我们的模块移植”)以注册原始格式化程序模块名称
所以我们hook_field_formatter_info_alter()
将是这样的:
function mymodule_field_formatter_info_alter(&$info) {
if($info) {
foreach($info as $name=>$formatter) {
if(
!@$formatter['settings']['mymodule graft'] # or already grafted
and
array_intersect($formatter['field types'],
array('text','text_long','text_with_summary')) # here it is for text fields only
) {
# substitute mymodule to original module:
$info[$name]['settings']['mymodule graft']=$formatter['module'];
$info[$name]['module']='mymodule';
}
}
}
}
一旦刷新类注册表,现在所有涉及的字段都将其格式化阶段重定向到我们自己的模块。
注意:安装一个新的格式化程序现在需要再次刷新类注册表,以便我们的模块也可以使用它。
5.关于如何使原始格式化程序在我们之后工作的详细信息:
如上所述,现在是我们自己的模块在必须格式化字段时收到通知,而不是最初受影响的格式化程序。
所以我们必须在我们的 中做出反应hook_field_formatter_prepare_view()
,它应该看起来像:
function mymodule_field_formatter_prepare_view(
$entity_type,$entities,$field,$instances,$langcode,&$items,$displays
) {
# here we do our own job with field values:
if($items) {
foreach($items as $nid=>$node_data) {
# ...
}
}
# then we give original formatter a chance to execute its own hook:
foreach($displays as $display) {
$hook=
$display['settings']['mymodule graft'].'_field_formatter_prepare_view';
if(function_exists($hook)) {
$hook(
$entity_type,$entities,$field,$instances,$langcode,$items,$displays
);
}
}
}
最后,我们还必须给其他格式化程序钩子执行的机会。
对于每一个,它应该看起来像(用每个钩子的正确数据替换 HOOK 和 ARGS):
function mymodule_field_formatter_HOOK(ARGS) {
$hook=$display['settings']['mymodule graft'].'_field_formatter_HOOK';
if(function_exists($hook)) {
return $hook(ARGS);
}
}
希望这可以帮助...