Projet

Général

Profil

Paste
Télécharger (12,7 ko) Statistiques
| Branche: | Révision:

root / htmltest / sites / all / modules / webform_validation / webform_validation.module @ dc45a079

1
<?php
2

    
3
/**
4
 * @file
5
 * Add validation rules to webforms
6
 */
7

    
8
include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'webform_validation') . '/' . 'webform_validation.validators.inc';
9
include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'webform_validation') . '/' . 'webform_validation.rules.inc';
10

    
11
/**
12
 * Implements hook_menu().
13
 */
14
function webform_validation_menu() {
15
  $items = array();
16

    
17
  $items['node/%webform_menu/webform/validation'] = array(
18
    'title' => 'Form validation',
19
    'page callback' => 'webform_validation_manage',
20
    'page arguments' => array(1),
21
    'access callback' => 'node_access',
22
    'access arguments' => array('update', 1),
23
    'file' => 'webform_validation.admin.inc',
24
    'weight' => 3,
25
    'type' => MENU_LOCAL_TASK,
26
  );
27

    
28
  $items['node/%webform_menu/webform/validation/add/%'] = array(
29
    'title' => 'Add validation',
30
    'page callback' => 'drupal_get_form',
31
    'page arguments' => array('webform_validation_manage_rule', 1, 'add', 5),
32
    'access callback' => 'node_access',
33
    'access arguments' => array('update', 1),
34
    'file' => 'webform_validation.admin.inc',
35
    'type' => MENU_CALLBACK,
36
  );
37

    
38
  $items['node/%webform_menu/webform/validation/edit/%/%webform_validation_rule'] = array(
39
    'title' => 'Edit rule',
40
    'page callback' => 'drupal_get_form',
41
    'page arguments' => array('webform_validation_manage_rule', 1, 'edit', 5, 6),
42
    'access callback' => 'node_access',
43
    'access arguments' => array('update', 1),
44
    'file' => 'webform_validation.admin.inc',
45
    'type' => MENU_CALLBACK,
46
  );
47

    
48
  $items['node/%webform_menu/webform/validation/delete/%webform_validation_rule'] = array(
49
    'title' => 'Delete rule',
50
    'page callback' => 'drupal_get_form',
51
    'page arguments' => array('webform_validation_delete_rule', 5),
52
    'access callback' => 'node_access',
53
    'access arguments' => array('update', 1),
54
    'file' => 'webform_validation.admin.inc',
55
    'type' => MENU_CALLBACK,
56
  );
57

    
58
  return $items;
59
}
60

    
61
/**
62
 * Loads validation rule from menu parameter
63
 */
64
function webform_validation_rule_load($ruleid) {
65
  return webform_validation_get_rule($ruleid);
66
}
67

    
68

    
69
/**
70
 * Implements hook_theme().
71
 */
72
function webform_validation_theme() {
73
  return array(
74
    'webform_validation_manage_add_rule' => array(
75
      'variables' => array(
76
        'nid' => NULL,
77
      ),
78
    ),
79
    'webform_validation_manage_overview' => array(
80
      'variables' => array(
81
        'rules' => NULL,
82
        'node' => NULL,
83
      ),
84
    ),
85
  );
86
}
87

    
88
/**
89
 * Implements hook_form_alter().
90
 */
91
function webform_validation_form_alter(&$form, &$form_state, $form_id) {
92
  if (strpos($form_id, 'webform_client_form_') !== FALSE) {
93
    $form['#validate'][] = 'webform_validation_validate';
94
  }
95
}
96

    
97
/**
98
 * Webform validation handler to validate against the given rules
99
 */
