addressfield_tokens.components.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. <?php
  2. // $Id$
  3. /*
  4. * Copyright © 2012 New Signature
  5. *
  6. * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  7. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  8. * You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
  9. * You can contact New Signature by electronic mail at labs@newsignature.com -or- by U.S. Postal Service at 1100 H St. NW, Suite 940, Washington, DC 20005.
  10. */
  11. /**
  12. * @file Webform Component information for an address field type
  13. */
  14. /**
  15. * Specify the default properties of a component.
  16. *
  17. * @return
  18. * An array defining the default structure of a component.
  19. */
  20. function _webform_defaults_addressfield() {
  21. return array (
  22. 'name' => '',
  23. 'form_key' => NULL,
  24. 'mandatory' => 0,
  25. 'pid' => 0,
  26. 'weight' => 0,
  27. 'extra' => array (
  28. 'title_display' => 0,
  29. 'private' => FALSE,
  30. 'attributes' => array (),
  31. 'description' => '',
  32. 'available_countries' => array(),
  33. 'csv_separate' => 0,
  34. ),
  35. );
  36. }
  37. /**
  38. * Generate the form for editing a component.
  39. * Create a set of form elements to be displayed on the form for editing this
  40. * component. Use care naming the form items, as this correlates directly to the
  41. * database schema. The component "Name" and "Description" fields are added to
  42. * every component type and are not necessary to specify here (although they
  43. * may be overridden if desired).
  44. *
  45. * @param $component
  46. * A Webform component array.
  47. *
  48. * @return
  49. * An array of form items to be displayed on the edit component page
  50. */
  51. function _webform_edit_addressfield($component) {
  52. $form = array ();
  53. $form['extra']['available_countries'] = array(
  54. '#type' => 'select',
  55. '#multiple' => TRUE,
  56. '#title' => t('Available countries'),
  57. '#description' => t('If no countries are selected, all countries will be available.'),
  58. '#options' => _addressfield_country_options_list(),
  59. '#default_value' => $component['extra']['available_countries'],
  60. );
  61. $form['extra']['csv_separate'] = array(
  62. '#type' => 'radios',
  63. '#title' => t('CSV download'),
  64. '#description' => t('How would you like addresses presented in CSV downloads?'),
  65. '#options' => array(
  66. 0 => t('Display entire address in a single column'),
  67. 1 => t('Display each address component in a separate column'),
  68. ),
  69. '#default_value' => $component['extra']['csv_separate'],
  70. );
  71. return $form;
  72. }
  73. /**
  74. * Render a Webform component to be part of a form.
  75. *
  76. * @param $component
  77. * A Webform component array.
  78. * @param $value
  79. * If editing an existing submission or resuming a draft, this will contain
  80. * an array of values to be shown instead of the default in the component
  81. * configuration. This value will always be an array, keyed numerically for
  82. * each value saved in this field.
  83. * @param $filter
  84. * Whether or not to filter the contents of descriptions and values when
  85. * rendering the component. Values need to be unfiltered to be editable by
  86. * Form Builder.
  87. *
  88. * @see _webform_client_form_add_component()
  89. */
  90. function _webform_render_addressfield($component, $value = NULL, $filter = TRUE) {
  91. $element = array (
  92. '#type' => 'fieldset',
  93. '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
  94. '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
  95. '#attributes' => $component['extra']['attributes'],
  96. '#theme_wrappers' => array ( 'webform_element' ),
  97. '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
  98. '#required' => $component['mandatory'],
  99. '#weight' => $component['weight'],
  100. '#translatable' => array (
  101. 'title',
  102. 'description',
  103. ),
  104. );
  105. $available = !empty($component['extra']['available_countries']) ? $component['extra']['available_countries'] : NULL;
  106. // Get the current address
  107. if (!empty($value[0])) {
  108. if (is_string($value[0])) {
  109. $address = unserialize($value[0]);
  110. }
  111. else {
  112. $address = $value[0];
  113. }
  114. }
  115. elseif (!empty($component['value'])) {
  116. $address = $component['value'];
  117. }
  118. else {
  119. $address = _webform_addressfield($component['cid']);
  120. }
  121. if (empty($address)) {
  122. $address = addressfield_default_values($available);
  123. }
  124. // Generate the address form.
  125. $context = array(
  126. 'mode' => 'form',
  127. );
  128. $element += addressfield_generate($address, array('address'), $context);
  129. if (!empty($available)) {
  130. $element['country']['#options'] = array_intersect_key($element['country']['#options'], $available);
  131. }
  132. $element['country']['#element_validate'] = array('_webform_addressfield_country_validate');
  133. $element['country']['#cid'] = $component['cid'];
  134. $element['country']['#limit_validation_errors'] = array();
  135. $form_state = array();
  136. drupal_alter('field_widget_addressfield_standard_form', $element, $form_state, $context);
  137. return $element;
  138. }
  139. /**
  140. * Stores an addressfield submitted in a webform component. Ideally we should store
  141. * it in the $form_state instead, but there appears to be no way to get it to actually
  142. * pass through to _webform_render_addressfield().
  143. *
  144. * @param $cid integer The ID of the webform component.
  145. * @param $address array If set, this address will be stored with the given $cid.
  146. * @return array The address stored with the given $cid, if there is one; otherwise, NULL.
  147. */
  148. function _webform_addressfield($cid, $address = NULL) {
  149. $out = &drupal_static(__FUNCTION__, array());
  150. if (isset($address)) {
  151. $out[$cid] = $address;
  152. }
  153. if (isset($out[$cid])) {
  154. return $out[$cid];
  155. }
  156. return NULL;
  157. }
  158. /**
  159. * Validates a country, and if it changes, rebuilds the form for the new country
  160. */
  161. function _webform_addressfield_country_validate(&$element, &$form_state) {
  162. // If the country was changed, rebuild the form.
  163. if ($element['#default_value'] != $element['#value']) {
  164. $form_state['rebuild'] = TRUE;
  165. }
  166. $cid = $element['#cid'];
  167. $parents = $element['#parents'];
  168. array_pop($parents);
  169. // Search through the form values to find the current address.
  170. $address = drupal_array_get_nested_value($form_state['values'], $parents);
  171. _webform_addressfield($cid, $address);
  172. }
  173. /**
  174. * Display the result of a submission for a component.
  175. * The output of this function will be displayed under the "Results" tab then
  176. * "Submissions". This should output the saved data in some reasonable manner.
  177. *
  178. * @param $component
  179. * A Webform component array.
  180. * @param $value
  181. * An array of information containing the submission result, directly
  182. * correlating to the webform_submitted_data database table schema.
  183. * @param $format
  184. * Either 'html' or 'text'. Defines the format that the content should be
  185. * returned as. Make sure that returned content is run through check_plain()
  186. * or other filtering functions when returning HTML.
  187. *
  188. * @return
  189. * A renderable element containing at the very least these properties:
  190. * - #title
  191. * - #weight
  192. * - #component
  193. * - #format
  194. * - #value
  195. * Webform also uses #theme_wrappers to output the end result to the user,
  196. * which will properly format the label and content for use within an e-mail
  197. * (such as wrapping the text) or as HTML (ensuring consistent output).
  198. */
  199. function _webform_display_addressfield($component, $value, $format = 'html') {
  200. $address = NULL;
  201. if (isset($value[0])) {
  202. $address = $value[0];
  203. if (is_string($address)) {
  204. $address = unserialize($address);
  205. }
  206. }
  207. return array (
  208. '#title' => $component['name'],
  209. '#weight' => $component['weight'],
  210. '#theme' => $format == 'html' ? 'addressfield_formatter' : 'addressfield_formatter__linear',
  211. '#theme_wrappers' => $format == 'html' ? array ( 'webform_element' ) : array ( 'webform_element_text' ),
  212. '#post_render' => array ( 'webform_element_wrapper' ),
  213. '#component' => $component,
  214. '#format' => $format,
  215. '#address' => $address,
  216. );
  217. }
  218. /**
  219. * A hook for changing the input values before saving to the database.
  220. * Webform expects a component to consist of a single field, or a single array
  221. * of fields. If you have a component that requires a deeper form tree
  222. * you must flatten the data into a single array using this callback
  223. * or by setting #parents on each field to avoid data loss and/or unexpected
  224. * behavior.
  225. * Note that Webform will save the result of this function directly into the
  226. * database.
  227. *
  228. * @param $component
  229. * A Webform component array.
  230. * @param $value
  231. * The POST data associated with the user input.
  232. *
  233. * @return
  234. * An array of values to be saved into the database. Note that this should be
  235. * a numerically keyed array.
  236. */
  237. function _webform_submit_addressfield($component, $value) {
  238. return serialize($value);
  239. }
  240. /**
  241. * Calculate and returns statistics about results for this component.
  242. * This takes into account all submissions to this webform. The output of this
  243. * function will be displayed under the "Results" tab then "Analysis".
  244. *
  245. * @param $component
  246. * An array of information describing the component, directly correlating to
  247. * the webform_component database schema.
  248. * @param $sids
  249. * An optional array of submission IDs (sid). If supplied, the analysis will
  250. * be limited to these sids.
  251. * @param $single
  252. * Boolean flag determining if the details about a single component are being
  253. * shown. May be used to provided detailed information about a single
  254. * component's analysis, such as showing "Other" options within a select list.
  255. *
  256. * @return
  257. * An array of data rows, each containing a statistic for this component's
  258. * submissions.
  259. */
  260. function _webform_analysis_addressfield($component, $sids = array (), $single = FALSE) {
  261. // TODO Update this function
  262. // Generate the list of options and questions.
  263. $query = db_select('webform_submitted_data', 'wsd')
  264. ->fields('wsd', array ('data'))
  265. ->condition('nid', $component['nid'])
  266. ->condition('cid', $component['cid']);
  267. if ( count($sids) ) {
  268. $query->condition('sid', $sids, 'IN');
  269. }
  270. $non_blanks = 0;
  271. $submissions = 0;
  272. $results = $query->execute();
  273. foreach ($results as $row) {
  274. if ( drupal_strlen(trim($row->data)) > 0 ) {
  275. $non_blanks++;
  276. }
  277. $submissions++;
  278. }
  279. $rows[0] = array (
  280. t('Left Blank'),
  281. ( $submissions - $non_blanks )
  282. );
  283. $rows[1] = array (
  284. t('User entered value'),
  285. $non_blanks
  286. );
  287. return $rows;
  288. }
  289. /**
  290. * Return the result of a component value for display in a table.
  291. * The output of this function will be displayed under the "Results" tab then
  292. * "Table".
  293. *
  294. * @param $component
  295. * A Webform component array.
  296. * @param $value
  297. * An array of information containing the submission result, directly
  298. * correlating to the webform_submitted_data database schema.
  299. *
  300. * @return
  301. * Textual output formatted for human reading.
  302. */
  303. function _webform_table_addressfield($component, $value) {
  304. if (!empty($value[0])) {
  305. return theme('addressfield_formatter', array( 'address' => $value[0] ));
  306. }
  307. return '';
  308. }
  309. /**
  310. * Return the header for this component to be displayed in a CSV file.
  311. * The output of this function will be displayed under the "Results" tab then
  312. * "Download".
  313. *
  314. * @param $component
  315. * A Webform component array.
  316. * @param $export_options
  317. * An array of options that may configure export of this field.
  318. *
  319. * @return
  320. * An array of data to be displayed in the first three rows of a CSV file, not
  321. * including either prefixed or trailing commas.
  322. */
  323. function _webform_csv_headers_addressfield($component, $export_options) {
  324. $header = array ();
  325. if (!empty($component['extra']['csv_separate']) && $component['extra']['csv_separate'] == 1) {
  326. $header[0] = array();
  327. $header[1] = array();
  328. $header[2] = array();
  329. foreach (addressfield_tokens_property_names() as $key => $name) {
  330. $header[0][] = '';
  331. $header[1][] = (empty($header[1])) ? $component['name'] : '';
  332. $header[2][] = $name;
  333. }
  334. }
  335. else {
  336. $header[0] = array('');
  337. $header[1] = array();
  338. $header[2] = array($component['name']);
  339. }
  340. return $header;
  341. }
  342. /**
  343. * Format the submitted data of a component for CSV downloading.
  344. * The output of this function will be displayed under the "Results" tab then
  345. * "Download".
  346. *
  347. * @param $component
  348. * A Webform component array.
  349. * @param $export_options
  350. * An array of options that may configure export of this field.
  351. * @param $value
  352. * An array of information containing the submission result, directly
  353. * correlating to the webform_submitted_data database schema.
  354. *
  355. * @return
  356. * An array of items to be added to the CSV file. Each value within the array
  357. * will be another column within the file. This function is called once for
  358. * every row of data.
  359. */
  360. function _webform_csv_data_addressfield($component, $export_options, $value) {
  361. if (!empty($component['extra']['csv_separate']) && $component['extra']['csv_separate'] == 1) {
  362. $return = array();
  363. foreach (addressfield_tokens_property_names() as $key => $name) {
  364. $return[] = (isset($value[0][$key])) ? $value[0][$key] : '';
  365. }
  366. return $return;
  367. }
  368. else {
  369. if (!empty($value[0])) {
  370. return theme('addressfield_formatter__linear', array( 'address' => $value[0] ));
  371. }
  372. return '';
  373. }
  374. }