field_example.module

Tracking 8.x-1.x branch
  1. drupal
    1. 7 contributions/examples/field_example/field_example.module
    2. 8 contributions/examples/field_example/field_example.module

An example field using the Field Types API.

Functions & methods

NameDescription
field_example_3text_validateValidate the individual fields and then convert them into a single HTML RGB value as text.
field_example_field_formatter_infoImplements hook_field_formatter_info().
field_example_field_formatter_viewImplements hook_field_formatter_view().
field_example_field_infoImplements hook_field_info().
field_example_field_is_emptyImplements hook_field_is_empty().
field_example_field_validateImplements hook_field_validate().
field_example_field_widget_errorImplements hook_field_widget_error().
field_example_field_widget_formImplements hook_field_widget_form().
field_example_field_widget_infoImplements hook_field_widget_info().
field_example_menuImplements hook_menu().
_field_example_pageA simple page to explain to the developer what to do.

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * An example field using the Field Types API.
  5. */
  6. /**
  7. * @defgroup field_example Example: Field Types API
  8. * @ingroup examples
  9. * @{
  10. * Examples using Field Types API.
  11. *
  12. * This is updated from Barry Jaspan's presentation at Drupalcon Paris,
  13. * @link http://acquia.com/community/resources/acquia-tv/intro-field-api-module-developers Video Presentation @endlink
  14. *
  15. * Providing a field requires:
  16. * - Defining a field:
  17. * - hook_field_info()
  18. * - hook_field_schema()
  19. * - hook_field_validate()
  20. * - hook_field_is_empty()
  21. *
  22. * - Defining a formatter for the field (the portion that outputs the field for
  23. * display):
  24. * - hook_field_formatter_info()
  25. * - hook_field_formatter_view()
  26. *
  27. * - Defining a widget for the edit form:
  28. * - hook_field_widget_info()
  29. * - hook_field_widget_form()
  30. *
  31. * Our module defines the field in field_example_field_info(),
  32. * field_example_field_validate() and field_example_field_is_empty().
  33. * field_example_field_schema() is implemented in field_example.install.
  34. *
  35. * Our module sets up a formatter in field_example_field_formatter_info() and
  36. * field_example_field_formatter_view(). These are the API hooks that present
  37. * formatted and themed output to the user.
  38. * And finally, our module defines the widet in
  39. * field_example_field_widget_info() and field_example_field_widget_form().
  40. * The widget is the form element used to receive input from the user
  41. * when the field is being populated.
  42. *
  43. * @see field_types
  44. * @see field
  45. */
  46. /***************************************************************
  47. * Field Type API hooks
  48. ***************************************************************/
  49. /**
  50. * Implements hook_field_info().
  51. *
  52. * Provides the description of the field.
  53. */
  54. function field_example_field_info() {
  55. return array(
  56. // We name our field as the associative name of the array.
  57. 'field_example_rgb' => array(
  58. 'label' => t('Example Color RGB'),
  59. 'description' => t('Demonstrates a field composed of an RGB color.'),
  60. 'default_widget' => 'field_example_3text',
  61. 'default_formatter' => 'field_example_simple_text',
  62. ),
  63. );
  64. }
  65. /**
  66. * Implements hook_field_validate().
  67. *
  68. * This hook gives us a chance to validate content that's in our
  69. * field. We're really only interested in the $items parameter, since
  70. * it holds arrays representing content in the field we've defined.
  71. * We want to verify that the items only contain RGB hex values like
  72. * this: #RRGGBB. If the item validates, we do nothing. If it doesn't
  73. * validate, we add our own error notification to the $errors parameter.
  74. *
  75. * @see field_example_field_widget_error()
  76. */
  77. function field_example_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  78. foreach ($items as $delta => $item) {
  79. if (!empty($item['rgb'])) {
  80. if (! preg_match('@^#[0-9a-f]{6}$@', $item['rgb'])) {
  81. $errors[$field['field_name']][$langcode][$delta][] = array(
  82. 'error' => 'field_example_invalid',
  83. 'message' => t('Color must be in the HTML format #abcdef.'),
  84. );
  85. }
  86. }
  87. }
  88. }
  89. /**
  90. * Implements hook_field_is_empty().
  91. *
  92. * hook_field_is_emtpy() is where Drupal asks us if this field is empty.
  93. * Return TRUE if it does not contain data, FALSE if it does. This lets
  94. * the form API flag an error when required fields are empty.
  95. */
  96. function field_example_field_is_empty($item, $field) {
  97. return empty($item['rgb']);
  98. }
  99. /**
  100. * Implements hook_field_formatter_info().
  101. *
  102. * We need to tell Drupal that we have two different types of formatters
  103. * for this field. One will change the text color, and the other will
  104. * change the background color.
  105. *
  106. * @see field_example_field_formatter_view()
  107. */
  108. function field_example_field_formatter_info() {
  109. return array(
  110. // This formatter just displays the hex value in the color indicated.
  111. 'field_example_simple_text' => array(
  112. 'label' => t('Simple text-based formatter'),
  113. 'field types' => array('field_example_rgb'),
  114. ),
  115. // This formatter changes the background color of the content region.
  116. 'field_example_color_background' => array(
  117. 'label' => t('Change the background of the output text'),
  118. 'field types' => array('field_example_rgb'),
  119. ),
  120. );
  121. }
  122. /**
  123. * Implements hook_field_formatter_view().
  124. *
  125. * Two formatters are implemented.
  126. * - field_example_simple_text just outputs markup indicating the color that
  127. * was entered and uses an inline style to set the text color to that value.
  128. * - field_example_color_background does the same but also changes the
  129. * background color of div.region-content.
  130. *
  131. * @see field_example_field_formatter_info()
  132. */
  133. function field_example_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  134. $element = array();
  135. switch ($display['type']) {
  136. // This formatter simply outputs the field as text and with a color.
  137. case 'field_example_simple_text':
  138. foreach ($items as $delta => $item) {
  139. $element[$delta] = array(
  140. // We create a render array to produce the desired markup,
  141. // "<p style="color: #hexcolor">The color code ... #hexcolor</p>".
  142. // See theme_html_tag().
  143. '#type' => 'html_tag',
  144. '#tag' => 'p',
  145. '#attributes' => array(
  146. 'style' => 'color: ' . $item['rgb'],
  147. ),
  148. '#value' => t('The color code in this field is @code', array('@code' => $item['rgb'])),
  149. );
  150. }
  151. break;
  152. // This formatter adds css to the page changing the '.region-content' area's
  153. // background color. If there are many fields, the last one will win.
  154. case 'field_example_color_background':
  155. foreach ($items as $delta => $item) {
  156. $element[$delta] = array(
  157. '#type' => 'html_tag',
  158. '#tag' => 'p',
  159. '#value' => t('The content area color has been changed to @code', array('@code' => $item['rgb'])),
  160. '#attached' => array(
  161. 'css' => array(
  162. array(
  163. 'data' => 'div.region-content { background-color:' . $item['rgb'] . ';}',
  164. 'type' => 'inline',
  165. ),
  166. ),
  167. ),
  168. );
  169. }
  170. break;
  171. }
  172. return $element;
  173. }
  174. /**
  175. * Implements hook_field_widget_info().
  176. *
  177. * Three widgets are provided.
  178. * - A simple text-only widget where the user enters the '#ffffff'.
  179. * - A 3-textfield widget that gathers the red, green, and blue values
  180. * separately.
  181. * - A farbtastic colorpicker widget that chooses the value graphically.
  182. *
  183. * These widget types will eventually show up in hook_field_widget_form,
  184. * where we will have to flesh them out.
  185. *
  186. * @see field_example_field_widget_form()
  187. */
  188. function field_example_field_widget_info() {
  189. return array(
  190. 'field_example_text' => array(
  191. 'label' => t('RGB value as #ffffff'),
  192. 'field types' => array('field_example_rgb'),
  193. ),
  194. 'field_example_3text' => array(
  195. 'label' => t('RGB text field'),
  196. 'field types' => array('field_example_rgb'),
  197. ),
  198. 'field_example_colorpicker' => array(
  199. 'label' => t('Color Picker'),
  200. 'field types' => array('field_example_rgb'),
  201. ),
  202. );
  203. }
  204. /**
  205. * Implements hook_field_widget_form().
  206. *
  207. * hook_widget_form() is where Drupal tells us to create form elements for
  208. * our field's widget.
  209. *
  210. * We provide one of three different forms, depending on the widget type of
  211. * the Form API item provided.
  212. *
  213. * The 'field_example_colorpicker' and 'field_example_text' are essentially
  214. * the same, but field_example_colorpicker adds a javascript colorpicker
  215. * helper.
  216. *
  217. * field_example_3text displays three text fields, one each for red, green,
  218. * and blue. However, the field type defines a single text column,
  219. * rgb, which needs an HTML color spec. Define an element validate
  220. * handler that converts our r, g, and b fields into a simulated single
  221. * 'rgb' form element.
  222. */
  223. function field_example_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  224. $value = isset($items[$delta]['rgb']) ? $items[$delta]['rgb'] : '';
  225. $widget = $element;
  226. $widget['#delta'] = $delta;
  227. switch ($instance['widget']['type']) {
  228. case 'field_example_colorpicker':
  229. $widget += array(
  230. '#suffix' => '<div class="field-example-colorpicker"></div>',
  231. '#attributes' => array('class' => array('edit-field-example-colorpicker')),
  232. '#attached' => array(
  233. // Add Farbtastic color picker.
  234. 'library' => array(
  235. array('system', 'farbtastic'),
  236. ),
  237. // Add javascript to trigger the colorpicker.
  238. 'js' => array(drupal_get_path('module', 'field_example') . '/field_example.js'),
  239. ),
  240. );
  241. // DELIBERATE fall-through: From here on the field_example_text and
  242. // field_example_colorpicker are exactly the same.
  243. case 'field_example_text':
  244. $widget += array(
  245. '#type' => 'textfield',
  246. '#default_value' => $value,
  247. // Allow a slightly larger size that the field length to allow for some
  248. // configurations where all characters won't fit in input field.
  249. '#size' => 7,
  250. '#maxlength' => 7,
  251. );
  252. break;
  253. case 'field_example_3text':
  254. // Convert rgb value into r, g, and b for #default_value.
  255. if (!empty($value)) {
  256. preg_match_all('@..@', substr($value, 1), $match);
  257. }
  258. else {
  259. $match = array(array());
  260. }
  261. // Make this a fieldset with the three text fields.
  262. $widget += array(
  263. '#type' => 'fieldset',
  264. '#element_validate' => array('field_example_3text_validate'),
  265. // #delta is set so that the validation function will be able
  266. // to access external value information which otherwise would be
  267. // unavailable.
  268. '#delta' => $delta,
  269. '#attached' => array(
  270. 'css' => array(drupal_get_path('module', 'field_example') . '/field_example.css'),
  271. ),
  272. );
  273. // Create a textfield for saturation values for Red, Green, and Blue.
  274. foreach (array('r' => t('Red'), 'g' => t('Green'), 'b' => t('Blue')) as $key => $title) {
  275. $widget[$key] = array(
  276. '#type' => 'textfield',
  277. '#title' => $title,
  278. '#size' => 2,
  279. '#default_value' => array_shift($match[0]),
  280. '#attributes' => array('class' => array('rgb-entry')),
  281. // '#description' => t('The 2-digit hexadecimal representation of the @color saturation, like "a1" or "ff"', array('@color' => $title)),
  282. );
  283. }
  284. break;
  285. }
  286. $element['rgb'] = $widget;
  287. return $element;
  288. }
  289. /**
  290. * Validate the individual fields and then convert them into a single HTML RGB
  291. * value as text.
  292. */
  293. function field_example_3text_validate($element, &$form_state) {
  294. $delta = $element['#delta']; // TODO: Isn't there a better way to find out which element?
  295. $field = $form_state['field'][$element['#field_name']][$element['#language']]['field'];
  296. $field_name = $field['field_name'];
  297. if (isset($form_state['values'][$field_name][$element['#language']][$delta]['rgb'])) {
  298. $values = $form_state['values'][$field_name][$element['#language']][$delta]['rgb'];
  299. foreach (array('r', 'g', 'b') as $colorfield) {
  300. $colorfield_value = hexdec($values[$colorfield]);
  301. // If they left any empty, we'll set the value empty and quit.
  302. if (strlen($values[$colorfield]) == 0) {
  303. form_set_value($element, '', $form_state);
  304. return;
  305. }
  306. // If they gave us anything that's not hex, reject it.
  307. if ( (strlen($values[$colorfield]) != 2) || $colorfield_value < 0 || $colorfield_value > 255) {
  308. form_error($element[$colorfield], t("Saturation value must be a 2-digit hexadecimal value between 00 and ff."));
  309. }
  310. }
  311. $value = sprintf('#%02s%02s%02s', $values['r'], $values['g'], $values['b']);
  312. form_set_value($element, $value, $form_state);
  313. }
  314. }
  315. /**
  316. * Implements hook_field_widget_error().
  317. *
  318. * hook_field_widget_error() lets us figure out what to do with errors
  319. * we might have generated in hook_field_validate(). Generally, we'll just
  320. * call form_error().
  321. *
  322. * @see field_example_field_validate()
  323. * @see form_error()
  324. */
  325. function field_example_field_widget_error($element, $error, $form, &$form_state) {
  326. switch ($error['error']) {
  327. case 'field_example_invalid':
  328. form_error($element, $error['message']);
  329. break;
  330. }
  331. }
  332. /**
  333. * Implements hook_menu().
  334. *
  335. * Provides a simple user interface that tells the developer where to go.
  336. */
  337. function field_example_menu() {
  338. $items['examples/field_example'] = array(
  339. 'title' => 'Field Example',
  340. 'page callback' => '_field_example_page',
  341. 'access callback' => TRUE,
  342. );
  343. return $items;
  344. }
  345. /**
  346. * A simple page to explain to the developer what to do.
  347. */
  348. function _field_example_page() {
  349. return t("The Field Example provides a field composed of an HTML RGB value, like #ff00ff. To use it, add the field to a content type.");
  350. }
  351. /**
  352. * @} End of "defgroup field_example".
  353. */