100
function webform_validation_validate($form, &$form_state) {
101
  $page_count = 1;
102
  $nid = $form_state['values']['details']['nid'];
103
  $node = node_load($nid);
104
  $values = isset($form_state['values']['submitted']) ? $form_state['values']['submitted'] : NULL;
105
  $flat_values = _webform_client_form_submit_flatten($node, $values);
106
  $rules = webform_validation_get_node_rules($nid);
107
  $sid = empty($form_state['values']['details']['sid']) ? 0 : $form_state['values']['details']['sid'];
108

    
109
  // Get number of pages for this webform
110
  if (isset($form_state['webform']['page_count'])) {
111
    $page_count = $form_state['webform']['page_count'];
112
  }
113
  elseif (isset($form_state['storage']['page_count'])) {
114
    $page_count = $form_state['storage']['page_count'];
115
  }
116

    
117
  // Filter out rules that don't apply to this step in the multistep form
118
  if ($values && $page_count && $page_count > 1) {
119
    $current_page_components = webform_validation_get_field_keys($form_state['values']['submitted'], $node);
120
    if ($rules) {
121
       // filter out rules that don't belong in the current step
122
      foreach ($rules as $ruleid => $rule) {
123
        // get all the component formkeys for this specific validation rule
124
        $rule_formkeys = webform_validation_rule_get_formkeys($rule);
125
        $rule_applies_to_current_page = FALSE;
126
        if (!empty($rule_formkeys)) {
127
          foreach ($rule_formkeys as $formkey) {
128
            if (in_array($formkey, $current_page_components)) {
129
              // this rule applies to the current page,
130
              // because one of the rule components is on the page
131
              $rule_applies_to_current_page = TRUE;
132
            }
133
          }
134
        }
135

    
136
        if (!$rule_applies_to_current_page) {
137
          unset($rules[$ruleid]);
138
        }
139
      }
140
    }
141
  }
142

    
143
  if ($rules) {
144
    foreach ($rules as $rule) {
145
      // create a list of components that need validation against this rule (component id => user submitted value)
146
      $items = array();
147
      foreach ($rule['components'] as $cid => $component) {
148
        if (isset($flat_values[$cid])) {
149
          $items[$cid] = $flat_values[$cid];
150
        }
151
      }
152
      // prefix array keys to avoid reindexing by the module_invoke_all function call
153
      $items = webform_validation_prefix_keys($items);
154
      $component_definitions = webform_validation_prefix_keys($node->webform['components']);
155
      $rule['sid'] = $sid;
156
      // have the submitted values validated
157
      $errors = module_invoke_all("webform_validation_validate", $rule['validator'], $items, $component_definitions, $rule);
158
      if ($errors) {
159
        $errors = webform_validation_unprefix_keys($errors);
160
        $components = webform_validation_unprefix_keys($component_definitions);
161
        foreach ($errors as $item_key => $error) {
162
          // build the proper form element error key, taking into account hierarchy
163
          $error_key = 'submitted][' . webform_validation_parent_tree($item_key, $components) . $components[$item_key]['form_key'];
164
          form_set_error($error_key, $error);
165
        }
166
      }
167
    }
168
  }
169
}
170

    
171
/**
172
 * Recursive helper function to get all field keys (including fields in fieldsets)
173
 */
174
function webform_validation_get_field_keys($submitted, $node) {
175
  static $fields = array();
176
  foreach (element_children($submitted) as $child) {
177
    if (is_array($submitted[$child]) && element_children($submitted[$child])) {
178
      // only keep searching recursively if it's a fieldset
179
      $group_components = _webform_validation_get_group_types();
180
      if (in_array(_webform_validation_get_component_type($node, $child), $group_components)) {
181
        webform_validation_get_field_keys($submitted[$child], $node);
182
      }
183
      else {
184
        $fields[$child] = $child;
185
      }
186

    
187
    }
188
    else {
189
      $fields[$child] = $child;
190
    }
191
  }
192
  return $fields;
193
}
194

    
195
/**
196
 * Recursively add the parents for the element, to be used as first argument to form_set_error
197
 */
198
function webform_validation_parent_tree($cid, $components) {
199
  $output = '';
200
  if ($pid = $components[$cid]['pid']) {
201
    $output .= webform_validation_parent_tree($pid, $components);
202
    $output .= $components[$pid]['form_key'] . '][';
203
  }
204
  return $output;
205
}
206

    
207
/**
208
 * Get an array of formkeys for all components that have been assigned to a rule
209
 */
210
function webform_validation_rule_get_formkeys($rule) {
211
  $formkeys = array();
212
  if (isset($rule['components'])) {
213
    foreach ($rule['components'] as $cid => $component) {
214
      $formkeys[] = $component['form_key'];
215
    }
216
  }
217
  return $formkeys;
218
}
219

    
220
/**
221
 * Prefix numeric array keys to avoid them being reindexed by module_invoke_all
222
 */
223
function webform_validation_prefix_keys($arr) {
224
  $ret = array();
225
  foreach ($arr as $k => $v) {
226
    $ret['item_' . $k] = $v;
227
  }
228
  return $ret;
229
}
230

    
231
/**
232
 * Undo prefixing numeric array keys to avoid them being reindexed by module_invoke_all
233
 */
234
function webform_validation_unprefix_keys($arr) {
235
  $ret = array();
236
  foreach ($arr as $k => $v) {
237
    $new_key = str_replace('item_', '', $k);
238
    $ret[$new_key] = $v;
239
  }
240
  return $ret;
241
}
242
/**
243
 * Theme the 'add rule' list
244
 */
245
function theme_webform_validation_manage_add_rule($variables) {
246
  $nid = $variables['nid'];
247
  $output = '';
248
  $validators = webform_validation_get_validators();
249

    
250
  if ($validators) {
251
    $output = '<h3>' . t('Add a validation rule') . '</h3>';
252
    $output .= '<dl>';
253
    foreach ($validators as $validator_key => $validator_info) {
254
      $item = '';
255
      $url = 'node/' . $nid . '/webform/validation/add/' . $validator_key;
256
      $components = ' (' . implode(', ', $validator_info['component_types']) . ')';
257
      $item = '<dt>' . l($validator_info['name'], $url, array("query" => drupal_get_destination())) . '</dt>';
258
      $item .= '<dd>';
259
      if ($validator_info['description']) {
260
        $item .= $validator_info['description'] . ' ';
261
      }
262
      $item .= $components . '</dd>';
263
      $output .= $item;
264
    }
265
    $output .= '</dl>';
266
  }
267
  return $output;
268
}
269

    
270
/**
271
 * Implements hook_webform_validation().
272
 */
