addressfield_tokens.module 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. /**
  3. * @file
  4. * Main components.
  5. */
  6. function addressfield_tokens_menu() {
  7. $items = array();
  8. $items['admin/config/regional/address'] = array(
  9. 'title' => 'Addresses',
  10. 'description' => 'Settings for address fields and tokens',
  11. 'page callback' => 'drupal_get_form',
  12. 'page arguments' => array('addressfield_tokens_admin_form'),
  13. 'access arguments' => array('administer site configuration'),
  14. 'file' => 'addressfield_tokens.admin.inc',
  15. 'type' => MENU_NORMAL_ITEM,
  16. );
  17. return $items;
  18. }
  19. /**
  20. * Implements hook_theme().
  21. */
  22. function addressfield_tokens_theme($existing, $type, $theme, $path) {
  23. $theme = array(
  24. 'addressfield_formatter' => array(
  25. 'variables' => array('address' => NULL, 'handlers' => array('address')),
  26. 'file' => 'addressfield_tokens.theme.inc',
  27. ),
  28. 'addressfield_formatter__citystate' => array(
  29. 'variables' => array('address' => NULL),
  30. 'file' => 'addressfield_tokens.theme.inc',
  31. ),
  32. 'addressfield_formatter__linear' => array(
  33. 'variables' => array('address' => NULL, 'premise' => TRUE, 'organisation_name' => TRUE, 'name_line' => TRUE),
  34. 'file' => 'addressfield_tokens.theme.inc',
  35. ),
  36. 'addressfield_formatter__components' => array(
  37. 'variables' => array(
  38. 'address' => NULL,
  39. 'components' => array('thoroughfare', 'premise', 'locality', 'administrative_area', 'postal_code', 'country'),
  40. 'separator' => ', ',
  41. ),
  42. 'file' => 'addressfield_tokens.theme.inc',
  43. ),
  44. );
  45. return $theme;
  46. }
  47. /**
  48. * Implements hook_field_formatter_info().
  49. */
  50. function addressfield_tokens_field_formatter_info() {
  51. return array(
  52. 'addressfield_citystate' => array(
  53. 'label' => t('City/State'),
  54. 'field types' => array('addressfield'),
  55. ),
  56. 'addressfield_linear' => array(
  57. 'label' => t('One line'),
  58. 'field types' => array('addressfield'),
  59. ),
  60. 'addressfield_state' => array(
  61. 'label' => t('State'),
  62. 'field types' => array('addressfield'),
  63. ),
  64. 'addressfield_country' => array(
  65. 'label' => t('Country'),
  66. 'field types' => array('addressfield'),
  67. ),
  68. 'addressfield_components' => array(
  69. 'label' => t('Address components'),
  70. 'field types' => array('addressfield'),
  71. 'settings' => array(
  72. 'components' => array('thoroughfare', 'premise', 'locality', 'administrative_area', 'postal_code', 'country'),
  73. 'separator' => ', ',
  74. ),
  75. ),
  76. );
  77. }
  78. /**
  79. * Implements hook_field_formatter_settings_form().
  80. */
  81. function addressfield_tokens_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  82. $display = $instance['display'][$view_mode];
  83. $settings = $display['settings'];
  84. $element = array();
  85. if ($display['type'] == 'addressfield_components') {
  86. $element['components'] = array(
  87. '#type' => 'select',
  88. '#title' => t('Components to render'),
  89. '#multiple' => TRUE,
  90. '#rows' => 10,
  91. '#options' => addressfield_tokens_components(),
  92. '#default_value' => $settings['components'],
  93. '#required' => TRUE,
  94. );
  95. $element['separator'] = array(
  96. '#type' => 'textfield',
  97. '#title' => t('Separator'),
  98. '#description' => t('The separator to use between components. Use \n for a line break.'),
  99. '#default_value' => $settings['separator'],
  100. );
  101. }
  102. return $element;
  103. }
  104. /**
  105. * Implements hook_field_formatter_settings_summary().
  106. */
  107. function addressfield_tokens_field_formatter_settings_summary($field, $instance, $view_mode) {
  108. $display = $instance['display'][$view_mode];
  109. $settings = $display['settings'];
  110. $summary = '';
  111. if ($display['type'] == 'addressfield_components') {
  112. $comps = array_intersect_key(addressfield_tokens_components(), array_flip($settings['components']));
  113. $sep = str_replace('\n', '<br/>', $settings['separator']);
  114. $summary = filter_xss(implode($sep, $comps));
  115. }
  116. return $summary;
  117. }
  118. /**
  119. * Implements hook_field_formatter_view().
  120. */
  121. function addressfield_tokens_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  122. $element = array();
  123. switch ($display['type']) {
  124. case 'addressfield_citystate':
  125. $theme = array('addressfield_formatter__citystate', 'addressfield_formatter');
  126. foreach ($items as $delta => $item) {
  127. if (!empty($item['country'])) {
  128. array_unshift($theme, 'addressfield_formatter__citystate__' . $item['country']);
  129. }
  130. $element[$delta] = array(
  131. '#theme' => $theme,
  132. '#address' => array_map('filter_xss', $item),
  133. );
  134. }
  135. break;
  136. case 'addressfield_linear':
  137. $theme = array('addressfield_formatter__linear', 'addressfield_formatter');
  138. foreach ($items as $delta => $item) {
  139. if (!empty($item['country'])) {
  140. array_unshift($theme, 'addressfield_formatter__linear__' . $item['country']);
  141. }
  142. $element[$delta] = array(
  143. '#theme' => $theme,
  144. '#address' => array_map('filter_xss', $item),
  145. );
  146. }
  147. break;
  148. case 'addressfield_country':
  149. foreach ($items as $delta => $item) {
  150. if (!empty($item['country'])) {
  151. $country = _addressfield_tokens_country($item['country']);
  152. $element[$delta] = array(
  153. '#type' => 'markup',
  154. '#markup' => filter_xss($country),
  155. '#prefix' => '<span class="addressfield-country">',
  156. '#suffix' => '</span>',
  157. );
  158. }
  159. }
  160. break;
  161. case 'addressfield_state':
  162. foreach ($items as $delta => $item) {
  163. if (!empty($item['country']) && !empty($item['administrative_area'])) {
  164. $state = _addressfield_tokens_state($item['country'], $item['administrative_area']);
  165. $element[$delta] = array(
  166. '#type' => 'markup',
  167. '#markup' => filter_xss($state),
  168. '#prefix' => '<span class="addressfield-state">',
  169. '#suffix' => '</span>',
  170. );
  171. }
  172. }
  173. break;
  174. case 'addressfield_components':
  175. $theme = array('addressfield_formatter__components', 'addressfield_formatter');
  176. $settings = $display['settings'];
  177. foreach ($items as $delta => $item) {
  178. if (!empty($item['country'])) {
  179. array_unshift($theme, 'addressfield_formatter__components__' . $item['country']);
  180. }
  181. $element[$delta] = array(
  182. '#theme' => $theme,
  183. '#address' => array_map('filter_xss', $item),
  184. '#components' => $settings['components'],
  185. '#separator' => filter_xss($settings['separator']),
  186. );
  187. }
  188. break;
  189. }
  190. return $element;
  191. }
  192. /**
  193. * Returns the country that has been configured as the default country.
  194. */
  195. function addressfield_tokens_default_country() {
  196. return variable_get('addressfield_tokens_default_country', 'US');
  197. }
  198. /**
  199. * Returns the names that have been configured for each address field.
  200. */
  201. function addressfield_tokens_property_names() {
  202. $names = variable_get('addressfield_tokens_property_names', array());
  203. if (empty($names)) {
  204. $props = addressfield_data_property_info();
  205. foreach ($props as $name => $prop) {
  206. $names[$name] = $prop['label'];
  207. }
  208. }
  209. return $names;
  210. }
  211. function addressfield_tokens_components() {
  212. $comps = &drupal_static(__FUNCTION__, array());
  213. if (empty($comps)) {
  214. $names = addressfield_tokens_property_names();
  215. foreach (array('first_name', 'last_name', 'name_line', 'organisation_name', 'thoroughfare', 'premise', 'locality', 'dependent_locality', 'administrative_area', 'sub_administrative_area', 'postal_code', 'country') as $key) {
  216. $comps[$key] = $names[$key];
  217. if (in_array($key, array('administrative_area', 'country'))) {
  218. $comps[$key . '_full'] = t('@name (full)', array(
  219. '@name' => $names[$key],
  220. ));
  221. }
  222. }
  223. }
  224. return $comps;
  225. }
  226. /**
  227. * Gets the list of countries from the locale settings in Drupal.
  228. *
  229. * @return array An array of countries. The keys are the 2-letter
  230. * abbreviations and the values are the full country names.
  231. */
  232. function _addressfield_tokens_countries() {
  233. $countries = &drupal_static(__FUNCTION__);
  234. if (empty($countries)) {
  235. include_once('includes/locale.inc');
  236. $countries = country_get_list();
  237. }
  238. return $countries;
  239. }
  240. /**
  241. * Gets the name of the country with the given abbreviation.
  242. *
  243. * @param string $country The 2-letter abbreviation of the country.
  244. * @return string The name of the country, or FALSE.
  245. */
  246. function _addressfield_tokens_country($country) {
  247. $countries = _addressfield_tokens_countries();
  248. // Country abbreviations will always be two uppercase letters.
  249. $country = drupal_strtoupper($country);
  250. if (!empty($country) && isset($countries[$country])) {
  251. return check_plain($countries[$country]);
  252. }
  253. return check_plain($country);
  254. }
  255. /**
  256. * Gets the abbreviation of the country with the given name
  257. *
  258. * @param string
  259. * The name of the country.
  260. * @return string $country
  261. * The 2-letter abbreviation of the country, or FALSE.
  262. */
  263. function _addressfield_tokens_country_abbr($country) {
  264. $countries = array_flip(array_map('strtolower', _addressfield_tokens_countries()));
  265. if (isset($countries[strtolower($country)])) {
  266. return check_plain($countries[strtolower($country)]);
  267. }
  268. return check_plain($country);
  269. }
  270. /**
  271. * Gets the list of states in the given country.
  272. *
  273. * @param string $country The 2-letter abbreviation of the country.
  274. *
  275. * @return array An array of countries. The keys are the 2-letter
  276. * abbreviations and the values are the full country names.
  277. */
  278. function _addressfield_tokens_states($country) {
  279. $states = &drupal_static(__FUNCTION__);
  280. $country = drupal_strtoupper($country);
  281. if (!isset($states[$country])) {
  282. $cache = cache_get('addressfield_tokens_states');
  283. if ($cache) {
  284. $states = $cache->data;
  285. }
  286. }
  287. if (!isset($states[$country])) {
  288. $format = addressfield_generate(array('country' => $country), array('address'), array('mode' => 'render'));
  289. if (isset($format['locality_block']['administrative_area']['#options'])) {
  290. $states[$country] = $format['locality_block']['administrative_area']['#options'];
  291. }
  292. else {
  293. $states[$country] = array();
  294. }
  295. cache_set('addressfield_tokens_states', $states);
  296. }
  297. return $states[$country];
  298. }
  299. /**
  300. * Gets the name of the state with the given abbreviation.
  301. *
  302. * @param string $country The 2-letter abbreviation of the country.
  303. * @param string $state The 2-letter abbreviation of the state.
  304. * @return string The name of the state, or FALSE.
  305. */
  306. function _addressfield_tokens_state($country, $state) {
  307. $states = _addressfield_tokens_states($country);
  308. // State abbreviations will usually be two uppercase letters.
  309. $state = drupal_strtoupper($state);
  310. if (!empty($state) && !empty($states[$state])) {
  311. return check_plain($states[$state]);
  312. }
  313. return check_plain($state);
  314. }
  315. /**
  316. * Implements hook_webform_component_info().
  317. */
  318. function addressfield_tokens_webform_component_info() {
  319. $components = array();
  320. $components['addressfield'] = array(
  321. 'label' => t('Address'),
  322. 'description' => t('Address field.'),
  323. 'features' => array(
  324. // Add content to CSV downloads. Defaults to TRUE.
  325. 'csv' => TRUE,
  326. // Show this component in e-mailed submissions. Defaults to TRUE.
  327. 'email' => TRUE,
  328. // Allow this component to be used as an e-mail FROM or TO address.
  329. // Defaults to FALSE.
  330. 'email_address' => FALSE,
  331. // Allow this component to be used as an e-mail SUBJECT or FROM name.
  332. // Defaults to FALSE.
  333. 'email_name' => FALSE,
  334. // This component may be toggled as required or not. Defaults to TRUE.
  335. 'required' => TRUE,
  336. // This component has a title that can be toggled as displayed or not.
  337. 'title_display' => TRUE,
  338. // This component has a title that can be displayed inline.
  339. 'title_inline' => FALSE,
  340. // If this component can be used as a conditional SOURCE. All components
  341. // may always be displayed conditionally, regardless of this setting.
  342. // Defaults to TRUE.
  343. 'conditional' => FALSE,
  344. // If this component allows other components to be grouped within it
  345. // (like a fieldset or tabs). Defaults to FALSE.
  346. 'group' => FALSE,
  347. // If this component can be used for SPAM analysis, usually with Mollom.
  348. 'spam_analysis' => FALSE,
  349. // If this component saves a file that can be used as an e-mail
  350. // attachment. Defaults to FALSE.
  351. 'attachment' => FALSE,
  352. ),
  353. 'file' => 'addressfield_tokens.components.inc',
  354. );
  355. return $components;
  356. }
  357. function _addressfield_tokens_webform_components($nid) {
  358. $components = &drupal_static(__FUNCTION__, array());
  359. if (!isset($components[$nid])) {
  360. $components[$nid] = db_select('webform_component')
  361. ->fields('webform_component')
  362. ->condition('type', 'addressfield')
  363. ->condition('nid', $nid)
  364. ->execute()
  365. ->fetchAllAssoc('cid', PDO::FETCH_ASSOC);
  366. }
  367. return $components[$nid];
  368. }
  369. /**
  370. * Implements hook_webform_submission_load().
  371. */
  372. function addressfield_tokens_webform_submission_load(&$submissions) {
  373. $submissions_reset = reset($submissions);
  374. $nid = $submissions_reset->nid;
  375. $components = _addressfield_tokens_webform_components($nid);
  376. foreach ($submissions as $sid => $submission) {
  377. foreach ($components as $cid => $component) {
  378. if (!empty($submission->data[$cid])) {
  379. $parents = array($cid);
  380. if (!empty($submission->data[$cid]['value'])) {
  381. $parents[] = 'value';
  382. }
  383. $addresses = array();
  384. foreach (drupal_array_get_nested_value($submission->data, $parents) as $delta => $data) {
  385. $data = empty($data) ? array() : unserialize($data);
  386. $addresses[$delta] = $data;
  387. }
  388. drupal_array_set_nested_value($submission->data, $parents, $addresses);
  389. }
  390. }
  391. }
  392. }
  393. /**
  394. * Implements hook_webform_validator_alter().
  395. */
  396. function addressfield_tokens_webform_validator_alter(&$validators) {
  397. $validators['unique']['component_types'][] = 'addressfield';
  398. $validators['oneoftwo']['component_types'][] = 'addressfield';
  399. $validators['oneofseveral']['component_types'][] = 'addressfield';
  400. }