作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
有时候,一个字段模块自己提供的格式器,可能会出现不够用的情况,比如说图片字段,在Drupal7里面,它的格式器可以用来显示原始图片、各种缩略图,但是无法显示图片的链接。如果使用views模块的时候,想输出图片字段的URL,默认是不可能的,当然我们可以通过定制views的模板文件,来输出图片的URL。如果我们能够为图片提供一个URL路径格式器,就可以解决上述的问题了。
是的,在drupal.org上就存在着这样的一个第三方模块“Image URL Formatter”,专门来解决这个问题的,这个项目地址是http://drupal.org/project/image_url_formatter。我们来学习一下这个模块,这个模块的代码大部分是从image模块中直接拷贝过来的。
/**
* Implements hook_field_formatter_info().
*/
function image_url_formatter_field_formatter_info() {
$formatters = array(
'image_url' => array(
'label' => t('Image URL'),
'field types' => array('image'),
'settings' => array('image_style' => '', 'image_link' => ''),
),
);
return $formatters;
}
我们在这里为image字段定义了一个新的格式器“Image URL”,顾名思义,它就是用来输出图片的URL路径的。
/**
* Implements hook_field_formatter_settings_form().
*/
function image_url_formatter_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$image_styles = image_style_options(FALSE);
$element['image_style'] = array(
'#title' => t('Image style'),
'#type' => 'select',
'#default_value' => $settings['image_style'],
'#empty_option' => t('None (original image)'),
'#options' => $image_styles,
);
$link_types = array(
'content' => t('Content'),
'file' => t('File'),
);
$element['image_link'] = array(
'#title' => t('Link image url to'),
'#type' => 'select',
'#default_value' => $settings['image_link'],
'#empty_option' => t('Nothing'),
'#options' => $link_types,
);
return $element;
}
这里的定义和核心image模块中的对应实现完全一致。我们创建一个节点类型,并为其添加图片字段,然后启用这个模块,在管理显示页面,假定我们选择了Image URL作为显示格式,如图所示:
图片在管理显示页面的对应项
当我们点击最右边的配置按钮时,就会出现更多的配置选项,如图所示:
格式器自带的设置项
上述代码就对应于右边的两个配置项。这下我们明白了钩子hook_field_formatter_settings_form是用来做什么的。在这个钩子里面,API函数image_style_options值得学习一下,它用来获取图片的样式选项。
/**
* Implements hook_field_formatter_settings_summary().
*/
function image_url_formatter_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = array();
$image_styles = image_style_options(FALSE);
// Unset possible 'No defined styles' option.
unset($image_styles['']);
// Styles could be lost because of enabled/disabled modules that defines
// their styles in code.
if (isset($image_styles[$settings['image_style']])) {
$summary[] = t('URL for image style: @style', array('@style' => $image_styles[$settings['image_style']]));
}
else {
$summary[] = t('Original image URL');
}
$link_types = array(
'content' => t('Linked to content'),
'file' => t('Linked to file'),
);
// Display this setting only if image is linked.
if (isset($link_types[$settings['image_link']])) {
$summary[] = $link_types[$settings['image_link']];
}
return implode('<br />', $summary);
}
上述代码就对应于图片字段,最右边配置按钮前面的那段描述,如图所示:
格式器具体配置的描述
这个钩子hook_field_formatter_settings_summary,就是为格式器的当前具体配置,返回一个简洁的描述,方便用户浏览。
/**
* Implements hook_field_formatter_view().
*/
function image_url_formatter_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
switch ($display['type']) {
case 'image_url':
// Check if the formatter involves a link.
if ($display['settings']['image_link'] == 'content') {
$uri = entity_uri($entity_type, $entity);
}
elseif ($display['settings']['image_link'] == 'file') {
$link_file = TRUE;
}
foreach ($items as $delta => $item) {
if (isset($link_file)) {
$uri = array(
'path' => file_create_url($item['uri']),
'options' => array(),
);
}
//debug($item);
$element[$delta] = array(
'#theme' => 'image_url_formatter',
'#item' => $item,
'#image_style' => $display['settings']['image_style'],
'#path' => isset($uri) ? $uri : '',
);
}
break;
}
return $element;
}
在这段代码中,我们返回了图片的呈现数组,在这个呈现数组的每个delta项中,对应的主题函数替换为了theme_image_url_formatter,而不是image模块里面的theme_image_formatter。这里面,API函数file_create_url用来把uri转换为URL,uri就是文件在Drupal里面存储的路径信息,但是这种信息,都是这种形式的“public://img/my123.jpg”,我们需要使用这个函数将其转换一下。
/**
* Implements hook_theme().
*/
function image_url_formatter_theme() {
return array(
'image_url_formatter' => array(
'variables' => array(
'item' => NULL,
'path' => NULL,
'image_style' => NULL,
),
),
);
}
/**
* Returns HTML for an image url field formatter.
*
* @param $variables
* An associative array containing:
* - item: An array of image data.
* - image_style: An optional image style.
* - path: An array containing the link 'path' and link 'options'.
*
* @ingroup themeable
*/
function theme_image_url_formatter($variables) {
$item = $variables['item'];
$image = array(
'path' => $item['uri'],
'alt' => $item['alt'],
);
// Do not output an empty 'title' attribute.
if (drupal_strlen($item['title']) > 0) {
$image['title'] = $item['title'];
}
$output = file_create_url($item['uri']);
if ($variables['image_style']) {
//debug($image);
$image['style_name'] = $variables['image_style'];
$output = image_style_url($image['style_name'], $item['uri']);
}
if ($variables['path']) {
$path = $variables['path']['path'];
$options = $variables['path']['options'];
// When displaying an image inside a link, the html option must be TRUE.
$options['html'] = TRUE;
$output = l($output, $path, $options);
}
return $output;
}
在这个主题函数中,我们返回的是图片的URL,而不是带有img标签的图片了。整个模块,全部都是复制拷贝image模块的代码,只有这里在逻辑上作了修改。image_style_url用来获取图片特定样式下对应图片的URL的。有时候,我们会用到这个函数。
我们看到,为一个已有的字段定义一个新的格式器,并不麻烦,而且很多代码都可以从原有模块中复制过来。采用这种方式的好处是,这个格式器定义好了以后,很多人都可以用,虽然定义的时候稍微麻烦了一点,但是以后会方便很多,送人玫瑰,手留余香。