273
function webform_validation_webform_validation($type, $op, $data) {
274
  if ($type == 'rule' && in_array($op, array('add', 'edit'))) {
275
    if (module_exists('i18nstrings') && isset($data['error_message'])) {
276
      i18nstrings_update('webform_validation:error_message:' . $data['ruleid'] . ':message', $data['error_message']);
277
    }
278
  }
279
}
280

    
281
/**
282
 * Implements hook_node_insert().
283
 */
284
function webform_validation_node_insert($node) {
285
  if (module_exists('clone')) {
286
    if (in_array($node->type, webform_variable_get('webform_node_types'))) {
287
      webform_validation_node_clone($node);
288
    }
289
  }
290
}
291

    
292
/**
293
 * Implements hook_node_delete().
294
 */
295
function webform_validation_node_delete($node) {
296
  $rules = webform_validation_get_node_rules($node->nid);
297
  if ($rules) {
298
    foreach (array_keys($rules) as $ruleid) {
299
      webform_dynamic_delete_rule($ruleid);
300
    }
301
  }
302
}
303

    
304
/**
305
 * Adds support for node_clone module
306
 */
307
function webform_validation_node_clone($node) {
308
  if (isset($node->clone_from_original_nid)) {
309
    $original_nid = $node->clone_from_original_nid;
310
    // Get existing rules for original node
311
    $rules = webform_validation_get_node_rules($original_nid);
312
    if ($rules) {
313
      foreach ($rules as $orig_ruleid => $rule) {
314
        unset($rule['ruleid']);
315
        $rule['action'] = 'add';
316
        $rule['nid'] = $node->nid; // attach existing rules to new node
317
        $rule['rule_components'] = $rule['components'];
318
        webform_validation_rule_save($rule);
319
      }
320
    }
321
  }
322
}
323

    
324
/**
325
 * Save a validation rule. Data comes from the admin form
326
 * or nodeapi function in case of node clone
327
 */
328
function webform_validation_rule_save($values) {
329
  // save rules data
330
  if ($values['action'] == 'add') {
331
    drupal_write_record('webform_validation_rule', $values);
332
    $ruleid = $values['ruleid'];
333
    if ($ruleid && array_filter($values['rule_components'])) {
334
      webform_validation_save_rule_components($ruleid, array_filter($values['rule_components']));
335
      module_invoke_all('webform_validation', 'rule', 'add', $values);
336
    }
337
  }
338

    
339
  if ($values['action'] == 'edit') {
340
    drupal_write_record('webform_validation_rule', $values, 'ruleid');
341
    $ruleid = $values['ruleid'];
342
    // delete earlier component records for this rule id*/
343
    db_delete('webform_validation_rule_components')
344
    ->condition('ruleid', $ruleid)
345
    ->execute();
346
    if ($components = array_filter($values['rule_components'])) {
347
      webform_validation_save_rule_components($ruleid, $components);
348
      module_invoke_all('webform_validation', 'rule', 'edit', $values);
349
    }
350
  }
351
}
352

    
353
/**
354
 * Save components attached to a specific rule
355
 */
356
function webform_validation_save_rule_components($ruleid, $components) {
357
  foreach ($components as $cid => $component) {
358
    $id = db_insert('webform_validation_rule_components')
359
    ->fields(array(
360
      'ruleid' => $ruleid,
361
      'cid' => $cid,
362
    ))
363
  ->execute();
364
  }
365
}
366

    
367
/**
368
 * Given a webform node, get the component type based on a given component key
369
 */
370
function _webform_validation_get_component_type($node, $component_key) {
371
  if ($node->webform['components']) {
372
    foreach ($node->webform['components'] as $component) {
373
      if ($component['form_key'] == $component_key) {
374
        return $component['type'];
375
      }
376
    }
377
  }
378
  return FALSE;
379
}
380

    
381
/**
382
 * Get all webform components that are defined as a group
383
 */
384
function _webform_validation_get_group_types() {
385
  $types = array();
386
  foreach (webform_components() as $name => $component) {
387
    if (isset($component['features']['group']) && $component['features']['group']) {
388
      $types[] = $name;
389
    }
390
  }
391
  return $types;
392
}
393

    
394
/**
395
 * Implements hook_webform_validator_alter().
396
 */
397
function webform_validation_webform_validator_alter(&$validators) {
398
  // Add support for the Select (or Other) module
399
  if (module_exists('select_or_other')) {
400
    // if this module exists, all select components can now except user input.
401
    // Thus we provide those components the same rules as a textfield
402
    if ($validators) {
403
      foreach ($validators as $validator_name => $validator_info) {
404
        if (in_array('textfield', $validator_info['component_types'])) {
405
          $validators[$validator_name]['component_types'][] = 'select';
406
        }
407
      }
408
    }
409
  }
410
}