webform.api.php 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  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. * the 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. * Alter the query that will produce the list of submission IDs to be
  756. * downloaded.
  757. *
  758. * @param object $query
  759. * The query object that is being built up to provide the list of submission
  760. * IDs.
  761. *
  762. * @see webform_download_sids_query()
  763. */
  764. function hook_webform_download_sids_query_alter(&$query) {
  765. global $user;
  766. // check if component value matches a node ID and author of that node.
  767. $query->join('webform_submitted_data', 'wsd', 'ws.sid = wsd.sid');
  768. $query->condition('wsd.cid', 2);
  769. $query->join('node', 'n', 'wsd.data = n.nid');
  770. $query->condition('n.uid', $user->uid);
  771. }
  772. /**
  773. * @}
  774. */
  775. /**
  776. * @defgroup webform_component Sample Webform Component
  777. * @{
  778. * In each of these examples, the word "component" should be replaced with the,
  779. * name of the component type (such as textfield or select). These are not
  780. * actual hooks, but instead samples of how Webform integrates with its own
  781. * built-in components.
  782. */
  783. /**
  784. * Specify the default properties of a component.
  785. *
  786. * @return array
  787. * An array defining the default structure of a component.
  788. */
  789. function _webform_defaults_component() {
  790. return array(
  791. 'name' => '',
  792. 'form_key' => NULL,
  793. 'required' => 0,
  794. 'pid' => 0,
  795. 'weight' => 0,
  796. 'extra' => array(
  797. 'options' => '',
  798. 'questions' => '',
  799. 'optrand' => 0,
  800. 'qrand' => 0,
  801. 'description' => '',
  802. 'description_above' => FALSE,
  803. 'private' => FALSE,
  804. 'analysis' => TRUE,
  805. ),
  806. );
  807. }
  808. /**
  809. * Generate the form for editing a component.
  810. *
  811. * Create a set of form elements to be displayed on the form for editing this
  812. * component. Use care naming the form items, as this correlates directly to the
  813. * database schema. The component "Name" and "Description" fields are added to
  814. * every component type and are not necessary to specify here (although they
  815. * may be overridden if desired).
  816. *
  817. * @param array $component
  818. * A Webform component array.
  819. * @param array $form
  820. * The form array.
  821. * @param array $form_state
  822. * The form state array.
  823. *
  824. * @return array
  825. * Return $form with whatever changes are desired.
  826. */
  827. function _webform_edit_component(array $component, array $form, array $form_state) {
  828. // Disabling the description if not wanted.
  829. $form['description']['#access'] = FALSE;
  830. // Most options are stored in the "extra" array, which stores any settings
  831. // unique to a particular component type.
  832. $form['extra']['options'] = array(
  833. '#type' => 'textarea',
  834. '#title' => t('Options'),
  835. '#default_value' => $component['extra']['options'],
  836. '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . ' ' . theme('webform_token_help'),
  837. '#cols' => 60,
  838. '#rows' => 5,
  839. '#weight' => -3,
  840. '#required' => TRUE,
  841. );
  842. return $form;
  843. }
  844. /**
  845. * Render a Webform component to be part of a form.
  846. *
  847. * @param $component
  848. * A Webform component array.
  849. * @param $value
  850. * If editing an existing submission or resuming a draft, this will contain
  851. * an array of values to be shown instead of the default in the component
  852. * configuration. This value will always be an array, keyed numerically for
  853. * each value saved in this field.
  854. * @param $filter
  855. * Whether or not to filter the contents of descriptions and values when
  856. * rendering the component. Values need to be unfiltered to be editable by
  857. * Form Builder.
  858. * @param $submission
  859. * The submission from which this component is being rendered. Usually not
  860. * needed. Used by _webform_render_date() to validate using the submission's
  861. * completion date.
  862. *
  863. * @return array
  864. * $form_item
  865. *
  866. * @see _webform_client_form_add_component()
  867. */
  868. function _webform_render_component($component, $value = NULL, $filter = TRUE, $submission = NULL) {
  869. $form_item = array(
  870. '#type' => 'textfield',
  871. '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
  872. '#required' => $component['required'],
  873. '#weight' => $component['weight'],
  874. '#description' => $filter ? webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
  875. '#default_value' => $filter ? webform_replace_tokens($component['value']) : $component['value'],
  876. '#theme_wrappers' => array('webform_element'),
  877. );
  878. if (isset($value)) {
  879. $form_item['#default_value'] = $value[0];
  880. }
  881. return $form_item;
  882. }
  883. /**
  884. * Allow modules to modify a webform component that will be rendered in a form.
  885. *
  886. * @param array $element
  887. * The display element as returned by _webform_render_component().
  888. * @param array $component
  889. * A Webform component array.
  890. *
  891. * @see _webform_render_component()
  892. */
  893. function hook_webform_component_render_alter(array &$element, array &$component) {
  894. if ($component['cid'] == 10) {
  895. $element['#title'] = 'My custom title';
  896. $element['#default_value'] = 42;
  897. }
  898. }
  899. /**
  900. * Display the result of a submission for a component.
  901. *
  902. * The output of this function will be displayed under the "Results" tab then
  903. * "Submissions". This should output the saved data in some reasonable manner.
  904. *
  905. * @param $component
  906. * A Webform component array.
  907. * @param $value
  908. * An array of information containing the submission result, directly
  909. * correlating to the webform_submitted_data database table schema.
  910. * @param $format
  911. * Either 'html' or 'text'. Defines the format that the content should be
  912. * returned as. Make sure that returned content is run through check_plain()
  913. * or other filtering functions when returning HTML.
  914. * @param $submission
  915. * The submission. Used to generate tokens.
  916. *
  917. * @return array
  918. * A renderable element containing at the very least these properties:
  919. * - #title
  920. * - #weight
  921. * - #component
  922. * - #format
  923. * - #value
  924. * Webform also uses #theme_wrappers to output the end result to the user,
  925. * which will properly format the label and content for use within an e-mail
  926. * (such as wrapping the text) or as HTML (ensuring consistent output).
  927. */
  928. function _webform_display_component($component, $value, $format = 'html', $submission = array()) {
  929. return array(
  930. '#title' => $component['name'],
  931. '#weight' => $component['weight'],
  932. '#theme' => 'webform_display_textfield',
  933. '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
  934. '#post_render' => array('webform_element_wrapper'),
  935. '#field_prefix' => $component['extra']['field_prefix'],
  936. '#field_suffix' => $component['extra']['field_suffix'],
  937. '#component' => $component,
  938. '#format' => $format,
  939. '#value' => isset($value[0]) ? $value[0] : '',
  940. );
  941. }
  942. /**
  943. * Allow modules to modify a "display only" webform component.
  944. *
  945. * @param array $element
  946. * The display element as returned by _webform_display_component().
  947. * @param array $component
  948. * A Webform component array.
  949. *
  950. * @see _webform_display_component()
  951. */
  952. function hook_webform_component_display_alter(array &$element, array &$component) {
  953. if ($component['cid'] == 10) {
  954. $element['#title'] = 'My custom title';
  955. $element['#default_value'] = 42;
  956. }
  957. }
  958. /**
  959. * Performs the conditional action set on an implemented component.
  960. *
  961. * Setting the form element allows form validation functions to see the value
  962. * that webform has set for the given component.
  963. *
  964. * @param array $component
  965. * The webform component array whose value is being set for the currently-
  966. * edited submission.
  967. * @param array $element
  968. * The form element currently being set.
  969. * @param array $form_state
  970. * The form's state.
  971. * @param string $value
  972. * The value to be set, as defined in the conditional action.
  973. */
  974. function _webform_action_set_component(array $component, array &$element, array &$form_state, $value) {
  975. $element['#value'] = $value;
  976. form_set_value($element, $value, $form_state);
  977. }
  978. /**
  979. * A hook for changing the input values before saving to the database.
  980. *
  981. * Webform expects a component to consist of a single field, or a single array
  982. * of fields. If you have a component that requires a deeper form tree
  983. * you must flatten the data into a single array using this callback
  984. * or by setting #parents on each field to avoid data loss and/or unexpected
  985. * behavior.
  986. *
  987. * Note that Webform will save the result of this function directly into the
  988. * database.
  989. *
  990. * @param $component
  991. * A Webform component array.
  992. * @param $value
  993. * The POST data associated with the user input.
  994. *
  995. * @return array
  996. * An array of values to be saved into the database. Note that this should be
  997. * a numerically keyed array.
  998. */
  999. function _webform_submit_component($component, $value) {
  1000. // Clean up a phone number into 123-456-7890 format.
  1001. if ($component['extra']['phone_number']) {
  1002. $number = preg_replace('/[^0-9]/', '', $value[0]);
  1003. if (strlen($number) == 7) {
  1004. $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
  1005. }
  1006. else {
  1007. $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
  1008. }
  1009. }
  1010. $value[0] = $number;
  1011. return $value;
  1012. }
  1013. /**
  1014. * Delete operation for a component or submission.
  1015. *
  1016. * @param $component
  1017. * A Webform component array.
  1018. * @param $value
  1019. * An array of information containing the submission result, directly
  1020. * correlating to the webform_submitted_data database schema.
  1021. */
  1022. function _webform_delete_component($component, $value) {
  1023. // Delete corresponding files when a submission is deleted.
  1024. if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
  1025. file_usage_delete($file, 'webform');
  1026. file_delete($file);
  1027. }
  1028. }
  1029. /**
  1030. * Module specific instance of hook_help().
  1031. *
  1032. * This allows each Webform component to add information into hook_help().
  1033. */
  1034. function _webform_help_component($section) {
  1035. switch ($section) {
  1036. case 'admin/config/content/webform#grid_description':
  1037. return t('Allows creation of grid questions, denoted by radio buttons.');
  1038. }
  1039. }
  1040. /**
  1041. * Module specific instance of hook_theme().
  1042. *
  1043. * This allows each Webform component to add information into hook_theme(). If
  1044. * you specify a file to include, you must define the path to the module that
  1045. * this file belongs to.
  1046. */
  1047. function _webform_theme_component() {
  1048. return array(
  1049. 'webform_grid' => array(
  1050. 'render element' => 'element',
  1051. 'file' => 'components/grid.inc',
  1052. 'path' => drupal_get_path('module', 'webform'),
  1053. ),
  1054. 'webform_display_grid' => array(
  1055. 'render element' => 'element',
  1056. 'file' => 'components/grid.inc',
  1057. 'path' => drupal_get_path('module', 'webform'),
  1058. ),
  1059. );
  1060. }
  1061. /**
  1062. * Calculate and returns statistics about results for this component.
  1063. *
  1064. * This takes into account all submissions to this webform. The output of this
  1065. * function will be displayed under the "Results" tab then "Analysis".
  1066. *
  1067. * @param $component
  1068. * An array of information describing the component, directly correlating to
  1069. * the webform_component database schema.
  1070. * @param $sids
  1071. * An optional array of submission IDs (sid). If supplied, the analysis will
  1072. * be limited to these sids.
  1073. * @param $single
  1074. * Boolean flag determining if the details about a single component are being
  1075. * shown. May be used to provided detailed information about a single
  1076. * component's analysis, such as showing "Other" options within a select list.
  1077. * @param $join
  1078. * An optional SelectQuery object to be used to join with the submissions
  1079. * table to restrict the submissions being analyzed.
  1080. *
  1081. * @return array
  1082. * An array containing one or more of the following keys:
  1083. * - table_rows: If this component has numeric data that can be represented in
  1084. * a grid, return the values here. This array assumes a 2-dimensional
  1085. * structure, with the first value being a label and subsequent values
  1086. * containing a decimal or integer.
  1087. * - table_header: If this component has more than a single set of values,
  1088. * include a table header so each column can be labeled.
  1089. * - other_data: If your component has non-numeric data to include, such as
  1090. * a description or link, include that in the other_data array. Each item
  1091. * may be a string or an array of values that matches the number of columns
  1092. * in the table_header property.
  1093. * At the very least, either table_rows or other_data should be provided.
  1094. * Note that if you want your component's analysis to be available by default
  1095. * without the user specifically enabling it, you must set
  1096. * $component['extra']['analysis'] = TRUE in your
  1097. * _webform_defaults_component() callback.
  1098. *
  1099. * @see _webform_defaults_component()
  1100. */
  1101. function _webform_analysis_component($component, $sids = array(), $single = FALSE, $join = NULL) {
  1102. // Generate the list of options and questions.
  1103. $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
  1104. $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
  1105. // Generate a lookup table of results.
  1106. $query = db_select('webform_submitted_data', 'wsd')
  1107. ->fields('wsd', array('no', 'data'))
  1108. ->condition('nid', $component['nid'])
  1109. ->condition('cid', $component['cid'])
  1110. ->condition('data', '', '<>')
  1111. ->groupBy('no')
  1112. ->groupBy('data');
  1113. $query->addExpression('COUNT(sid)', 'datacount');
  1114. if (count($sids)) {
  1115. $query->condition('sid', $sids, 'IN');
  1116. }
  1117. if ($join) {
  1118. $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
  1119. }
  1120. $result = $query->execute();
  1121. $counts = array();
  1122. foreach ($result as $data) {
  1123. $counts[$data->no][$data->data] = $data->datacount;
  1124. }
  1125. // Create an entire table to be put into the returned row.
  1126. $rows = array();
  1127. $header = array('');
  1128. // Add options as a header row.
  1129. foreach ($options as $option) {
  1130. $header[] = $option;
  1131. }
  1132. // Add questions as each row.
  1133. foreach ($questions as $qkey => $question) {
  1134. $row = array($question);
  1135. foreach ($options as $okey => $option) {
  1136. $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
  1137. }
  1138. $rows[] = $row;
  1139. }
  1140. $other = array();
  1141. $other[] = l(t('More information'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']);
  1142. return array(
  1143. 'table_header' => $header,
  1144. 'table_rows' => $rows,
  1145. 'other_data' => $other,
  1146. );
  1147. }
  1148. /**
  1149. * Return the result of a component value for display in a table.
  1150. *
  1151. * The output of this function will be displayed under the "Results" tab then
  1152. * "Table".
  1153. *
  1154. * @param $component
  1155. * A Webform component array.
  1156. * @param $value
  1157. * An array of information containing the submission result, directly
  1158. * correlating to the webform_submitted_data database schema.
  1159. *
  1160. * @return string
  1161. * Textual output formatted for human reading.
  1162. */
  1163. function _webform_table_component($component, $value) {
  1164. $questions = array_values(_webform_component_options($component['extra']['questions']));
  1165. $output = '';
  1166. // Set the value as a single string.
  1167. if (is_array($value)) {
  1168. foreach ($value as $item => $value) {
  1169. if ($value !== '') {
  1170. $output .= $questions[$item] . ': ' . check_plain($value) . '<br />';
  1171. }
  1172. }
  1173. }
  1174. else {
  1175. $output = check_plain(!isset($value['0']) ? '' : $value['0']);
  1176. }
  1177. return $output;
  1178. }
  1179. /**
  1180. * Return the header for this component to be displayed in a CSV file.
  1181. *
  1182. * The output of this function will be displayed under the "Results" tab then
  1183. * "Download".
  1184. *
  1185. * @param $component
  1186. * A Webform component array.
  1187. * @param $export_options
  1188. * An array of options that may configure export of this field.
  1189. *
  1190. * @return array
  1191. * An array of data to be displayed in the first three rows of a CSV file, not
  1192. * including either prefixed or trailing commas.
  1193. */
  1194. function _webform_csv_headers_component($component, $export_options) {
  1195. $header = array();
  1196. $header[0] = array('');
  1197. $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name']);
  1198. $items = _webform_component_options($component['extra']['questions']);
  1199. $count = 0;
  1200. foreach ($items as $key => $item) {
  1201. // Empty column per sub-field in main header.
  1202. if ($count != 0) {
  1203. $header[0][] = '';
  1204. $header[1][] = '';
  1205. }
  1206. // The value for this option.
  1207. $header[2][] = $item;
  1208. $count++;
  1209. }
  1210. return $header;
  1211. }
  1212. /**
  1213. * Format the submitted data of a component for CSV downloading.
  1214. *
  1215. * The output of this function will be displayed under the "Results" tab then
  1216. * "Download".
  1217. *
  1218. * @param $component
  1219. * A Webform component array.
  1220. * @param $export_options
  1221. * An array of options that may configure export of this field.
  1222. * @param $value
  1223. * An array of information containing the submission result, directly
  1224. * correlating to the webform_submitted_data database schema.
  1225. *
  1226. * @return array
  1227. * An array of items to be added to the CSV file. Each value within the array
  1228. * will be another column within the file. This function is called once for
  1229. * every row of data.
  1230. */
  1231. function _webform_csv_data_component($component, $export_options, $value) {
  1232. $questions = array_keys(_webform_select_options($component['extra']['questions']));
  1233. $return = array();
  1234. foreach ($questions as $key => $question) {
  1235. $return[] = isset($value[$key]) ? $value[$key] : '';
  1236. }
  1237. return $return;
  1238. }
  1239. /**
  1240. * Fix the view field(s) that are automatically generated for number components.
  1241. *
  1242. * Provides each component the opportunity to adjust how this component is
  1243. * displayed in a view as a field in a view table. For example, a component may
  1244. * modify how it responds to click-sorting. Or it may add additional fields,
  1245. * such as a grid component having a column for each question.
  1246. *
  1247. * @param array $component
  1248. * A Webform component array.
  1249. * @param array $fields
  1250. * An array of field-definition arrays. Will be passed one field definition,
  1251. * which may be modified. Additional fields may be added to the array.
  1252. *
  1253. * @return array
  1254. * The modified $fields array.
  1255. */
  1256. function _webform_view_field_component(array $component, array $fields) {
  1257. foreach ($fields as &$field) {
  1258. $field['webform_datatype'] = 'number';
  1259. }
  1260. return $fields;
  1261. }
  1262. /**
  1263. * Modify the how a view was expanded to show all the components.
  1264. *
  1265. * This alter function is only called when the view is actually modified. It
  1266. * provides modules an opportunity to alter the changes that webform made to
  1267. * the view.
  1268. *
  1269. * This hook is called from webform_views_pre_view. If another module also
  1270. * changes views by implementing this same views hook, the relative order of
  1271. * execution of the two implementations will depend upon the module weights of
  1272. * the two modules. Using hook_webform_view_alter instead guarantees an
  1273. * opportunity to modify the view AFTER webform.
  1274. *
  1275. * @param object $view
  1276. * The view object.
  1277. * @param string $display_id
  1278. * The display_id that was expanded by webform.
  1279. * @param array $args
  1280. * The arguments that were passed to the view.
  1281. */
  1282. function hook_webform_view_alter($view, $display_id, array $args) {
  1283. // Don't show component with cid == 4.
  1284. $fields = $view->get_items('field', $display_id);
  1285. foreach ($fields as $id => $field) {
  1286. if (isset($field['webform_cid']) && $field['webform_cid'] == 4) {
  1287. unset($fields[$id]);
  1288. }
  1289. }
  1290. $view->display[$display_id]->handler->set_option('fields', $fields);
  1291. }
  1292. /**
  1293. * Modify the list of mail systems that are capable of sending HTML email.
  1294. *
  1295. * @param array &$systems
  1296. * An array of mail system class names.
  1297. */
  1298. function hook_webform_html_capable_mail_systems_alter(array &$systems) {
  1299. if (module_exists('my_module')) {
  1300. $systems[] = 'MyModuleMailSystem';
  1301. }
  1302. }
  1303. /**
  1304. * Define a list of webform exporters.
  1305. *
  1306. * @return array
  1307. * A list of the available exporters provided by the module.
  1308. *
  1309. * @see webform_webform_exporters()
  1310. */
  1311. function hook_webform_exporters() {
  1312. $exporters = array(
  1313. 'webform_exporter_custom' => array(
  1314. 'title' => t('Webform exporter name'),
  1315. 'description' => t('The description for this exporter.'),
  1316. 'handler' => 'webform_exporter_custom',
  1317. 'file' => drupal_get_path('module', 'yourmodule') . '/includes/webform_exporter_custom.inc',
  1318. 'weight' => 10,
  1319. ),
  1320. );
  1321. return $exporters;
  1322. }
  1323. /**
  1324. * Modify the list of webform exporters definitions.
  1325. *
  1326. * @param array &$exporters
  1327. * A list of all available webform exporters.
  1328. */
  1329. function hook_webform_exporters_alter(array &$exporters) {
  1330. $exporters['excel']['handler'] = 'customized_excel_exporter';
  1331. $exporters['excel']['file'] = drupal_get_path('module', 'yourmodule') . '/includes/customized_excel_exporter.inc';
  1332. }
  1333. /**
  1334. * Declare conditional types and their operators.
  1335. *
  1336. * Each conditional type defined here may then be referenced in
  1337. * hook_webform_component_info(). For each type this hook also declares a set of
  1338. * operators that may be applied to a component of this conditional type in
  1339. * conditionals.
  1340. *
  1341. * @return array
  1342. * A 2-dimensional array of operator configurations. The configurations are
  1343. * keyed first by their conditional type then by operator key. Each operator
  1344. * declaration is an array with the following keys:
  1345. * - label: Translated label for this operator that is shown in the UI.
  1346. * - comparison callback: A callback for server-side evaluation.
  1347. * - js comparison callback: A JavaScript callback for client-side evaluation.
  1348. * The callback will be looked for in the Drupal.webform object.
  1349. * - form callback (optional): A form callback that allows configuring
  1350. * additional parameters for this operator. Default:
  1351. * 'webform_conditional_operator_text'.
  1352. *
  1353. * @see hook_webform_component_info()
  1354. * @see callback_webform_conditional_comparision_operator()
  1355. * @see callback_webform_conditional_rule_value_form()
  1356. */
  1357. function hook_webform_conditional_operator_info() {
  1358. $operators = array();
  1359. $operators['string']['not_equal'] = array(
  1360. 'label' => t('is not'),
  1361. 'comparison callback' => 'webform_conditional_operator_string_not_equal',
  1362. 'js comparison callback' => 'conditionalOperatorStringNotEqual',
  1363. );
  1364. return $operators;
  1365. }
  1366. /**
  1367. * Alter the list of operators and conditional types.
  1368. *
  1369. * @param array $operators
  1370. * A data structure as described in hook_webform_conditional_operator_info().
  1371. *
  1372. * @see hook_webform_conditional_operator_info()
  1373. */
  1374. function hook_webform_conditional_operators_alter(array &$operators) {
  1375. $operators['string']['not_equal']['label'] = t('not equal');
  1376. }
  1377. /**
  1378. * Evaluate the operator for a given set of values.
  1379. *
  1380. * This function will be called two times with potentially different kinds of
  1381. * values: Once in _webform_client_form_validate() before any of the validate
  1382. * handlers or the _webform_submit_COMPONENT() callback is called, and once in
  1383. * webform_client_form_pages() after those handlers have been called.
  1384. *
  1385. * @param array $input_values
  1386. * The values received from the browser.
  1387. * @param mixed $rule_value
  1388. * The value as configured in the form callback.
  1389. * @param array $component
  1390. * The component for which we are evaluating the operator.
  1391. *
  1392. * @return bool
  1393. * The operation result.
  1394. */
  1395. function callback_webfom_conditional_comparison_operator(array $input_values, $rule_value, array $component) {
  1396. foreach ($input_values as $value) {
  1397. if (strcasecmp($value, $rule_value)) {
  1398. return TRUE;
  1399. }
  1400. }
  1401. return FALSE;
  1402. }
  1403. /**
  1404. * Define a form element that configures your operator.
  1405. *
  1406. * @param object $node
  1407. * The node for which the conditionals are being configured.
  1408. *
  1409. * @return string|string[]
  1410. * Either a single rendered form element or a rendered form element per
  1411. * component (keyed by cid). Make sure that none of the rendered strings
  1412. * contains any HTML IDs as the form element will be rendered multiple times.
  1413. * The JavaScript will take care of adding the appropriate name attributes.
  1414. *
  1415. * @see _webform_conditional_expand_value_forms()
  1416. */
  1417. function callback_webform_conditional_rule_value_form($node) {
  1418. $forms = [];
  1419. foreach ($node->webform['components'] as $cid => $component) {
  1420. if (webform_component_property($component['type'], 'conditional_type') == 'newsletter') {
  1421. $element = [
  1422. '#type' => 'select',
  1423. '#options' => [
  1424. 'yes' => t('Opt-in'),
  1425. 'no' => t('No opt-in'),
  1426. ],
  1427. ];
  1428. $forms[$cid] = drupal_render($element);
  1429. }
  1430. }
  1431. return $forms;
  1432. }
  1433. /**
  1434. * @}
  1435. */