entity.info.inc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. /**
  3. * @file
  4. * Provides basic entity property info for entities provided via the CRUD API,
  5. * as well as property info for all entity types defined by core. For that
  6. * the respective modules/MODULE.info.inc files are included.
  7. */
  8. /**
  9. * Implements hook_entity_property_info().
  10. */
  11. function entity_entity_property_info() {
  12. $items = array();
  13. // Add in info about entities provided by the CRUD API.
  14. foreach (entity_crud_get_info() as $type => $info) {
  15. // Automatically enable the controller only if the module does not implement
  16. // the hook itself.
  17. if (!isset($info['metadata controller class']) && !empty($info['base table']) && (!isset($info['module']) || !module_hook($info['module'], 'entity_property_info'))) {
  18. $info['metadata controller class'] = 'EntityDefaultMetadataController';
  19. }
  20. if (!empty($info['metadata controller class'])) {
  21. $controller = new $info['metadata controller class']($type);
  22. $items += $controller->entityPropertyInfo();
  23. }
  24. }
  25. // Add in info for all core entities.
  26. foreach (_entity_metadata_core_modules() as $module) {
  27. module_load_include('inc', 'entity', "modules/$module.info");
  28. if (function_exists($function = "entity_metadata_{$module}_entity_property_info")) {
  29. if ($return = $function()) {
  30. $items = array_merge_recursive($items, $return);
  31. }
  32. }
  33. }
  34. return $items;
  35. }
  36. /**
  37. * Implements hook_entity_property_info_alter().
  38. */
  39. function entity_entity_property_info_alter(&$entity_info) {
  40. // Add in info for all core entities.
  41. foreach (_entity_metadata_core_modules() as $module) {
  42. module_load_include('inc', 'entity', "modules/$module.info");
  43. if (function_exists($function = "entity_metadata_{$module}_entity_property_info_alter")) {
  44. $function($entity_info);
  45. }
  46. }
  47. }
  48. function _entity_metadata_core_modules() {
  49. return array_filter(array('book', 'comment', 'field', 'locale', 'node', 'taxonomy', 'user', 'system', 'statistics'), 'module_exists');
  50. }
  51. /**
  52. * Default controller for generating some basic metadata for CRUD entity types.
  53. */
  54. class EntityDefaultMetadataController {
  55. protected $type, $info;
  56. public function __construct($type) {
  57. $this->type = $type;
  58. $this->info = entity_get_info($type);
  59. }
  60. public function entityPropertyInfo() {
  61. $entity_label = drupal_strtolower($this->info['label']);
  62. // Provide defaults based on the schema.
  63. $info['properties'] = $this->convertSchema();
  64. foreach ($info['properties'] as $name => &$property) {
  65. // Add a description.
  66. $property['description'] = t('@entity "@property" property.', array('@entity' => drupal_ucfirst($entity_label), '@property' => $name));
  67. }
  68. // Set better metadata for known entity keys.
  69. $id_key = $this->info['entity keys']['id'];
  70. if (!empty($this->info['entity keys']['name']) && $key = $this->info['entity keys']['name']) {
  71. $info['properties'][$key]['type'] = 'token';
  72. $info['properties'][$key]['label'] = t('Machine-readable name');
  73. $info['properties'][$key]['description'] = t('The machine-readable name identifying this @entity.', array('@entity' => $entity_label));
  74. $info['properties'][$id_key]['label'] = t('Internal, numeric @entity ID', array('@entity' => $entity_label));
  75. $info['properties'][$id_key]['description'] = t('The ID used to identify this @entity internally.', array('@entity' => $entity_label));
  76. }
  77. else {
  78. $info['properties'][$id_key]['label'] = t('@entity ID', array('@entity' => drupal_ucfirst($entity_label)));
  79. $info['properties'][$id_key]['description'] = t('The unique ID of the @entity.', array('@entity' => $entity_label));
  80. }
  81. // Care for the bundle.
  82. if (!empty($this->info['entity keys']['bundle']) && $key = $this->info['entity keys']['bundle']) {
  83. $info['properties'][$key]['type'] = 'token';
  84. $info['properties'][$key]['options list'] = array(get_class($this), 'bundleOptionsList');
  85. }
  86. // Care for the label.
  87. if (!empty($this->info['entity keys']['label']) && $key = $this->info['entity keys']['label']) {
  88. $info['properties'][$key]['label'] = t('Label');
  89. $info['properties'][$key]['description'] = t('The human readable label.');
  90. }
  91. // Add a computed property for the entity URL and expose it to views.
  92. if (empty($info['properties']['url']) && !empty($this->info['uri callback'])) {
  93. $info['properties']['url'] = array(
  94. 'label' => t('URL'),
  95. 'description' => t('The URL of the entity.'),
  96. 'getter callback' => 'entity_metadata_entity_get_properties',
  97. 'type' => 'uri',
  98. 'computed' => TRUE,
  99. 'entity views field' => TRUE,
  100. );
  101. }
  102. return array($this->type => $info);
  103. }
  104. /**
  105. * A options list callback returning all bundles for an entity type.
  106. */
  107. public static function bundleOptionsList($name, $info) {
  108. if (!empty($info['parent']) && $type = $info['parent']) {
  109. $entity_info = $info['parent']->entityInfo();
  110. $options = array();
  111. foreach ($entity_info['bundles'] as $name => $bundle_info) {
  112. $options[$name] = $bundle_info['label'];
  113. }
  114. return $options;
  115. }
  116. }
  117. /**
  118. * Return a set of properties for an entity based on the schema definition
  119. */
  120. protected function convertSchema() {
  121. return entity_metadata_convert_schema($this->info['base table']);
  122. }
  123. }
  124. /**
  125. * Converts the schema information available for the given table to property info.
  126. *
  127. * @param $table
  128. * The name of the table as used in hook_schema().
  129. * @return
  130. * An array of property info as suiting for hook_entity_property_info().
  131. */
  132. function entity_metadata_convert_schema($table) {
  133. $schema = drupal_get_schema($table);
  134. $properties = array();
  135. foreach ($schema['fields'] as $name => $info) {
  136. if ($type = _entity_metadata_convert_schema_type($info['type'])) {
  137. $properties[$name] = array(
  138. 'type' => $type,
  139. 'label' => drupal_ucfirst($name),
  140. 'schema field' => $name,
  141. // As we cannot know about any setter access, leave out the setter
  142. // callback. For getting usually no further access callback is needed.
  143. );
  144. if ($info['type'] == 'serial') {
  145. $properties[$name]['validation callback'] = 'entity_metadata_validate_integer_positive';
  146. }
  147. }
  148. }
  149. return $properties;
  150. }
  151. function _entity_metadata_convert_schema_type($type) {
  152. switch ($type) {
  153. case 'int':
  154. case 'serial':
  155. case 'date':
  156. return 'integer';
  157. case 'float':
  158. case 'numeric':
  159. return 'decimal';
  160. case 'char':
  161. case 'varchar':
  162. case 'text':
  163. return 'text';
  164. }
  165. }
  166. /**
  167. * Interface for extra fields controller.
  168. *
  169. * Note: Displays extra fields exposed by this controller are rendered by
  170. * default by the EntityAPIController.
  171. */
  172. interface EntityExtraFieldsControllerInterface {
  173. /**
  174. * Returns extra fields for this entity type.
  175. *
  176. * @see hook_field_extra_fields().
  177. */
  178. public function fieldExtraFields();
  179. }
  180. /**
  181. * Default controller for generating extra fields based on property metadata.
  182. *
  183. * By default a display extra field for each property not being a field, ID or
  184. * bundle is generated.
  185. */
  186. class EntityDefaultExtraFieldsController implements EntityExtraFieldsControllerInterface {
  187. /**
  188. * @var string
  189. */
  190. protected $entityType;
  191. /**
  192. * @var array
  193. */
  194. protected $entityInfo;
  195. /**
  196. * Constructor.
  197. */
  198. public function __construct($type) {
  199. $this->entityType = $type;
  200. $this->entityInfo = entity_get_info($type);
  201. $this->propertyInfo = entity_get_property_info($type);
  202. }
  203. /**
  204. * Implements EntityExtraFieldsControllerInterface::fieldExtraFields().
  205. */
  206. public function fieldExtraFields() {
  207. $extra = array();
  208. foreach ($this->propertyInfo['properties'] as $name => $property_info) {
  209. // Skip adding the ID or bundle.
  210. if ($this->entityInfo['entity keys']['id'] == $name || $this->entityInfo['entity keys']['bundle'] == $name) {
  211. continue;
  212. }
  213. $extra[$this->entityType][$this->entityType]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
  214. }
  215. // Handle bundle properties.
  216. $this->propertyInfo += array('bundles' => array());
  217. foreach ($this->propertyInfo['bundles'] as $bundle_name => $info) {
  218. foreach ($info['properties'] as $name => $property_info) {
  219. if (empty($property_info['field'])) {
  220. $extra[$this->entityType][$bundle_name]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
  221. }
  222. }
  223. }
  224. return $extra;
  225. }
  226. /**
  227. * Generates the display field info for a given property.
  228. */
  229. protected function generateExtraFieldInfo($name, $property_info) {
  230. $info = array(
  231. 'label' => $property_info['label'],
  232. 'weight' => 0,
  233. );
  234. if (!empty($property_info['description'])) {
  235. $info['description'] = $property_info['description'];
  236. }
  237. return $info;
  238. }
  239. }