Entity API模块定义了一个新的钩子,hook_entity_property_info(),通过这个钩子函数,就可以定义实体包含哪些属性信息了,这个信息里面还包括,属性的数据类型、获取、设置属性的回调函数。注意,很多常用的模块,都用到了这里定义的属性,比如Rules模块。而前面的entity_get_property_info,则是用来获取hook_entity_property_info()里面的定义信息的。这个钩子函数比较抽象,我们可以看一个例子,在sites\all\modules\entity\modules下面可以找到,Drupal核心中各个子系统的钩子实现。下面这个是用户系统的实现:
/**
* Implements hook_entity_property_info() on top of user module.
*
* @see entity_entity_property_info()
*/
function entity_metadata_user_entity_property_info() {
$info = array();
// Add meta-data about the user properties.
$properties = &$info['user']['properties'];
$properties['uid'] = array(
'label' => t("User ID"),
'type' => 'integer',
'description' => t("The unique ID of the user account."),
'schema field' => 'uid',
);
$properties['name'] = array(
'label' => t("Name"),
'description' => t("The login name of the user account."),
'getter callback' => 'entity_metadata_user_get_properties',
'setter callback' => 'entity_property_verbatim_set',
'sanitize' => 'filter_xss',
'required' => TRUE,
'access callback' => 'entity_metadata_user_properties_access',
'schema field' => 'name',
);
…
下面的这段则是节点系统的实现:
…
$properties['created'] = array(
'label' => t("Date created"),
'type' => 'date',
'description' => t("The date the node was posted."),
'setter callback' => 'entity_property_verbatim_set',
'setter permission' => 'administer nodes',
'schema field' => 'created',
);
$properties['changed'] = array(
'label' => t("Date changed"),
'type' => 'date',
'schema field' => 'changed',
'description' => t("The date the node was most recently updated."),
);
$properties['author'] = array(
'label' => t("Author"),
'type' => 'user',
'description' => t("The author of the node."),
'setter callback' => 'entity_property_verbatim_set',
'setter permission' => 'administer nodes',
'required' => TRUE,
'schema field' => 'uid',
);
…
除了这些实体系统以外,字段系统也都被包含了进来,不过字段系统的代码比较抽象:
/**
* Implements hook_entity_property_info() on top of field module.
*
* @see entity_field_info_alter()
* @see entity_entity_property_info()
*/
function entity_metadata_field_entity_property_info() {
$info = array();
// Loop over all field instances and add them as property.
foreach (field_info_fields() as $field_name => $field) {
$field += array('bundles' => array());
if ($field_type = field_info_field_types($field['type'])) {
// Add in our default callback as the first one.
$field_type += array('property_callbacks' => array());
array_unshift($field_type['property_callbacks'], 'entity_metadata_field_default_property_callback');
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle) {
$instance = field_info_instance($entity_type, $field_name, $bundle);
if ($instance && empty($instance['deleted'])) {
foreach ($field_type['property_callbacks'] as $callback) {
$callback($info, $entity_type, $field, $instance, $field_type);
}
}
}
}
}
}
return $info;
}
/**
* Callback to add in property info defaults per field instance.
* @see entity_metadata_field_entity_property_info().
*/
function entity_metadata_field_default_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
if (!empty($field_type['property_type'])) {
if ($field['cardinality'] != 1) {
$field_type['property_type'] = 'list<' . $field_type['property_type'] . '>';
}
// Add in instance specific property info, if given and apply defaults.
$name = $field['field_name'];
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
$instance += array('property info' => array());
$property = $instance['property info'] + array(
'label' => $instance['label'],
'type' => $field_type['property_type'],
'description' => t('Field "@name".', array('@name' => $name)),
'getter callback' => 'entity_metadata_field_property_get',
'setter callback' => 'entity_metadata_field_property_set',
'access callback' => 'entity_metadata_field_access_callback',
'query callback' => 'entity_metadata_field_query',
'translatable' => !empty($field['translatable']),
// Specify that this property stems from a field.
'field' => TRUE,
'required' => !empty($instance['required']),
);
// For field types of the list module add in the options list callback.
if (strpos($field['type'], 'list') === 0) {
$property['options list'] = 'entity_metadata_field_options_list';
}
}
}
Drupal核心系统,默认是不支持这个钩子的,但是Entity API模块把核心系统里面的所有涉及到的部分,都实现出来了。这里是包括所有的Drupal核心的字段类型的。我们在这里,前期不需要完全明白这些代码的含义,大致看一下,知道有这么回事就可以了,我们只需要记住,这里面,在属性数组信息里面,包含哪些常用的键就可以了。'label'、'description'、'getter callback'、'setter callback'、'sanitize'、'required'、'access callback'、'schema field'。有兴趣的话,可以沿着我们提示,把sites\all\modules\entity\modules下面,所有inc文件里面的代码都阅读一遍。注意,verbatim的中文意思为“完全)照字面的(地),逐字的(地)”,里面的代码会遇到这个单词。