Drupal-7 如何在不覆盖现有格式化程序的情况下调用 hook_field_[formatter_]prepare_view()
Drupal-7 how to get hook_field_[formatter_]prepare_view() invoked without overwriting existing formatter
在我的模块中,我正在寻找一种在渲染过程中更改文本字段值的方法,但不创建新的格式化程序,并且在当前受影响的格式化程序工作之前。
换句话说,我希望我的更改总是在任何文本字段上进行,作为一个通用的准备步骤,而不管之后将使用哪个格式化程序。
要实现这一点:
我首先考虑使用hook_field_formatter_prepare_view()
。
为了调用它,我想使用 hook_field_formatter_info_alter()
将我的模块名称添加到此处找到的每个相关格式化程序。但它
似乎 "module" 索引只接受唯一的模块名称,
不是数组。
顺便说一句,我对这种缺失感到非常惊讶:我似乎允许一系列格式化程序是有意义的,比如允许一系列
过滤器!
- 然后我考虑使用
hook_field_prepare_view()
,这似乎
成为最佳候选人,因为医生说它在
格式化程序拥有 hook_field_formatter_prepare_view()。但是那个
也不起作用:此挂钩仅针对由创建的字段调用
涉及的模块(这个问题已经讨论过here)。
有什么想法吗?提前致谢。
我实际上找到了一种很好的方法来完成我想要的事情。
该方法具有相当大的侵入性,但效果很好,可以在不同情况下重复使用。
1.为了尽可能清楚,首先我用
一般用例:
In the rendering process, how to permit a module to change value of one or more
fields (given field-id, given field-type...) before the formatter (if any) do its own job?
2。完成这个问题:
We can't make the module define a new formatter, because only one may
be defined at the same time for the same field
3。使我达到预期结果的策略:
- 使用
hook_field_formatter_info_alter()
到 运行 通过现有的格式化程序和 "graft" 我的模块在我希望干预的地方
(详见下方 4)
- 使用
hook_field_formatter_prepare_view()
来:
(a) 对字段值执行所需的更改
(我的模块旨在完成或不完成的工作,取决于给定类型的所有字段或精确标识的字段等,具体取决于任何详细需求)
(b) 再次 运行 通过格式化程序列表,并在涉及时触发它们自己的 hook_field_formatter_prepare_view()
如果它存在
(详见下文 5)
- 执行与上面 (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(
# ...
),
# ...
);
我们可以轻松地 运行 通过格式化程序列表并查看 "field types" 索引到 select 哪些是我们需要关注的。
然后对于每一个涉及的,我们可以:
- 将我们自己的模块名称替换为 "module" 索引中的格式化程序模块名称
- 在"settings"索引中添加一个新的子索引(比如"our module graft")以注册原始格式化程序模块名称
所以我们的 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';
}
}
}
}
一旦刷新 class 注册表,现在所有涉及的字段都将其格式化阶段重定向到我们自己的模块。
注意:安装新的格式化程序现在需要再次刷新 class 注册表,以便我们的模块也能使用它。
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);
}
}
希望这对您有所帮助...
在我的模块中,我正在寻找一种在渲染过程中更改文本字段值的方法,但不创建新的格式化程序,并且在当前受影响的格式化程序工作之前。
换句话说,我希望我的更改总是在任何文本字段上进行,作为一个通用的准备步骤,而不管之后将使用哪个格式化程序。
要实现这一点:
我首先考虑使用
hook_field_formatter_prepare_view()
。为了调用它,我想使用
hook_field_formatter_info_alter()
将我的模块名称添加到此处找到的每个相关格式化程序。但它 似乎 "module" 索引只接受唯一的模块名称, 不是数组。
顺便说一句,我对这种缺失感到非常惊讶:我似乎允许一系列格式化程序是有意义的,比如允许一系列 过滤器!- 然后我考虑使用
hook_field_prepare_view()
,这似乎 成为最佳候选人,因为医生说它在 格式化程序拥有 hook_field_formatter_prepare_view()。但是那个 也不起作用:此挂钩仅针对由创建的字段调用 涉及的模块(这个问题已经讨论过here)。
有什么想法吗?提前致谢。
我实际上找到了一种很好的方法来完成我想要的事情。
该方法具有相当大的侵入性,但效果很好,可以在不同情况下重复使用。
1.为了尽可能清楚,首先我用 一般用例:
In the rendering process, how to permit a module to change value of one or more fields (given field-id, given field-type...) before the formatter (if any) do its own job?
2。完成这个问题:
We can't make the module define a new formatter, because only one may be defined at the same time for the same field
3。使我达到预期结果的策略:
- 使用
hook_field_formatter_info_alter()
到 运行 通过现有的格式化程序和 "graft" 我的模块在我希望干预的地方
(详见下方 4) - 使用
hook_field_formatter_prepare_view()
来:
(a) 对字段值执行所需的更改
(我的模块旨在完成或不完成的工作,取决于给定类型的所有字段或精确标识的字段等,具体取决于任何详细需求)
(b) 再次 运行 通过格式化程序列表,并在涉及时触发它们自己的hook_field_formatter_prepare_view()
如果它存在
(详见下文 5) - 执行与上面 (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(
# ...
),
# ...
);
我们可以轻松地 运行 通过格式化程序列表并查看 "field types" 索引到 select 哪些是我们需要关注的。
然后对于每一个涉及的,我们可以:
- 将我们自己的模块名称替换为 "module" 索引中的格式化程序模块名称
- 在"settings"索引中添加一个新的子索引(比如"our module graft")以注册原始格式化程序模块名称
所以我们的 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';
}
}
}
}
一旦刷新 class 注册表,现在所有涉及的字段都将其格式化阶段重定向到我们自己的模块。
注意:安装新的格式化程序现在需要再次刷新 class 注册表,以便我们的模块也能使用它。
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);
}
}
希望这对您有所帮助...