webform.api.php 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. <?php
  2. /**
  3. * @file
  4. * Sample hooks demonstrating usage in Webform.
  5. */
  6. /**
  7. * @defgroup webform_hooks Webform Module Hooks
  8. * @{
  9. * Webform's hooks enable other modules to intercept events within Webform, such
  10. * as the completion of a submission or adding validation. Webform's hooks also
  11. * allow other modules to provide additional components for use within forms.
  12. */
  13. /**
  14. * Define callbacks that can be used as select list options.
  15. *
  16. * When users create a select component, they may select a pre-built list of
  17. * certain options. Webform core provides a few of these lists such as the
  18. * United States, countries of the world, and days of the week. This hook
  19. * provides additional lists that may be utilized.
  20. *
  21. * @see webform_options_example()
  22. * @see hook_webform_select_options_info_alter()
  23. *
  24. * @return array
  25. * An array of callbacks that can be used for select list options. This array
  26. * should be keyed by the "name" of the pre-defined list. The values should
  27. * be an array with the following additional keys:
  28. * - title: The translated title for this list.
  29. * - options callback: The name of a function implementing
  30. * callback_webform_options() that will return the list.
  31. * - options arguments: Any additional arguments to send to the callback.
  32. * - file: Optional. The file containing the options callback, relative to
  33. * the module root.
  34. */
  35. function hook_webform_select_options_info() {
  36. $items = array();
  37. $items['days'] = array(
  38. 'title' => t('Days of the week'),
  39. 'options callback' => 'webform_options_days',
  40. 'file' => 'includes/webform.options.inc',
  41. );
  42. return $items;
  43. }
  44. /**
  45. * Alter the list of select list options provided by Webform and other modules.
  46. *
  47. * @see hook_webform_select_options_info()
  48. */
  49. function hook_webform_select_options_info_alter(&$items) {
  50. // Remove the days of the week options.
  51. unset($items['days']);
  52. }
  53. /**
  54. * Define a list of options that Webform may use in a select component.
  55. *
  56. * Callback for hook_webform_select_options_info().
  57. *
  58. * @param $component
  59. * The Webform component array for the select component being displayed.
  60. * @param $flat
  61. * Boolean value indicating whether the returned list needs to be a flat array
  62. * of key => value pairs. Select components support up to one level of
  63. * nesting, but when results are displayed, the list needs to be returned
  64. * without the nesting.
  65. * @param $arguments
  66. * The "options arguments" specified in hook_webform_select_options_info().
  67. *
  68. * @return array
  69. * An array of key => value pairs suitable for a select list's #options
  70. * FormAPI property.
  71. */
  72. function callback_webform_options($component, $flat, $arguments) {
  73. $options = array(
  74. 'one' => t('Pre-built option one'),
  75. 'two' => t('Pre-built option two'),
  76. 'three' => t('Pre-built option three'),
  77. );
  78. return $options;
  79. }
  80. /**
  81. * Respond to the loading of Webform submissions.
  82. *
  83. * @param $submissions
  84. * An array of Webform submissions that are being loaded, keyed by the
  85. * submission ID. Modifications to the submissions are done by reference.
  86. */
  87. function hook_webform_submission_load(&$submissions) {
  88. foreach ($submissions as $sid => $submission) {
  89. $submissions[$sid]->new_property = 'foo';
  90. }
  91. }
  92. /**
  93. * Respond to the creation of a new submission from form values.
  94. *
  95. * This hook is called when a user has completed a submission to initialize the
  96. * submission object. After this object has its values populated, it will be
  97. * saved by webform_submission_insert(). Note that this hook is only called for
  98. * new submissions, not for submissions being edited. If responding to the
  99. * saving of all submissions, it's recommended to use
  100. * hook_webform_submission_presave().
  101. *
  102. * @param $submission
  103. * The submission object that has been created.
  104. * @param $node
  105. * The Webform node for which this submission is being saved.
  106. * @param $account
  107. * The user account that is creating the submission.
  108. * @param $form_state
  109. * The contents of form state that is the basis for this submission.
  110. *
  111. * @see webform_submission_create()
  112. */
  113. function hook_webform_submission_create_alter(&$submission, &$node, &$account, &$form_state) {
  114. $submission->new_property = TRUE;
  115. }
  116. /**
  117. * Modify a Webform submission, prior to saving it in the database.
  118. *
  119. * @param $node
  120. * The Webform node on which this submission was made.
  121. * @param $submission
  122. * The Webform submission that is about to be saved to the database.
  123. */
  124. function hook_webform_submission_presave($node, &$submission) {
  125. // Update some component's value before it is saved.
  126. $component_id = 4;
  127. $submission->data[$component_id][0] = 'foo';
  128. }
  129. /**
  130. * Respond to a Webform submission being inserted.
  131. *
  132. * Note that this hook is called after a submission has already been saved to
  133. * the database. If needing to modify the submission prior to insertion, use
  134. * hook_webform_submission_presave().
  135. *
  136. * @param $node
  137. * The Webform node on which this submission was made.
  138. * @param $submission
  139. * The Webform submission that was just inserted into the database.
  140. */
  141. function hook_webform_submission_insert($node, $submission) {
  142. // Insert a record into a 3rd-party module table when a submission is added.
  143. db_insert('mymodule_table')
  144. ->fields(array(
  145. 'nid' => $node->nid,
  146. 'sid' => $submission->sid,
  147. 'foo' => 'foo_data',
  148. ))
  149. ->execute();
  150. }
  151. /**
  152. * Respond to a Webform submission being updated.
  153. *
  154. * Note that this hook is called after a submission has already been saved to
  155. * the database. If needing to modify the submission prior to updating, use
  156. * hook_webform_submission_presave().
  157. *
  158. * @param $node
  159. * The Webform node on which this submission was made.
  160. * @param $submission
  161. * The Webform submission that was just updated in the database.
  162. */
  163. function hook_webform_submission_update($node, $submission) {
  164. // Update a record in a 3rd-party module table when a submission is updated.
  165. db_update('mymodule_table')
  166. ->fields(array(
  167. 'foo' => 'foo_data',
  168. ))
  169. ->condition('nid', $node->nid)
  170. ->condition('sid', $submission->sid)
  171. ->execute();
  172. }
  173. /**
  174. * Respond to a Webform submission being deleted.
  175. *
  176. * @param $node
  177. * The Webform node on which this submission was made.
  178. * @param $submission
  179. * The Webform submission that was just deleted from the database.
  180. */
  181. function hook_webform_submission_delete($node, $submission) {
  182. // Delete a record from a 3rd-party module table when a submission is deleted.
  183. db_delete('mymodule_table')
  184. ->condition('nid', $node->nid)
  185. ->condition('sid', $submission->sid)
  186. ->execute();
  187. }
  188. /**
  189. * Provide a list of actions that can be executed on a submission.
  190. *
  191. * Some actions are displayed in the list of submissions such as edit, view, and
  192. * delete. All other actions are displayed only when viewing the submission.
  193. * These additional actions may be specified in this hook. Examples included
  194. * directly in the Webform module include PDF, print, and resend e-mails. Other
  195. * modules may extend this list by using this hook.
  196. *
  197. * @param $node
  198. * The Webform node on which this submission was made.
  199. * @param $submission
  200. * The Webform submission on which the actions may be performed.
  201. *
  202. * @return array
  203. * List of action.
  204. */
  205. function hook_webform_submission_actions($node, $submission) {
  206. $actions = array();
  207. if (webform_results_access($node)) {
  208. $actions['myaction'] = array(
  209. 'title' => t('Do my action'),
  210. 'href' => 'node/' . $node->nid . '/submission/' . $submission->sid . '/myaction',
  211. 'query' => drupal_get_destination(),
  212. );
  213. }
  214. return $actions;
  215. }
  216. /**
  217. * Modify the draft to be presented for editing.
  218. *
  219. * When drafts are enabled for the webform, by default, a pre-existing draft is
  220. * presented when the webform is displayed to that user. To allow multiple
  221. * drafts, implement this alter function to set the $sid to NULL, or use your
  222. * application's business logic to determine whether a new draft or which of
  223. * he pre-existing drafts should be presented.
  224. *
  225. * @param int $sid
  226. * The id of the most recent submission to be presented for editing. Change
  227. * to a different draft's sid or set to NULL for a new draft.
  228. * @param array $context
  229. * Array of context with indices 'nid' and 'uid'.
  230. */
  231. function hook_webform_draft_alter(&$sid, array $context) {
  232. if ($_GET['newdraft']) {
  233. $sid = NULL;
  234. }
  235. }
  236. /**
  237. * Alter the display of a Webform submission.
  238. *
  239. * This function applies to both e-mails sent by Webform and normal display of
  240. * submissions when viewing through the administrative interface.
  241. *
  242. * @param $renderable
  243. * The Webform submission in a renderable array, similar to FormAPI's
  244. * structure. This variable must be passed in by-reference. Important
  245. * properties of this array include #node, #submission, #email, and #format,
  246. * which can be used to find the context of the submission that is being
  247. * rendered.
  248. */
  249. function hook_webform_submission_render_alter(&$renderable) {
  250. // Remove page breaks from sent e-mails.
  251. if (isset($renderable['#email'])) {
  252. foreach (element_children($renderable) as $key) {
  253. if ($renderable[$key]['#component']['type'] == 'pagebreak') {
  254. unset($renderable[$key]);
  255. }
  256. }
  257. }
  258. }
  259. /**
  260. * Modify a loaded Webform component.
  261. *
  262. * IMPORTANT: This hook does not actually exist because components are loaded
  263. * in bulk as part of webform_node_load(). Use hook_node_load() to modify loaded
  264. * components when the node is loaded. This example is provided merely to point
  265. * to hook_node_load().
  266. *
  267. * @see hook_nodeapi()
  268. * @see webform_node_load()
  269. */
  270. function hook_webform_component_load() {
  271. // This hook does not exist. Instead use hook_node_load().
  272. }
  273. /**
  274. * Modify a Webform component before it is saved to the database.
  275. *
  276. * Note that most of the time this hook is not necessary, because Webform will
  277. * automatically add data to the component based on the component form. Using
  278. * hook_form_alter() will be sufficient in most cases.
  279. *
  280. * @param $component
  281. * The Webform component being saved.
  282. *
  283. * @see hook_form_alter()
  284. * @see webform_component_edit_form()
  285. */
  286. function hook_webform_component_presave(&$component) {
  287. $component['extra']['new_option'] = 'foo';
  288. }
  289. /**
  290. * Respond to a Webform component being inserted into the database.
  291. */
  292. function hook_webform_component_insert($component) {
  293. // Insert a record into a 3rd-party module table when a component is inserted.
  294. db_insert('mymodule_table')
  295. ->fields(array(
  296. 'nid' => $component['nid'],
  297. 'cid' => $component['cid'],
  298. 'foo' => 'foo_data',
  299. ))
  300. ->execute();
  301. }
  302. /**
  303. * Respond to a Webform component being updated in the database.
  304. */
  305. function hook_webform_component_update($component) {
  306. // Update a record in a 3rd-party module table when a component is updated.
  307. db_update('mymodule_table')
  308. ->fields(array(
  309. 'foo' => 'foo_data',
  310. ))
  311. ->condition('nid', $component['nid'])
  312. ->condition('cid', $component['cid'])
  313. ->execute();
  314. }
  315. /**
  316. * Respond to a Webform component being deleted.
  317. */
  318. function hook_webform_component_delete($component) {
  319. // Delete a record in a 3rd-party module table when a component is deleted.
  320. db_delete('mymodule_table')
  321. ->condition('nid', $component['nid'])
  322. ->condition('cid', $component['cid'])
  323. ->execute();
  324. }
  325. /**
  326. * Alter the entire analysis before rendering to the page on the Analysis tab.
  327. *
  328. * This alter hook allows modification of the entire analysis of a node's
  329. * Webform results. The resulting analysis is displayed on the Results ->
  330. * Analysis tab on the Webform.
  331. *
  332. * @param array $analysis
  333. * A Drupal renderable array, passed by reference, containing the entire
  334. * contents of the analysis page. This typically will contain the following
  335. * two major keys:
  336. * - form: The form for configuring the shown analysis.
  337. * - components: The list of analyses for each analysis-enabled component
  338. * for the node. Each keyed by its component ID.
  339. */
  340. function hook_webform_analysis_alter(array &$analysis) {
  341. $node = $analysis['#node'];
  342. // Add an additional piece of information to every component's analysis:
  343. foreach (element_children($analysis['components']) as $cid) {
  344. $component = $node->components[$cid];
  345. $analysis['components'][$cid]['chart'] = array(
  346. '#markup' => t('Chart for the @name component', array('@name' => $component['name'])),
  347. );
  348. }
  349. }
  350. /**
  351. * Alter data when displaying an analysis on that component.
  352. *
  353. * This hook modifies the data from an individual component's analysis results.
  354. * It can be used to add additional analysis, or to modify the existing results.
  355. * If needing to alter the entire set of analyses rather than an individual
  356. * component, hook_webform_analysis_alter() may be used instead.
  357. *
  358. * @param array $data
  359. * An array containing the result of a components analysis hook, passed by
  360. * reference. This is passed directly from a component's
  361. * _webform_analysis_component() function. See that hook for more information
  362. * on this value.
  363. * @param object $node
  364. * The node object that contains the component being analyzed.
  365. * @param array $component
  366. * The Webform component array whose analysis results are being displayed.
  367. *
  368. * @see _webform_analysis_component()
  369. * @see hook_webform_analysis_alter()
  370. */
  371. function hook_webform_analysis_component_data_alter(array &$data, $node, array $component) {
  372. if ($component['type'] === 'textfield') {
  373. // Do not display rows that contain a zero value.
  374. foreach ($data as $row_number => $row_data) {
  375. if ($row_data[1] === 0) {
  376. unset($data[$row_number]);
  377. }
  378. }
  379. }
  380. }
  381. /**
  382. * Alter a Webform submission's header when exported.
  383. */
  384. function hook_webform_csv_header_alter(&$header, $component) {
  385. // Use the machine name for component headers, but only for the webform
  386. // with node 5 and components that are text fields.
  387. if ($component['nid'] == 5 && $component['type'] == 'textfield') {
  388. $header[2] = $component['form_key'];
  389. }
  390. }
  391. /**
  392. * Alter a Webform submission's data when exported.
  393. */
  394. function hook_webform_csv_data_alter(&$data, $component, $submission) {
  395. // If a value of a field was left blank, use the value from another
  396. // field.
  397. if ($component['cid'] == 1 && empty($data)) {
  398. $data = $submission->data[2]['value'][0];
  399. }
  400. }
  401. /**
  402. * Define components to Webform.
  403. *
  404. * @return array
  405. * An array of components, keyed by machine name. Required properties are
  406. * "label" and "description". The "features" array defines which capabilities
  407. * the component has, such as being displayed in e-mails or csv downloads.
  408. * A component like "markup" for example would not show in these locations.
  409. * The possible features of a component include:
  410. *
  411. * - csv
  412. * - email
  413. * - email_address
  414. * - email_name
  415. * - required
  416. * - conditional
  417. * - spam_analysis
  418. * - group
  419. * - private
  420. *
  421. * Note that most of these features do not indicate the default state, but
  422. * determine if the component can have this property at all. Setting
  423. * "required" to TRUE does not mean that a component's fields will always be
  424. * required, but instead give the option to the administrator to choose the
  425. * requiredness. See the example implementation for details on how these
  426. * features may be set.
  427. *
  428. * An optional "file" may be specified to be loaded when the component is
  429. * needed. A set of callbacks will be established based on the name of the
  430. * component. All components follow the pattern:
  431. *
  432. * _webform_[callback]_[component]
  433. *
  434. * Where [component] is the name of the key of the component and [callback] is
  435. * any of the following:
  436. *
  437. * - defaults
  438. * - edit
  439. * - render
  440. * - display
  441. * - submit
  442. * - delete
  443. * - help
  444. * - theme
  445. * - analysis
  446. * - table
  447. * - csv_headers
  448. * - csv_data
  449. *
  450. * See the sample component implementation for details on each one of these
  451. * callbacks.
  452. *
  453. * @see webform_components()
  454. */
  455. function hook_webform_component_info() {
  456. $components = array();
  457. $components['textfield'] = array(
  458. 'label' => t('Textfield'),
  459. 'description' => t('Basic textfield type.'),
  460. 'features' => array(
  461. // This component includes an analysis callback. Defaults to TRUE.
  462. 'analysis' => TRUE,
  463. // Add content to CSV downloads. Defaults to TRUE.
  464. 'csv' => TRUE,
  465. // This component supports default values. Defaults to TRUE.
  466. 'default_value' => FALSE,
  467. // This component supports a description field. Defaults to TRUE.
  468. 'description' => FALSE,
  469. // Show this component in e-mailed submissions. Defaults to TRUE.
  470. 'email' => TRUE,
  471. // Allow this component to be used as an e-mail FROM or TO address.
  472. // Defaults to FALSE.
  473. 'email_address' => FALSE,
  474. // Allow this component to be used as an e-mail SUBJECT or FROM name.
  475. // Defaults to FALSE.
  476. 'email_name' => TRUE,
  477. // This component may be toggled as required or not. Defaults to TRUE.
  478. 'required' => TRUE,
  479. // This component supports a title attribute. Defaults to TRUE.
  480. 'title' => FALSE,
  481. // This component has a title that can be toggled as displayed or not.
  482. 'title_display' => TRUE,
  483. // This component has a title that can be displayed inline.
  484. 'title_inline' => TRUE,
  485. // If this component can be used as a conditional SOURCE. All components
  486. // may always be displayed conditionally, regardless of this setting.
  487. // Defaults to TRUE.
  488. 'conditional' => TRUE,
  489. // If this component allows other components to be grouped within it
  490. // (like a fieldset or tabs). Defaults to FALSE.
  491. 'group' => FALSE,
  492. // If this component can be used for SPAM analysis.
  493. 'spam_analysis' => FALSE,
  494. // If this component saves a file that can be used as an e-mail
  495. // attachment. Defaults to FALSE.
  496. 'attachment' => FALSE,
  497. // If this component reflects a time range and should use labels such as
  498. // "Before" and "After" when exposed as filters in Views module.
  499. 'views_range' => FALSE,
  500. // Set this to FALSE if this component cannot be used as a private
  501. // component. If this is not FALSE, in your implementation of
  502. // _webform_defaults_COMPONENT(), set ['extra']['private'] property to
  503. // TRUE or FALSE.
  504. 'private' => FALSE,
  505. ),
  506. // Specify the conditional behaviour of this component.
  507. // Examples are 'string', 'date', 'time', 'numeric', 'select'.
  508. // Defaults to 'string'.
  509. 'conditional_type' => 'string',
  510. 'file' => 'components/textfield.inc',
  511. );
  512. return $components;
  513. }
  514. /**
  515. * Alter the list of available Webform components.
  516. *
  517. * @param $components
  518. * A list of existing components as defined by hook_webform_component_info().
  519. *
  520. * @see hook_webform_component_info()
  521. */
  522. function hook_webform_component_info_alter(&$components) {
  523. // Completely remove a component.
  524. unset($components['grid']);
  525. // Change the name of a component.
  526. $components['textarea']['label'] = t('Text box');
  527. }
  528. /**
  529. * Alter the list of Webform component default values.
  530. *
  531. * @param $defaults
  532. * A list of component defaults as defined by _webform_defaults_COMPONENT().
  533. * @param $type
  534. * The component type whose defaults are being provided.
  535. *
  536. * @see _webform_defaults_component()
  537. */
  538. function hook_webform_component_defaults_alter(&$defaults, $type) {
  539. // Alter a default for all component types.
  540. $defaults['required'] = 1;
  541. // Add a default for a new field added via hook_form_alter() or
  542. // hook_form_FORM_ID_alter() for all component types.
  543. $defaults['extra']['added_field'] = t('Added default value');
  544. // Add or alter defaults for specific component types:
  545. switch ($type) {
  546. case 'select':
  547. $defaults['extra']['optrand'] = 1;
  548. break;
  549. case 'textfield':
  550. case 'textarea':
  551. $defaults['extra']['another_added_field'] = t('Another added default value');
  552. }
  553. }
  554. /**
  555. * Alter access to a Webform submission.
  556. *
  557. * @param $node
  558. * The Webform node on which this submission was made.
  559. * @param $submission
  560. * The Webform submission.
  561. * @param $op
  562. * The operation to be performed on the submission. Possible values are:
  563. * - "view"
  564. * - "edit"
  565. * - "delete"
  566. * - "list"
  567. * @param $account
  568. * A user account object.
  569. *
  570. * @return bool
  571. * TRUE if the current user has access to submission,
  572. * or FALSE otherwise.
  573. */
  574. function hook_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
  575. switch ($op) {
  576. case 'view':
  577. return TRUE;
  578. case 'edit':
  579. return FALSE;
  580. case 'delete':
  581. return TRUE;
  582. case 'list':
  583. return TRUE;
  584. }
  585. }
  586. /**
  587. * Determine if a user has access to see the results of a webform.
  588. *
  589. * Note in addition to the view access to the results granted here, the $account
  590. * must also have view access to the Webform node in order to see results.
  591. * Access via this hook is in addition (adds permission) to the standard
  592. * webform access.
  593. *
  594. * @param $node
  595. * The Webform node to check access on.
  596. * @param $account
  597. * The user account to check access on.
  598. *
  599. * @return bool
  600. * TRUE or FALSE if the user can access the webform results.
  601. *
  602. * @see webform_results_access()
  603. */
  604. function hook_webform_results_access($node, $account) {
  605. // Let editors view results of unpublished webforms.
  606. if ($node->status == 0 && in_array('editor', $account->roles)) {
  607. return TRUE;
  608. }
  609. else {
  610. return FALSE;
  611. }
  612. }
  613. /**
  614. * Determine if a user has access to clear the results of a webform.
  615. *
  616. * Access via this hook is in addition (adds permission) to the standard
  617. * webform access (delete all webform submissions).
  618. *
  619. * @param object $node
  620. * The Webform node to check access on.
  621. * @param object $account
  622. * The user account to check access on.
  623. *
  624. * @return bool
  625. * TRUE or FALSE if the user can access the webform results.
  626. *
  627. * @see webform_results_clear_access()
  628. */
  629. function hook_webform_results_clear_access($node, $account) {
  630. return user_access('my additional access', $account);
  631. }
  632. /**
  633. * Overrides the node_access and user_access permissions.
  634. *
  635. * Overrides the node_access and user_access permission to access and edit
  636. * webform components, e-mails, conditions, and form settings.
  637. *
  638. * Return NULL to defer to other modules. If all implementations defer, then
  639. * access to the node's EDIT tab plus 'edit webform components' permission
  640. * determines access. To grant access, return TRUE; to deny access, return
  641. * FALSE. If more than one implementation return TRUE/FALSE, all must be TRUE
  642. * to grant access.
  643. *
  644. * In this way, access to the EDIT tab of the node may be decoupled from
  645. * access to the WEBFORM tab. When returning TRUE, consider all aspects of
  646. * access as this will be the only test. For example, 'return TRUE;' would grant
  647. * annonymous access to creating webform components, which seldom be desired.
  648. *
  649. * @param object $node
  650. * The Webform node to check access on.
  651. * @param object $account
  652. * The user account to check access on.
  653. *
  654. * @return bool|null
  655. * TRUE or FALSE if the user can access the webform results, or NULL if
  656. * access should be deferred to other implementations of this hook or
  657. * node_access('update') plus user_access('edit webform components').
  658. *
  659. * @see webform_node_update_access()
  660. */
  661. function hook_webform_update_access($node, $account) {
  662. // Allow anyone who can see webform_editable_by_user nodes and who has
  663. // 'my webform component edit access' permission to see, edit, and delete the
  664. // webform components, e-mails, conditionals, and form settings.
  665. if ($node->type == 'webform_editable_by_user') {
  666. return node_access('view', $node, $account) && user_access('my webform component edit access', $account);
  667. }
  668. }
  669. /**
  670. * Return an array of files associated with the component.
  671. *
  672. * The output of this function will be used to attach files to e-mail messages.
  673. *
  674. * @param $component
  675. * A Webform component array.
  676. * @param $value
  677. * An array of information containing the submission result, directly
  678. * correlating to the webform_submitted_data database schema.
  679. *
  680. * @return array
  681. * An array of files, each file is an array with following keys:
  682. * - filepath: The relative path to the file.
  683. * - filename: The name of the file including the extension.
  684. * - filemime: The mimetype of the file.
  685. * This will result in an array looking something like this:
  686. *
  687. * @code
  688. * array[0] => array(
  689. * 'filepath' => '/sites/default/files/attachment.txt',
  690. * 'filename' => 'attachment.txt',
  691. * 'filemime' => 'text/plain',
  692. * );
  693. * @endcode
  694. */
  695. function _webform_attachments_component($component, $value) {
  696. $files = array();
  697. $files[] = (array) file_load($value[0]);
  698. return $files;
  699. }
  700. /**
  701. * Alter default settings for a newly created webform node.
  702. *
  703. * @param array $defaults
  704. * Default settings for a newly created webform node as defined by
  705. * webform_node_defaults().
  706. *
  707. * @see webform_node_defaults()
  708. */
  709. function hook_webform_node_defaults_alter(array &$defaults) {
  710. $defaults['allow_draft'] = '1';
  711. }
  712. /**
  713. * Add additional fields to submission data downloads.
  714. *
  715. * @return array
  716. * Keys and titles for default submission information.
  717. *
  718. * @see hook_webform_results_download_submission_information_data()
  719. */
  720. function hook_webform_results_download_submission_information_info() {
  721. return array(
  722. 'field_key_1' => t('Field Title 1'),
  723. 'field_key_2' => t('Field Title 2'),
  724. );
  725. }
  726. /**
  727. * Return values for submission data download fields.
  728. *
  729. * @param $token
  730. * The name of the token being replaced.
  731. * @param $submission
  732. * The data for an individual submission from webform_get_submissions().
  733. * @param array $options
  734. * A list of options that define the output format. These are generally passed
  735. * through from the GUI interface.
  736. * @param $serial_start
  737. * The starting position for the Serial column in the output.
  738. * @param $row_count
  739. * The number of the row being generated.
  740. *
  741. * @return string
  742. * Value for requested submission information field.
  743. *
  744. * @see hook_webform_results_download_submission_information_info()
  745. */
  746. function hook_webform_results_download_submission_information_data($token, $submission, array $options, $serial_start, $row_count) {
  747. switch ($token) {
  748. case 'field_key_1':
  749. return 'Field Value 1';
  750. case 'field_key_2':
  751. return 'Field Value 2';
  752. }
  753. }
  754. /**
  755. * @}
  756. */
  757. /**
  758. * @defgroup webform_component Sample Webform Component
  759. * @{
  760. * In each of these examples, the word "component" should be replaced with the,
  761. * name of the component type (such as textfield or select). These are not
  762. * actual hooks, but instead samples of how Webform integrates with its own
  763. * built-in components.
  764. */
  765. /**
  766. * Specify the default properties of a component.
  767. *
  768. * @return array
  769. * An array defining the default structure of a component.
  770. */
  771. function _webform_defaults_component() {
  772. return array(
  773. 'name' => '',
  774. 'form_key' => NULL,
  775. 'required' => 0,
  776. 'pid' => 0,
  777. 'weight' => 0,
  778. 'extra' => array(
  779. 'options' => '',
  780. 'questions' => '',
  781. 'optrand' => 0,
  782. 'qrand' => 0,
  783. 'description' => '',
  784. 'description_above' => FALSE,
  785. 'private' => FALSE,
  786. 'analysis' => TRUE,
  787. ),
  788. );
  789. }
  790. /**
  791. * Generate the form for editing a component.
  792. *
  793. * Create a set of form elements to be displayed on the form for editing this
  794. * component. Use care naming the form items, as this correlates directly to the
  795. * database schema. The component "Name" and "Description" fields are added to
  796. * every component type and are not necessary to specify here (although they
  797. * may be overridden if desired).
  798. *
  799. * @param array $component
  800. * A Webform component array.
  801. * @param array $form
  802. * The form array.
  803. * @param array $form_state
  804. * The form state array.
  805. *
  806. * @return array
  807. * An array of form items to be displayed on the edit component page
  808. */
  809. function _webform_edit_component(array $component, array &$form, array &$form_state) {
  810. // Disabling the description if not wanted.
  811. $form['description']['#access'] = FALSE;
  812. // Most options are stored in the "extra" array, which stores any settings
  813. // unique to a particular component type.
  814. $form['extra']['options'] = array(
  815. '#type' => 'textarea',
  816. '#title' => t('Options'),
  817. '#default_value' => $component['extra']['options'],
  818. '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . ' ' . theme('webform_token_help'),
  819. '#cols' => 60,
  820. '#rows' => 5,
  821. '#weight' => -3,
  822. '#required' => TRUE,
  823. );
  824. return $form;
  825. }
  826. /**
  827. * Render a Webform component to be part of a form.
  828. *
  829. * @param $component
  830. * A Webform component array.
  831. * @param $value
  832. * If editing an existing submission or resuming a draft, this will contain
  833. * an array of values to be shown instead of the default in the component
  834. * configuration. This value will always be an array, keyed numerically for
  835. * each value saved in this field.
  836. * @param $filter
  837. * Whether or not to filter the contents of descriptions and values when
  838. * rendering the component. Values need to be unfiltered to be editable by
  839. * Form Builder.
  840. * @param $submission
  841. * The submission from which this component is being rendered. Usually not
  842. * needed. Used by _webform_render_date() to validate using the submission's
  843. * completion date.
  844. *
  845. * @return array
  846. * $form_item
  847. *
  848. * @see _webform_client_form_add_component()
  849. */
  850. function _webform_render_component($component, $value = NULL, $filter = TRUE, $submission = NULL) {
  851. $form_item = array(
  852. '#type' => 'textfield',
  853. '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
  854. '#required' => $component['required'],
  855. '#weight' => $component['weight'],
  856. '#description' => $filter ? webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
  857. '#default_value' => $filter ? webform_replace_tokens($component['value']) : $component['value'],
  858. '#theme_wrappers' => array('webform_element'),
  859. );
  860. if (isset($value)) {
  861. $form_item['#default_value'] = $value[0];
  862. }
  863. return $form_item;
  864. }
  865. /**
  866. * Allow modules to modify a webform component that will be rendered in a form.
  867. *
  868. * @param array $element
  869. * The display element as returned by _webform_render_component().
  870. * @param array $component
  871. * A Webform component array.
  872. *
  873. * @see _webform_render_component()
  874. */
  875. function hook_webform_component_render_alter(array &$element, array &$component) {
  876. if ($component['cid'] == 10) {
  877. $element['#title'] = 'My custom title';
  878. $element['#default_value'] = 42;
  879. }
  880. }
  881. /**
  882. * Display the result of a submission for a component.
  883. *
  884. * The output of this function will be displayed under the "Results" tab then
  885. * "Submissions". This should output the saved data in some reasonable manner.
  886. *
  887. * @param $component
  888. * A Webform component array.
  889. * @param $value
  890. * An array of information containing the submission result, directly
  891. * correlating to the webform_submitted_data database table schema.
  892. * @param $format
  893. * Either 'html' or 'text'. Defines the format that the content should be
  894. * returned as. Make sure that returned content is run through check_plain()
  895. * or other filtering functions when returning HTML.
  896. * @param $submission
  897. * The submission. Used to generate tokens.
  898. *
  899. * @return array
  900. * A renderable element containing at the very least these properties:
  901. * - #title
  902. * - #weight
  903. * - #component
  904. * - #format
  905. * - #value
  906. * Webform also uses #theme_wrappers to output the end result to the user,
  907. * which will properly format the label and content for use within an e-mail
  908. * (such as wrapping the text) or as HTML (ensuring consistent output).
  909. */
  910. function _webform_display_component($component, $value, $format = 'html', $submission = array()) {
  911. return array(
  912. '#title' => $component['name'],
  913. '#weight' => $component['weight'],
  914. '#theme' => 'webform_display_textfield',
  915. '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
  916. '#post_render' => array('webform_element_wrapper'),
  917. '#field_prefix' => $component['extra']['field_prefix'],
  918. '#field_suffix' => $component['extra']['field_suffix'],
  919. '#component' => $component,
  920. '#format' => $format,
  921. '#value' => isset($value[0]) ? $value[0] : '',
  922. );
  923. }
  924. /**
  925. * Allow modules to modify a "display only" webform component.
  926. *
  927. * @param array $element
  928. * The display element as returned by _webform_display_component().
  929. * @param array $component
  930. * A Webform component array.
  931. *
  932. * @see _webform_display_component()
  933. */
  934. function hook_webform_component_display_alter(array &$element, array &$component) {
  935. if ($component['cid'] == 10) {
  936. $element['#title'] = 'My custom title';
  937. $element['#default_value'] = 42;
  938. }
  939. }
  940. /**
  941. * Performs the conditional action set on an implemented component.
  942. *
  943. * Setting the form element allows form validation functions to see the value
  944. * that webform has set for the given component.
  945. *
  946. * @param array $component
  947. * The webform component array whose value is being set for the currently-
  948. * edited submission.
  949. * @param array $element
  950. * The form element currently being set.
  951. * @param array $form_state
  952. * The form's state.
  953. * @param string $value
  954. * The value to be set, as defined in the conditional action.
  955. */
  956. function _webform_action_set_component(array $component, array &$element, array &$form_state, $value) {
  957. $element['#value'] = $value;
  958. form_set_value($element, $value, $form_state);
  959. }
  960. /**
  961. * A hook for changing the input values before saving to the database.
  962. *
  963. * Webform expects a component to consist of a single field, or a single array
  964. * of fields. If you have a component that requires a deeper form tree
  965. * you must flatten the data into a single array using this callback
  966. * or by setting #parents on each field to avoid data loss and/or unexpected
  967. * behavior.
  968. *
  969. * Note that Webform will save the result of this function directly into the
  970. * database.
  971. *
  972. * @param $component
  973. * A Webform component array.
  974. * @param $value
  975. * The POST data associated with the user input.
  976. *
  977. * @return array
  978. * An array of values to be saved into the database. Note that this should be
  979. * a numerically keyed array.
  980. */
  981. function _webform_submit_component($component, $value) {
  982. // Clean up a phone number into 123-456-7890 format.
  983. if ($component['extra']['phone_number']) {
  984. $number = preg_replace('/[^0-9]/', '', $value[0]);
  985. if (strlen($number) == 7) {
  986. $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
  987. }
  988. else {
  989. $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
  990. }
  991. }
  992. $value[0] = $number;
  993. return $value;
  994. }
  995. /**
  996. * Delete operation for a component or submission.
  997. *
  998. * @param $component
  999. * A Webform component array.
  1000. * @param $value
  1001. * An array of information containing the submission result, directly
  1002. * correlating to the webform_submitted_data database schema.
  1003. */
  1004. function _webform_delete_component($component, $value) {
  1005. // Delete corresponding files when a submission is deleted.
  1006. if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
  1007. file_usage_delete($file, 'webform');
  1008. file_delete($file);
  1009. }
  1010. }
  1011. /**
  1012. * Module specific instance of hook_help().
  1013. *
  1014. * This allows each Webform component to add information into hook_help().
  1015. */
  1016. function _webform_help_component($section) {
  1017. switch ($section) {
  1018. case 'admin/config/content/webform#grid_description':
  1019. return t('Allows creation of grid questions, denoted by radio buttons.');
  1020. }
  1021. }
  1022. /**
  1023. * Module specific instance of hook_theme().
  1024. *
  1025. * This allows each Webform component to add information into hook_theme(). If
  1026. * you specify a file to include, you must define the path to the module that
  1027. * this file belongs to.
  1028. */
  1029. function _webform_theme_component() {
  1030. return array(
  1031. 'webform_grid' => array(
  1032. 'render element' => 'element',
  1033. 'file' => 'components/grid.inc',
  1034. 'path' => drupal_get_path('module', 'webform'),
  1035. ),
  1036. 'webform_display_grid' => array(
  1037. 'render element' => 'element',
  1038. 'file' => 'components/grid.inc',
  1039. 'path' => drupal_get_path('module', 'webform'),
  1040. ),
  1041. );
  1042. }
  1043. /**
  1044. * Calculate and returns statistics about results for this component.
  1045. *
  1046. * This takes into account all submissions to this webform. The output of this
  1047. * function will be displayed under the "Results" tab then "Analysis".
  1048. *
  1049. * @param $component
  1050. * An array of information describing the component, directly correlating to
  1051. * the webform_component database schema.
  1052. * @param $sids
  1053. * An optional array of submission IDs (sid). If supplied, the analysis will
  1054. * be limited to these sids.
  1055. * @param $single
  1056. * Boolean flag determining if the details about a single component are being
  1057. * shown. May be used to provided detailed information about a single
  1058. * component's analysis, such as showing "Other" options within a select list.
  1059. * @param $join
  1060. * An optional SelectQuery object to be used to join with the submissions
  1061. * table to restrict the submissions being analyzed.
  1062. *
  1063. * @return array
  1064. * An array containing one or more of the following keys:
  1065. * - table_rows: If this component has numeric data that can be represented in
  1066. * a grid, return the values here. This array assumes a 2-dimensional
  1067. * structure, with the first value being a label and subsequent values
  1068. * containing a decimal or integer.
  1069. * - table_header: If this component has more than a single set of values,
  1070. * include a table header so each column can be labeled.
  1071. * - other_data: If your component has non-numeric data to include, such as
  1072. * a description or link, include that in the other_data array. Each item
  1073. * may be a string or an array of values that matches the number of columns
  1074. * in the table_header property.
  1075. * At the very least, either table_rows or other_data should be provided.
  1076. * Note that if you want your component's analysis to be available by default
  1077. * without the user specifically enabling it, you must set
  1078. * $component['extra']['analysis'] = TRUE in your
  1079. * _webform_defaults_component() callback.
  1080. *
  1081. * @see _webform_defaults_component()
  1082. */
  1083. function _webform_analysis_component($component, $sids = array(), $single = FALSE, $join = NULL) {
  1084. // Generate the list of options and questions.
  1085. $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
  1086. $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
  1087. // Generate a lookup table of results.
  1088. $query = db_select('webform_submitted_data', 'wsd')
  1089. ->fields('wsd', array('no', 'data'))
  1090. ->condition('nid', $component['nid'])
  1091. ->condition('cid', $component['cid'])
  1092. ->condition('data', '', '<>')
  1093. ->groupBy('no')
  1094. ->groupBy('data');
  1095. $query->addExpression('COUNT(sid)', 'datacount');
  1096. if (count($sids)) {
  1097. $query->condition('sid', $sids, 'IN');
  1098. }
  1099. if ($join) {
  1100. $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
  1101. }
  1102. $result = $query->execute();
  1103. $counts = array();
  1104. foreach ($result as $data) {
  1105. $counts[$data->no][$data->data] = $data->datacount;
  1106. }
  1107. // Create an entire table to be put into the returned row.
  1108. $rows = array();
  1109. $header = array('');
  1110. // Add options as a header row.
  1111. foreach ($options as $option) {
  1112. $header[] = $option;
  1113. }
  1114. // Add questions as each row.
  1115. foreach ($questions as $qkey => $question) {
  1116. $row = array($question);
  1117. foreach ($options as $okey => $option) {
  1118. $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
  1119. }
  1120. $rows[] = $row;
  1121. }
  1122. $other = array();
  1123. $other[] = l(t('More information'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']);
  1124. return array(
  1125. 'table_header' => $header,
  1126. 'table_rows' => $rows,
  1127. 'other_data' => $other,
  1128. );
  1129. }
  1130. /**
  1131. * Return the result of a component value for display in a table.
  1132. *
  1133. * The output of this function will be displayed under the "Results" tab then
  1134. * "Table".
  1135. *
  1136. * @param $component
  1137. * A Webform component array.
  1138. * @param $value
  1139. * An array of information containing the submission result, directly
  1140. * correlating to the webform_submitted_data database schema.
  1141. *
  1142. * @return string
  1143. * Textual output formatted for human reading.
  1144. */
  1145. function _webform_table_component($component, $value) {
  1146. $questions = array_values(_webform_component_options($component['extra']['questions']));
  1147. $output = '';
  1148. // Set the value as a single string.
  1149. if (is_array($value)) {
  1150. foreach ($value as $item => $value) {
  1151. if ($value !== '') {
  1152. $output .= $questions[$item] . ': ' . check_plain($value) . '<br />';
  1153. }
  1154. }
  1155. }
  1156. else {
  1157. $output = check_plain(!isset($value['0']) ? '' : $value['0']);
  1158. }
  1159. return $output;
  1160. }
  1161. /**
  1162. * Return the header for this component to be displayed in a CSV file.
  1163. *
  1164. * The output of this function will be displayed under the "Results" tab then
  1165. * "Download".
  1166. *
  1167. * @param $component
  1168. * A Webform component array.
  1169. * @param $export_options
  1170. * An array of options that may configure export of this field.
  1171. *
  1172. * @return array
  1173. * An array of data to be displayed in the first three rows of a CSV file, not
  1174. * including either prefixed or trailing commas.
  1175. */
  1176. function _webform_csv_headers_component($component, $export_options) {
  1177. $header = array();
  1178. $header[0] = array('');
  1179. $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name']);
  1180. $items = _webform_component_options($component['extra']['questions']);
  1181. $count = 0;
  1182. foreach ($items as $key => $item) {
  1183. // Empty column per sub-field in main header.
  1184. if ($count != 0) {
  1185. $header[0][] = '';
  1186. $header[1][] = '';
  1187. }
  1188. // The value for this option.
  1189. $header[2][] = $item;
  1190. $count++;
  1191. }
  1192. return $header;
  1193. }
  1194. /**
  1195. * Format the submitted data of a component for CSV downloading.
  1196. *
  1197. * The output of this function will be displayed under the "Results" tab then
  1198. * "Download".
  1199. *
  1200. * @param $component
  1201. * A Webform component array.
  1202. * @param $export_options
  1203. * An array of options that may configure export of this field.
  1204. * @param $value
  1205. * An array of information containing the submission result, directly
  1206. * correlating to the webform_submitted_data database schema.
  1207. *
  1208. * @return array
  1209. * An array of items to be added to the CSV file. Each value within the array
  1210. * will be another column within the file. This function is called once for
  1211. * every row of data.
  1212. */
  1213. function _webform_csv_data_component($component, $export_options, $value) {
  1214. $questions = array_keys(_webform_select_options($component['extra']['questions']));
  1215. $return = array();
  1216. foreach ($questions as $key => $question) {
  1217. $return[] = isset($value[$key]) ? $value[$key] : '';
  1218. }
  1219. return $return;
  1220. }
  1221. /**
  1222. * Fix the view field(s) that are automatically generated for number components.
  1223. *
  1224. * Provides each component the opportunity to adjust how this component is
  1225. * displayed in a view as a field in a view table. For example, a component may
  1226. * modify how it responds to click-sorting. Or it may add additional fields,
  1227. * such as a grid component having a column for each question.
  1228. *
  1229. * @param array $component
  1230. * A Webform component array.
  1231. * @param array $fields
  1232. * An array of field-definition arrays. Will be passed one field definition,
  1233. * which may be modified. Additional fields may be added to the array.
  1234. *
  1235. * @return array
  1236. * The modified $fields array.
  1237. */
  1238. function _webform_view_field_component(array $component, array $fields) {
  1239. foreach ($fields as &$field) {
  1240. $field['webform_datatype'] = 'number';
  1241. }
  1242. return $fields;
  1243. }
  1244. /**
  1245. * Modify the how a view was expanded to show all the components.
  1246. *
  1247. * This alter function is only called when the view is actually modified. It
  1248. * provides modules an opportunity to alter the changes that webform made to
  1249. * the view.
  1250. *
  1251. * This hook is called from webform_views_pre_view. If another module also
  1252. * changes views by implementing this same views hook, the relative order of
  1253. * execution of the two implementations will depend upon the module weights of
  1254. * the two modules. Using hook_webform_view_alter instead guarantees an
  1255. * opportunity to modify the view AFTER webform.
  1256. *
  1257. * @param object $view
  1258. * The view object.
  1259. * @param string $display_id
  1260. * The display_id that was expanded by webform.
  1261. * @param array $args
  1262. * The arguments that were passed to the view.
  1263. */
  1264. function hook_webform_view_alter($view, $display_id, array $args) {
  1265. // Don't show component with cid == 4.
  1266. $fields = $view->get_items('field', $display_id);
  1267. foreach ($fields as $id => $field) {
  1268. if (isset($field['webform_cid']) && $field['webform_cid'] == 4) {
  1269. unset($fields[$id]);
  1270. }
  1271. }
  1272. $view->display[$display_id]->handler->set_option('fields', $fields);
  1273. }
  1274. /**
  1275. * Modify the list of mail systems that are capable of sending HTML email.
  1276. *
  1277. * @param array &$systems
  1278. * An array of mail system class names.
  1279. */
  1280. function hook_webform_html_capable_mail_systems_alter(array &$systems) {
  1281. if (module_exists('my_module')) {
  1282. $systems[] = 'MyModuleMailSystem';
  1283. }
  1284. }
  1285. /**
  1286. * Define a list of webform exporters.
  1287. *
  1288. * @return array
  1289. * A list of the available exporters provided by the module.
  1290. *
  1291. * @see webform_webform_exporters()
  1292. */
  1293. function hook_webform_exporters() {
  1294. $exporters = array(
  1295. 'webform_exporter_custom' => array(
  1296. 'title' => t('Webform exporter name'),
  1297. 'description' => t('The description for this exporter.'),
  1298. 'handler' => 'webform_exporter_custom',
  1299. 'file' => drupal_get_path('module', 'yourmodule') . '/includes/webform_exporter_custom.inc',
  1300. 'weight' => 10,
  1301. ),
  1302. );
  1303. return $exporters;
  1304. }
  1305. /**
  1306. * Modify the list of webform exporters definitions.
  1307. *
  1308. * @param array &$exporters
  1309. * A list of all available webform exporters.
  1310. */
  1311. function hook_webform_exporters_alter(array &$exporters) {
  1312. $exporters['excel']['handler'] = 'customized_excel_exporter';
  1313. $exporters['excel']['file'] = drupal_get_path('module', 'yourmodule') . '/includes/customized_excel_exporter.inc';
  1314. }
  1315. /**
  1316. * Declare conditional types and their operators.
  1317. *
  1318. * Each conditional type defined here may then be referenced in
  1319. * hook_webform_component_info(). For each type this hook also declares a set of
  1320. * operators that may be applied to a component of this conditional type in
  1321. * conditionals.
  1322. *
  1323. * @return array
  1324. * A 2-dimensional array of operator configurations. The configurations are
  1325. * keyed first by their conditional type then by operator key. Each operator
  1326. * declaration is an array with the following keys:
  1327. * - label: Translated label for this operator that is shown in the UI.
  1328. * - comparison callback: A callback for server-side evaluation.
  1329. * - js comparison callback: A JavaScript callback for client-side evaluation.
  1330. * The callback will be looked for in the Drupal.webform object.
  1331. * - form callback (optional): A form callback that allows configuring
  1332. * additional parameters for this operator. Default:
  1333. * 'webform_conditional_operator_text'.
  1334. *
  1335. * @see hook_webform_component_info()
  1336. * @see callback_webform_conditional_comparision_operator()
  1337. * @see callback_webform_conditional_rule_value_form()
  1338. */
  1339. function hook_webform_conditional_operator_info() {
  1340. $operators = array();
  1341. $operators['string']['not_equal'] = array(
  1342. 'label' => t('is not'),
  1343. 'comparison callback' => 'webform_conditional_operator_string_not_equal',
  1344. 'js comparison callback' => 'conditionalOperatorStringNotEqual',
  1345. );
  1346. return $operators;
  1347. }
  1348. /**
  1349. * Alter the list of operators and conditional types.
  1350. *
  1351. * @param array $operators
  1352. * A data structure as described in hook_webform_conditional_operator_info().
  1353. *
  1354. * @see hook_webform_conditional_operator_info()
  1355. */
  1356. function hook_webform_conditional_operators_alter(array &$operators) {
  1357. $operators['string']['not_equal']['label'] = t('not equal');
  1358. }
  1359. /**
  1360. * Evaluate the operator for a given set of values.
  1361. *
  1362. * This function will be called two times with potentially different kinds of
  1363. * values: Once in _webform_client_form_validate() before any of the validate
  1364. * handlers or the _webform_submit_COMPONENT() callback is called, and once in
  1365. * webform_client_form_pages() after those handlers have been called.
  1366. *
  1367. * @param array $input_values
  1368. * The values received from the browser.
  1369. * @param mixed $rule_value
  1370. * The value as configured in the form callback.
  1371. * @param array $component
  1372. * The component for which we are evaluating the operator.
  1373. *
  1374. * @return bool
  1375. * The operation result.
  1376. */
  1377. function callback_webfom_conditional_comparison_operator(array $input_values, $rule_value, array $component) {
  1378. foreach ($input_values as $value) {
  1379. if (strcasecmp($value, $rule_value)) {
  1380. return TRUE;
  1381. }
  1382. }
  1383. return FALSE;
  1384. }
  1385. /**
  1386. * Define a form element that configures your operator.
  1387. *
  1388. * @param object $node
  1389. * The node for which the conditionals are being configured.
  1390. *
  1391. * @return string|string[]
  1392. * Either a single rendered form element or a rendered form element per
  1393. * component (keyed by cid). Make sure that none of the rendered strings
  1394. * contains any HTML IDs as the form element will be rendered multiple times.
  1395. * The JavaScript will take care of adding the appropriate name attributes.
  1396. *
  1397. * @see _webform_conditional_expand_value_forms()
  1398. */
  1399. function callback_webform_conditional_rule_value_form($node) {
  1400. $forms = [];
  1401. foreach ($node->webform['components'] as $cid => $component) {
  1402. if (webform_component_property($component['type'], 'conditional_type') == 'newsletter') {
  1403. $element = [
  1404. '#type' => 'select',
  1405. '#options' => [
  1406. 'yes' => t('Opt-in'),
  1407. 'no' => t('No opt-in'),
  1408. ],
  1409. ];
  1410. $forms[$cid] = drupal_render($element);
  1411. }
  1412. }
  1413. return $forms;
  1414. }
  1415. /**
  1416. * @}
  1417. */