TripalField.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. <?php
  2. /**
  3. * A base class for all fields supported by Tripal.
  4. *
  5. * The Field API of Drupal defines three "levels" for fields: field types,
  6. * fields, and instances of fields. This class attempts to consolidate use
  7. * of all three "levels". All fields must be of a specific type, and
  8. * the field types are typically defined using the hook_field_info() hook.
  9. * Normally, using Drupal's Field API, fields can be created by using the
  10. * field_create_field() function which defines the parameters and settings
  11. * for the field. The field_create_instance() function is then used to attach
  12. * a field to a bundle and to set local parameters and settings for the field
  13. * when attached to the bundle. There are also a variety of hooks for creating
  14. * widgets, formatters, customizaing settings forms, loading values, validating
  15. * widget forms, etc. Rather than use all of these hooks, the TripalField class
  16. * is used to consolidate and simplify creation and management of Fields.
  17. *
  18. * A module can extend this class to create new fields, and attach them to
  19. * bundles. The class is structured to allow fields to specify which bundles
  20. * they want to "automatically" attach. This is a bit different from how fields
  21. * would normally be attached. But allows a field to be self-aware.
  22. *
  23. * All of the functionality for a field is self-contained in the Class
  24. * implementation. To change functionality a developer need only edit the
  25. * class file for a field rathaer than look for all of the Field API hook that
  26. * would typically be spread around the module.
  27. *
  28. * This class also supports use of controlled vocabulaaries for providing
  29. * "types" to these fields. This is important for use with the semantic web
  30. * support for Tripal v3.
  31. *
  32. * AJAX callbacks, and theme functions unfortunately cannot be part of the
  33. * implementation of this class. To keep all functionality for a field
  34. * in the same file, it is recommended that those functions, if needed, should
  35. * be added to the bottom of the file where the child class is housed, and each
  36. * TripalField child class should each be written in a separate file.
  37. *
  38. */
  39. class TripalField {
  40. // An object containing configuration data for this field. The contents
  41. // of this object come directly from the field_config table of Drupal.
  42. protected $field;
  43. // --------------------------------------------------------------------------
  44. // STATIC CONSTANTS
  45. //
  46. // The following constants SHOULD be set for each descendent class. They are
  47. // used by the static functions to provide information to Drupal about
  48. // the field and it's default widget and formatter.
  49. // --------------------------------------------------------------------------
  50. // The default lable for this field.
  51. public static $default_label = 'Tripal Field.';
  52. // The default description for this field.
  53. public static $default_description = 'The generic base class for all
  54. Tripal Fields. Replace this text as appropriate for the child implementation.';
  55. // Add any default settings elements. If you override the fieldSettingsForm()
  56. // or the instanceSettingsForm() functions then you need to be sure that
  57. // any settings you want those functions to manage are listed in this
  58. // array.
  59. public static $default_settings = array();
  60. // Set this to the name of the storage backend that by default will support
  61. // this field.
  62. public static $default_storage = 'tripal';
  63. // Set this to be the name of the module that is responsible for this field.
  64. public static $module = 'tripal';
  65. // --------------------------------------------------------------------------
  66. // CONSTRUCTORS & STATIC CONSTRUCTOR HELPERS
  67. //
  68. // Child classes SHOULD NOT need to override these functions.
  69. // --------------------------------------------------------------------------
  70. /**
  71. * Instantiates a new TripalField object.
  72. *
  73. * @param $field
  74. * If the field already exists in Drupal, then pass in the $field array
  75. * for this argument. If nothing is passed in then an "empty" field
  76. * is created. This is only useful
  77. *
  78. * The field must have already been previously created.
  79. */
  80. public function __construct($info = array()) {
  81. // If the field array has been passed in then just link it.
  82. if (array_key_exists('field', $info)) {
  83. $this->field = $field;
  84. }
  85. // If the field name has been passed in then retreive the form info.
  86. if (array_key_exists('field_name', $info)) {
  87. $this->field = field_info_field($field_name);
  88. }
  89. // If the field info has been passed in then create the field.
  90. if (array_key_exists('info', $info)) {
  91. $this->field = field_create_field($info['info']);
  92. }
  93. // Include any instances that have been created for this field.
  94. if (is_array($field) and array_key_exists('id', $this->field)) {
  95. $instances = db_select('field_config_instance', 'fci')
  96. ->fields('fci')
  97. ->condition('field_id', $field['id'])
  98. ->execute();
  99. while ($instance = $instances->fetchObject()) {
  100. $this->instances[$instance->field_name] = $instance;
  101. }
  102. }
  103. }
  104. // --------------------------------------------------------------------------
  105. // STATIC INFO FUNCTIONS
  106. //
  107. // Child classes SHOULD NOT need to override these functions.
  108. // --------------------------------------------------------------------------
  109. /**
  110. * Provides default information about this field type
  111. *
  112. * NOTE: this field should NOT be overridden by child classes.
  113. *
  114. * @return
  115. * An array whose keys are field type names and whose values are arrays
  116. * describing the field type. The keys are the same as for the
  117. * hook_field_info() function.
  118. */
  119. public static function globalInfo() {
  120. $field_type = get_called_class();
  121. return array(
  122. 'label' => self::$default_label,
  123. 'description' => self::$default_description,
  124. 'default_widget' => $field_type . '_widget',
  125. 'default_formatter' => $field_type . '_formatter',
  126. 'settings' => self::$default_settings,
  127. 'storage' => array(
  128. 'type' => self::$default_storage,
  129. 'module' => 'tripal',
  130. 'active' => TRUE
  131. ),
  132. );
  133. }
  134. /**
  135. * Provides information about the widgets provided by this field.
  136. *
  137. * This is a static function as it provides default values for all of the
  138. * widgets for this field type, and thus we don't need an instantiated
  139. * object to provide this information.
  140. *
  141. * @return
  142. * An associative array with key/value pairs compatible with those from the
  143. * hook_field_widget_info() function of the Drupal Field API.
  144. */
  145. public static function widgetInfo() {
  146. $field_type = get_called_class();
  147. return array(
  148. $field_type . '_widget' => array(
  149. 'label' => self::$default_label,
  150. 'field types' => array($field_type)
  151. ),
  152. );
  153. }
  154. /**
  155. * Provides information about the formatter for this field.
  156. *
  157. * This is a static function as it provides default values for all of the
  158. * formatters for this field type, and thus we don't need an instantiated
  159. * object to provide this information.
  160. *
  161. * @return
  162. * An associative array with key/value paris compatible with those from the
  163. * hook_field_formatter_info() function of the Drupal Field API.
  164. *
  165. */
  166. public static function formatterInfo() {
  167. $field_type = get_called_class();
  168. return array(
  169. $field_type . '_formatter' => array(
  170. 'label' => self::$default_label,
  171. 'field types' => array($field_type),
  172. 'settings' => array(),
  173. ),
  174. );
  175. }
  176. // --------------------------------------------------------------------------
  177. // GETTERS AND SETTERS
  178. //
  179. // Child classes SHOULD NOT need to override these functions.
  180. // --------------------------------------------------------------------------
  181. /**
  182. * Retrives the name of this field.
  183. *
  184. * @return
  185. * This field's name.
  186. */
  187. public function getFieldName() {
  188. return $this->field['field_name'];
  189. }
  190. // --------------------------------------------------------------------------
  191. // FIELD SPECIFIC FUNCTIONS
  192. //
  193. // Child classes SHOULD NOT override these functions as needed.
  194. // --------------------------------------------------------------------------
  195. /**
  196. * Creates an instance of a field and attaches it to a bundle.
  197. *
  198. * Typically there is no reason for a child class to override this function.
  199. *
  200. * @param $info
  201. */
  202. public function createInstance($info = array()) {
  203. //if ($this->canAttach($info['entity_type'], $info['bundle'])) {
  204. return field_create_instance($info);
  205. //}
  206. //else {
  207. // return FALSE;
  208. //}
  209. }
  210. // --------------------------------------------------------------------------
  211. // OVERRIDEABLE FIELD SPECIFIC FUNCTIONS
  212. //
  213. // Child classes SHOULD override these functions as needed.
  214. // --------------------------------------------------------------------------
  215. /**
  216. * Performs a check to see disallow attaching of a field instance to a bundle.
  217. *
  218. * By default Tripal will try to automatically attach all TripalFields to
  219. * every bundle. But this is certainly not appropriate.
  220. * This function should be overridden by a child to ensure it is attached
  221. * to only desired bundles.
  222. *
  223. * This function returns FALSE if this field should NOT be attached to the
  224. * bundle. This should always be honored by a child class. If the parent class
  225. * returns FALSE then so should the child. Alternatively, this function
  226. * returns NULL if there is no good reason to deny attachment and leaves it up
  227. * to the child class to decide. If the child class does not impolment
  228. * this function then the NULL is recognized as FALSE by Tripal and the
  229. * field will not be attached to the bundle. Therefore, it is necessary
  230. * for the child class to implement this function and return TRUE for
  231. * bundles to which this field should be attached. Because bundles names
  232. * use controlled vocabulary terms the child class should be able to
  233. * determine if it should attach.
  234. *
  235. * @param $entity_type
  236. * The entity type
  237. * @param $bundle_name
  238. * The name of the bundle
  239. *
  240. * @return
  241. * FALSE if the child class should return FALSE, NULL if the child class
  242. * should decide. The child class should always return FAlSE or TRUE. If
  243. * TRUE is returned then an instance of the field can be attached to the
  244. * bundle.
  245. */
  246. // protected function canAttach($entity_type, $bundle_name) {
  247. // // Don't attach if it's already attached.
  248. // if (array_key_exists('bundles', $this->field) and
  249. // array_key_exists('TripalEntity', $this->field['bundles']) and
  250. // in_array($bundle_name, $this->field['bundles']['TripalEntity'])) {
  251. // return FALSE;
  252. // }
  253. // // Child classes should check to see if this field can be attached
  254. // // to the bundle.
  255. // return NULL;
  256. // }
  257. /**
  258. * Provides a summary of the formatter settings.
  259. *
  260. * On the 'Manage Display' page of the content type administration page,
  261. * fields are allowed to provide a settings form. This settings form can
  262. * be used to allow the site admin to define how the field should be
  263. * formatted. The settings are then available for the formatter()
  264. * function of this class. This function provides a text-based description
  265. * of the settings for the site developer to see. It appears on the manage
  266. * display page inline with the field. A field must always return a
  267. * value in this function if the settings form gear button is to appear.
  268. *
  269. * See the hook_field_formatter_settings_summary() function for more
  270. * information.
  271. *
  272. * @param $field
  273. * @param $instance
  274. * @param $view_mode
  275. *
  276. * @return string
  277. * A string that provides a very brief summary of the field settings
  278. * to the user.
  279. *
  280. */
  281. public static function formatterSettingsSummary($field, $instance, $view_mode) {
  282. }
  283. /**
  284. * Provides the field's setting form.
  285. *
  286. * The settings form appears on the 'Manage Display' page of the content
  287. * type administration page. This function provides the form that will
  288. * appear on that page.
  289. *
  290. * To add a validate function, please create a static function in the
  291. * implementing class, and indicate that this function should be used
  292. * in the form array that is returned by this function.
  293. *
  294. * This form will not be displayed if the formatter_settings_summary()
  295. * function does not return anything.
  296. *
  297. * @param $field
  298. * @param $instance
  299. * @param $view_mode
  300. * @param $form
  301. * @param $form_state
  302. *
  303. * @return
  304. * A Drupal Form array containing the settings form for this field.
  305. */
  306. public static function formatterSettingsForm($field, $instance,
  307. $view_mode, $form, &$form_state) {
  308. }
  309. /**
  310. * Provides the display for a field
  311. *
  312. * This function provides the display for a field when it is viewed on
  313. * the web page. The content returned by the formatter should only include
  314. * what is present in the $items[$delta]['values] array. This way, the
  315. * contents that are displayed on the page, via webservices and downloaded
  316. * into a CSV file will always be identical. The view need not show all
  317. * of the data in the 'values' array.
  318. *
  319. * @param $element
  320. * @param $entity_type
  321. * @param $entity
  322. * @param $field
  323. * @param $instance
  324. * @param $langcode
  325. * @param $items
  326. * @param $display
  327. *
  328. * @return
  329. * An element array compatible with that returned by the
  330. * hook_field_formatter_view() function.
  331. */
  332. public static function formatterView(&$element, $entity_type, $entity,
  333. $field, $instance, $langcode, $items, $display) {
  334. foreach($items as $delta => $item) {
  335. $element[$delta] = array(
  336. '#type' => 'markup',
  337. '#markup' => $item['value'],
  338. );
  339. }
  340. }
  341. /**
  342. * Provides the form for editing of this field.
  343. *
  344. * This form is diplayed when the user creates a new entity or edits an
  345. * existing entity. If the field is attached to the entity then the form
  346. * provided by this function will be displayed.
  347. *
  348. * At a minimum, the form must have a 'value' element. For Tripal, the
  349. * 'value' element of a field always corresponds to the value that is
  350. * presented to the end-user either directly on the page (with formatting)
  351. * or via web services, or some other mechanism. However, the 'value' is
  352. * sometimes not enough for a field. For example, the Tripal Chado module
  353. * maps fields to table columns and sometimes those columns are foreign keys
  354. * therefore, the Tripal Chado modules does not use the 'value' but adds
  355. * additional elements to help link records via FKs. But even in this case
  356. * the 'value' element must always be present in the returne form and in such
  357. * cases it's value should be set equal to that added in the 'load' function.
  358. *
  359. * @param $widget
  360. * @param $form
  361. * @param $form_state
  362. * @param $field
  363. * @param $instance
  364. * @param $langcode
  365. * @param $items
  366. * @param $delta
  367. * @param $element
  368. *
  369. * @return
  370. * A Drupal form. See the hook_field_widget_form() function for more information.
  371. */
  372. public static function widgetForm(&$widget, &$form, &$form_state, $field, $instance,
  373. $langcode, $items, $delta, $element) {
  374. $widget['value'] = array(
  375. '#type' => 'value',
  376. '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
  377. );
  378. }
  379. /**
  380. * Perform validation of the widget_form when adding or editing the entity.
  381. *
  382. * Any errors encountered should be indicatd by adding a value to the $errors
  383. * array according to the instructions below.
  384. *
  385. * @param $entity_type
  386. * The type of $entity.
  387. * @param $entity
  388. * The entity for the operation.
  389. * @param $field
  390. * The field structure for the operation.
  391. * @param $instance
  392. * The instance structure for $field on $entity's bundle.
  393. * @param $langcode
  394. * The language associated with $items.
  395. * @param $items
  396. * $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  397. * @param $errors
  398. * The array of errors (keyed by field name, language code, and delta) that
  399. * have already been reported for the entity. The function should add its
  400. * errors to this array. Each error is an associative array with the
  401. * following keys and values:
  402. * - error: An error code (should be a string prefixed with the
  403. * module name).
  404. * - message: The human readable message to be displayed.
  405. *
  406. */
  407. public static function widgetFormValidate($entity_type, $entity, $field, $instance, $langcode,
  408. $items, &$errors) {
  409. }
  410. /**
  411. * Performs extra commands when the entity form is submitted.
  412. *
  413. * Drupal typically does not provide a submit hook for fields. The
  414. * TripalField provides one to allow for behind-the-scenes actions to
  415. * occur. This function should never be used for updates, deletes or
  416. * inserts into the storage backend. Rather, the appropriate Field Storage
  417. * implementation will take care of that. An example where this function
  418. * may be useful would be to set values in the $items array using values
  419. * of the other.
  420. *
  421. * @param $entity_type
  422. * The type of $entity.
  423. * @param $entity
  424. * The entity for the operation.
  425. * @param $field
  426. * The field structure for the operation.
  427. * @param $instance
  428. * The instance structure for $field on $entity's bundle.
  429. * @param $langcode
  430. * The language associated with $items.
  431. * @param $items
  432. * $entity->{$field['field_name']}[$langcode], or an empty array if unset.
  433. * @param $form
  434. * The submitted form array.
  435. * @param $form_state.
  436. * The form state array.
  437. */
  438. public static function widgetFormSubmit($entity_type, $entity, $field, $instance, $langcode,
  439. &$items, $form, &$form_state) {
  440. }
  441. /**
  442. * Loads the field values from the underlying data store.
  443. *
  444. * @param $field
  445. * @param $entity
  446. * @param $details
  447. *
  448. * @return
  449. * An array of the following format:
  450. * $entity->{$field_name}['und'][0]['value'] = $value;
  451. * where:
  452. * - $entity is the enity object to which this field is attached.
  453. * - $field_name is the name of this field
  454. * - 'und' is the language code (in this case 'und' == undefined)
  455. * - 0 is the cardinality. Increment by 1 when more than one item is
  456. * available.
  457. * - 'value' is the key indicating the value of this field. It should
  458. * always be set. The value of the 'value' key will be the contents
  459. * used for web services and for downloadable content. The value
  460. * should be of the follow format types: 1) A single value (text,
  461. * numeric, etc.) 2) An array of key value pair. 3) If multiple entries
  462. * then cardinality should incremented and format types 1 and 2 should
  463. * be used for each item.
  464. * The array may contain as many other keys at the same level as 'value'
  465. * but those keys are for internal field use and are not considered the
  466. * value of the field.
  467. *
  468. *
  469. */
  470. public static function load($field, $entity, $details = array()) {
  471. }
  472. public function instanceLoad($instance) {
  473. }
  474. /**
  475. * Provides a form for the 'Field Settings' of the field management page.
  476. *
  477. * This is an optional hook function and is similar to the
  478. * hook_field_settings_form function().
  479. *
  480. * @param $field
  481. * The field structure being configured.
  482. * @param $instance
  483. * The instance structure being configured.
  484. * @param $has_data
  485. * TRUE if the field already has data, FALSE if not.
  486. */
  487. public static function instanceSettingsForm($field, $instance) {
  488. $settings = $instance['settings'];
  489. $element = array();
  490. // $element['semantic_web'] = array(
  491. // '#type' => 'textfield',
  492. // '#title' => 'Semantic Web',
  493. // '#description' => t('Each field must be associated with a term
  494. // from a controlled vocabulary. This allows computer programs to understand
  495. // the data provided on this site. Please be cautions changing these
  496. // values. Defaults are set by Tripal and sites that use the same
  497. // terms can exchange information.'),
  498. // '#collapsed' => TRUE,
  499. // '#collapsible' => TRUE,
  500. // '#tree' => TRUE,
  501. // );
  502. $module = $field['module'];
  503. $element['#field'] = $field;
  504. $element['#instance'] = $instance;
  505. $element['#element_validate'][] = $module . '_field_instance_settings_form_validate';
  506. return $element;
  507. }
  508. /**
  509. *
  510. * @param unknown $form
  511. * @param unknown $form_state
  512. */
  513. public static function instanceSettingsFormValidate($field, $instance, $form, &$form_state) {
  514. }
  515. /**
  516. * Provides a form for the 'Field Settings' of the field management page.
  517. *
  518. * This is an optional hook function and is similar to the
  519. * hook_field_settings_form function().
  520. *
  521. * @param $field
  522. * The field structure being configured.
  523. * @param $instance
  524. * The instance structure being configured.
  525. * @param $has_data
  526. * TRUE if the field already has data, FALSE if not.
  527. */
  528. public static function globalSettingsForm($field, $instance, $has_data) {
  529. $settings = $field['settings'];
  530. $element = array();
  531. // $element['semantic_web'] = array(
  532. // '#type' => 'textfield',
  533. // '#title' => 'Semantic Web',
  534. // '#description' => t('Each field must be associated with a term
  535. // from a controlled vocabulary. This allows computer programs to understand
  536. // the data provided on this site. Please be cautions changing these
  537. // values. Defaults are set by Tripal and sites that use the same
  538. // terms can exchange information.'),
  539. // '#collapsed' => TRUE,
  540. // '#collapsible' => TRUE,
  541. // '#tree' => TRUE,
  542. // );
  543. $module = $field['module'];
  544. $element['#field'] = $field;
  545. $element['#instance'] = $instance;
  546. $element['#element_validate'][] = $module . '_field_settings_form_validate';
  547. return $element;
  548. }
  549. /**
  550. *
  551. * @param unknown $form
  552. * @param unknown $form_state
  553. */
  554. public static function globalSettingsFormValidate($field, $instance, $form, &$form_state) {
  555. }
  556. /**
  557. * Describes this fields "data tables" to Views.
  558. *
  559. * This function is the equivalent of the hook_views_data() function of
  560. * the Drupal Views API. It provides the necessary details to allow
  561. * Views to integrate the field.
  562. *
  563. * @return
  564. * An associative array describing the data structure of the field.
  565. */
  566. public static function viewsDataAlter(&$data, $field, $entity_info) {
  567. }
  568. }