/[drupal]/contributions/modules/validation_api/validation_api.module
ViewVC logotype

Contents of /contributions/modules/validation_api/validation_api.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.25 - (show annotations) (download) (as text)
Sun Jul 27 22:51:17 2008 UTC (15 months, 4 weeks ago) by tapocol
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.24: +4 -4 lines
File MIME type: text/x-php
Messages can now be overwritten on the field level. Also, the fields admin UI has been turned into a two-step process for adding new fields.
1 <?php
2 // $Id: validation_api.module,v 1.24 2008/07/24 22:29:03 tapocol Exp $
3
4 /**
5 * @file
6 */
7
8 define('HOOK_ADD_VALIDATOR', 'add_validator');
9
10 /**
11 * Implementation of hook_help().
12 */
13 function validation_api_help($path, $arg) {
14 switch ($path) {
15 case 'admin/help#validation_api':
16 $output = '<p>'. t('Validation API offers the ability to create a validation PHP script or Regular-Expression script to validate any field on the site.') .'</p>';
17 $output .= '<p>'. t('Validators are the scripts that are run to test if the field is valid. Fields are representatives of any form field on the site that you want to assign a validator to test.') .'</p>';
18 return $output;
19 case 'admin/build/validation_api':
20 $output = '<p>'. t('Validators are the scripts that are run to test if the field is valid. Fields are representatives of any form field on the site that you want to assign a validator to test.') .'</p>';
21 return $output;
22 case 'admin/build/validation_api/validators':
23 $output = '<p>'. t('This page contains all of the validators in the database. You can add/edit your own validators, import validators from other modules, import validators with code, export code for a validator, and clone validators. The update link under Ops (You may or may not see this link) is for imported validators from other modules that are now different from the one in the database.');
24 return $output;
25 case 'admin/build/validation_api/validators/add':
26 $output = '<p>'. t('The rule is the script that is run to validate the value passed to this validator. The code is ran in either PHP or RegEx (depending on the language type you select).') .'</p>';
27 $output .= '<p>'. t('If you choose PHP, you need to use $value as the value and (if applicable) use $arg as the argument in the rule. If you choose RegEx, the value will automatically be used and (if applicable) just use %arg as the argument in the rule (e.g. "/^((.)|(\s)){%arg,}$/").') .'</p>';
28 $output .= '<p>'. t('Messages may use placeholders to further describe the error. You need to use %field as the placeholder for the name of the field and use %arg as the placeholder for the argument.') .'</p>';
29 return $output;
30 case 'admin/build/validation_api/validators/edit/%':
31 $output = '<p>'. t('The rule is the script that is run to validate the value passed to this validator. The code is ran in either PHP or RegEx (depending on the language type you select).') .'</p>';
32 $output .= '<p>'. t('If you choose PHP, you need to use $value as the value and (if applicable) use $arg as the argument in the rule. If you choose RegEx, the value will automatically be used and (if applicable) just use %arg as the argument in the rule (e.g. "/^((.)|(\s)){%arg,}$/").') .'</p>';
33 $output .= '<p>'. t('Messages may use placeholders to further describe the error. You need to use %field as the placeholder for the name of the field and use %arg as the placeholder for the argument.') .'</p>';
34 return $output;
35 case 'admin/build/validation_api/validators/import':
36 $output = '<p>'. t('You can check any validator(s) you want imported from modules, and/or you can put code from an export into the text-area.') .'</p>';
37 return $output;
38 case 'admin/build/validation_api/validators/export':
39 $output = '<p>'. t('Check which validators you would like to export. After exporting, copy the code in the text-area and paste into the import text-area to import these validators on other systems.') .'</p>';
40 return $output;
41 case 'admin/build/validation_api/validators/clone':
42 $output = '<p>'. t('Check which validators you would like to clone. This will create a copy of that validator to the database with a number added to the end of the name.') .'</p>';
43 return $output;
44 case 'admin/build/validation_api/fields':
45 $output = '<p>'. t('This page contains all of the fields in the database that have been associated with a validator. You can add/edit your own fields, or you can go to the field you want to add a validator to, and click the link below to add a validator.');
46 return $output;
47 case 'admin/build/validation_api/fields/add':
48 $output = '<p>'. t('The Form ID is the ID of the form the field is located in. The Field Name is the name of the field you want to validate. You can get both of the fields by going to the field and using the link directly below the field.') .'</p>';
49 $output .= '<p>'. t('Field Name\'s can have several actual fields grouped together. You can validate all fields by just using the field name. However, if you want to validate each field below it separately, you can use indexes (e.g. field_name[0]).') .'</p>';
50 $output .= '<p>'. t('The Argument is an option available if you want to have one validator serve a general purpose, and each field will send an argument for the validation. For example, if you make a validator that tests the minimum-length of the field, you can use the argument to tell the validator the minimum-length of this particular field. Make sure you set-up the validator to accept these arguments, or they will not be applied properly. If you are not using an argument, you can just leave the field blank.') .'</p>';
51 return $output;
52 case 'admin/build/validation_api/fields/edit/%':
53 $output = '<p>'. t('The Form ID is the ID of the form the field is located in. The Field Name is the name of the field you want to validate. You can get both of the fields by going to the field and using the link directly below the field.') .'</p>';
54 $output .= '<p>'. t('Field Name\'s can have several actual fields grouped together. You can validate all fields by just using the field name. However, if you want to validate each field below it separately, you can use indexes (e.g. field_name[0]).') .'</p>';
55 $output .= '<p>'. t('The Argument is an option available if you want to have one validator serve a general purpose, and each field will send an argument for the validation. For example, if you make a validator that tests the minimum-length of the field, you can use the argument to tell the validator the minimum-length of this particular field. Make sure you set-up the validator to accept these arguments, or they will not be applied properly. If you are not using an argument, you can just leave the field blank.') .'</p>';
56 return $output;
57 }
58 }
59
60 /**
61 * Implementation of hook_form_alter().
62 */
63 function validation_api_form_alter(&$form, $form_state, $form_id) {
64 $form = _validation_api_form_fields($form, _validation_api_fields($form_id, TRUE), $form_id, array('password', 'textarea', 'textfield'));
65 if (variable_get('ajax_submission', 1) == 1) {
66 drupal_add_js(drupal_get_path('module', 'validation_api') .'/validation_api.js');
67 }
68 }
69
70 /**
71 * Implementation of hook_menu().
72 */
73 function validation_api_menu() {
74 $items['admin/build/validation_api'] = array(
75 'title' => 'Validation API',
76 'description' => t('Create and manage validators and a form field\'s relationship with a validator.'),
77 'page callback' => 'validation_api_admin',
78 'access callback' => 'user_access',
79 'access arguments' => array('administer validators'),
80 'file' => 'validation_api.admin.inc',
81 );
82 $items['admin/build/validation_api/settings'] = array(
83 'title' => 'Settings',
84 'description' => t('Modify settings for the Validation API system.'),
85 'page callback' => 'drupal_get_form',
86 'page arguments' => array('validation_api_admin_settings_form'),
87 'access callback' => 'user_access',
88 'access arguments' => array('administer validators'),
89 'file' => 'validation_api.admin.inc',
90 'weight' => 2,
91 );
92 $items['admin/build/validation_api/validators'] = array(
93 'title' => 'Validators',
94 'description' => t('Create and manage validator rules, messages, etc.'),
95 'page callback' => 'validation_api_admin_validators',
96 'access callback' => 'user_access',
97 'access arguments' => array('administer validators'),
98 'file' => 'validation_api.admin.inc',
99 );
100 $items['admin/build/validation_api/validators/list'] = array(
101 'title' => 'List',
102 'type' => MENU_DEFAULT_LOCAL_TASK
103 );
104 $items['admin/build/validation_api/validators/add'] = array(
105 'title' => 'Add',
106 'page callback' => 'drupal_get_form',
107 'page arguments' => array('validation_api_admin_validators_form'),
108 'access callback' => 'user_access',
109 'access arguments' => array('administer validators'),
110 'file' => 'validation_api.admin.inc',
111 'type' => MENU_LOCAL_TASK,
112 'weight' => 1,
113 );
114 $items['admin/build/validation_api/validators/import'] = array(
115 'title' => 'Import',
116 'page callback' => 'drupal_get_form',
117 'page arguments' => array('validation_api_admin_import_form'),
118 'access callback' => 'user_access',
119 'access arguments' => array('administer validators'),
120 'file' => 'validation_api.admin.inc',
121 'type' => MENU_LOCAL_TASK,
122 'weight' => 4,
123 );
124 $items['admin/build/validation_api/validators/export'] = array(
125 'title' => 'Export',
126 'page callback' => 'drupal_get_form',
127 'page arguments' => array('validation_api_admin_export_form'),
128 'access callback' => 'user_access',
129 'access arguments' => array('administer validators'),
130 'file' => 'validation_api.admin.inc',
131 'type' => MENU_LOCAL_TASK,
132 'weight' => 5,
133 );
134 $items['admin/build/validation_api/validators/clone'] = array(
135 'title' => 'Clone',
136 'page callback' => 'drupal_get_form',
137 'page arguments' => array('validation_api_admin_clone_form'),
138 'access callback' => 'user_access',
139 'access arguments' => array('administer validators'),
140 'file' => 'validation_api.admin.inc',
141 'type' => MENU_LOCAL_TASK,
142 'weight' => 6,
143 );
144 $items['admin/build/validation_api/validators/edit/%'] = array(
145 'title' => 'Edit',
146 'page callback' => 'drupal_get_form',
147 'page arguments' => array('validation_api_admin_validators_form', 5),
148 'access callback' => 'user_access',
149 'access arguments' => array('administer validators'),
150 'file' => 'validation_api.admin.inc',
151 'type' => MENU_CALLBACK,
152 );
153 $items['admin/build/validation_api/validators/update/%'] = array(
154 'title' => 'Update',
155 'page callback' => 'drupal_get_form',
156 'page arguments' => array('validation_api_admin_update_form', 5),
157 'access callback' => 'user_access',
158 'access arguments' => array('administer validators'),
159 'file' => 'validation_api.admin.inc',
160 'type' => MENU_CALLBACK,
161 );
162 $items['admin/build/validation_api/validators/delete/%'] = array(
163 'title' => 'Delete',
164 'page callback' => 'drupal_get_form',
165 'page arguments' => array('validation_api_admin_validators_delete', 5),
166 'access callback' => 'user_access',
167 'access arguments' => array('administer validators'),
168 'file' => 'validation_api.admin.inc',
169 'type' => MENU_CALLBACK,
170 );
171 $items['admin/build/validation_api/fields'] = array(
172 'title' => 'Fields',
173 'description' => t('Create and manage a form field\'s validator, argument, etc.'),
174 'page callback' => 'validation_api_admin_fields',
175 'access callback' => 'user_access',
176 'access arguments' => array('administer fields'),
177 'file' => 'validation_api.admin.inc',
178 'weight' => 1,
179 );
180 $items['admin/build/validation_api/fields/list'] = array(
181 'title' => 'List',
182 'type' => MENU_DEFAULT_LOCAL_TASK
183 );
184 $items['admin/build/validation_api/fields/add'] = array(
185 'title' => 'Add',
186 'page callback' => 'drupal_get_form',
187 'page arguments' => array('validation_api_admin_fields_form'),
188 'access callback' => 'user_access',
189 'access arguments' => array('administer fields'),
190 'file' => 'validation_api.admin.inc',
191 'type' => MENU_LOCAL_TASK,
192 );
193 $items['admin/build/validation_api/fields/edit/%'] = array(
194 'title' => 'Edit',
195 'page callback' => 'drupal_get_form',
196 'page arguments' => array('validation_api_admin_fields_form', 5),
197 'access callback' => 'user_access',
198 'access arguments' => array('administer fields'),
199 'file' => 'validation_api.admin.inc',
200 'type' => MENU_CALLBACK,
201 );
202 $items['admin/build/validation_api/fields/delete/%'] = array(
203 'title' => 'Delete',
204 'page callback' => 'drupal_get_form',
205 'page arguments' => array('validation_api_admin_fields_delete', 5),
206 'access callback' => 'user_access',
207 'access arguments' => array('administer validators'),
208 'file' => 'validation_api.admin.inc',
209 'type' => MENU_CALLBACK,
210 );
211 $items['validation_api'] = array(
212 'page callback' => 'validation_api_ajax_page',
213 'access callback' => 'user_access',
214 'access arguments' => array('access content'),
215 'type' => MENU_CALLBACK,
216 );
217 $items['validation_api_test'] = array(
218 'title' => 'Validation API Test',
219 'page callback' => 'drupal_get_form',
220 'page arguments' => array('validation_api_test_form'),
221 'access callback' => 'user_access',
222 'access arguments' => array('access content'),
223 'type' => MENU_CALLBACK,
224 );
225
226 return $items;
227 }
228
229 function validation_api_test_form () {
230 $form['text_test'] = array(
231 '#type' => 'textfield',
232 '#title' => t('Test Text'),
233 '#required' => TRUE,
234 );
235 $form['checkboxes_test'] = array(
236 '#type' => 'checkboxes',
237 '#title' => t('Test Boxes'),
238 '#options' => array(1 => 'One', 2 => 'Two', 3 => 'Three'),
239 );
240 $form['submit'] = array(
241 '#type' => 'submit',
242 '#value' => 'Test Submit',
243 );
244
245 return $form;
246 }
247
248 /**
249 * Implementation of hook_perm().
250 */
251 function validation_api_perm() {
252 return array('administer validators');
253 }
254
255 /**
256 * Helper function to incorporate the elements that need validation into the structured form array.
257 * Also, adds a 'Add a validator to this field' link to the #suffix of core text-like elements.
258 *
259 * @param $elements
260 * Structured section of a form array.
261 * @param $va_fields
262 * A keyed array of field objects.
263 * @param $form_id
264 * Form ID.
265 * @param $field_types
266 * An array of field types that allow links to be added to the suffix.
267 *
268 * @return
269 * Returns the element with possible changes.
270 */
271 function _validation_api_form_fields($elements, $validation_api_fields, $form_id, $field_types) {
272 foreach (element_children($elements) as $key) {
273 if (isset($validation_api_fields[$key])) {
274 $elements[$key]['#element_validate'][] = '_validation_api_validator';
275 }
276 if (!is_int($key) && isset($elements[$key]['#type']) && user_access('administer validators') && in_array($elements[$key]['#type'], $field_types)) {
277 $elements[$key]['#suffix'] = (isset($elements[$key]['#suffix']) ? $elements[$key]['#suffix'] : '') .'<div class="va_link">'. l(t('Add a validator to this field'), 'admin/build/validation_api/fields/add', array('query' => array('form_id' => $form_id, 'form_field' => $key))) .'</div>';
278 }
279 if (is_array($elements[$key])) {
280 $elements[$key] = _validation_api_form_fields($elements[$key], $validation_api_fields, $form_id, $field_types);
281 }
282 }
283
284 return $elements;
285 }
286
287 /**
288 * Helper function to get each field that needs validation from the form ID.
289 *
290 * @param $form_id
291 * Form ID.
292 *
293 * @return
294 * Returns a keyed array of field validator objects.
295 *
296 * array(
297 * $field1_name => array(
298 * $field1_validator1->obj,
299 * $field1_validator2->obj,
300 * ...
301 * ),
302 * $field2_name => array(
303 * $field2_validator1->obj,
304 * $field2_validator2->obj,
305 * ...
306 * ),
307 * ...
308 * );
309 */
310 function _validation_api_fields($form_id, $unique = FALSE) {
311 $result = db_query('SELECT * FROM {validation_api_fields} WHERE form_id = "%s"', $form_id);
312 $fields = array();
313 while ($obj = db_fetch_object($result)) {
314 $fields[$obj->form_field][] = $obj;
315 }
316
317 if ($unique) {
318 foreach ($fields as $name => $field) {
319 $pos = strpos($name, '[');
320 if ($pos !== FALSE) {
321 $new_name = substr($name, 0, $pos);
322 if (isset($fields[$new_name])) {
323 $fields[$new_name] = array_merge($fields[$new_name], $field);
324 }
325 else {
326 $fields[$new_name] = $field;
327 }
328 unset($fields[$name]);
329 }
330 }
331 }
332
333 return $fields;
334 }
335
336 /**
337 * Get an object for every validator in the database.
338 *
339 * @return
340 * Returns a keyed array of validator objects.
341 *
342 * array(
343 * $validator1_id => $validator1->obj,
344 * $validator2_id => $validator2->obj,
345 * ...
346 * );
347 */
348 function _validation_api_validators() {
349 $validators = array();
350 $result = db_query('SELECT * FROM {validation_api_validators}');
351 while ($obj = db_fetch_object($result)) {
352 $validators[$obj->vavid] = $obj;
353 }
354
355 return $validators;
356 }
357
358 /**
359 * Get an object for every validator in hooks.
360 *
361 * @return
362 * Returns a keyed array of validator objects.
363 *
364 * array(
365 * $validator1_id => $validator1->obj,
366 * $validator2_id => $validator2->obj,
367 * ...
368 * );
369 */
370 function _validation_api_validators_from_hook() {
371 $validators = array();
372 foreach (module_implements(HOOK_ADD_VALIDATOR) as $module) {
373 $hook_return = call_user_func($module .'_'. HOOK_ADD_VALIDATOR);
374 foreach ($hook_return as $delta => $validator) {
375 $validators[$module .'-'. $delta] = $validator;
376 $validators[$module .'-'. $delta]->module = $module;
377 $validators[$module .'-'. $delta]->delta = $delta;
378 }
379 }
380
381 return $validators;
382 }
383
384 /**
385 * Function that is used in a form element's #element_validate property.
386 * This will run the element through the validation process, and set an error if there are any incorrect submissions.
387 *
388 * @param $element
389 * A form element's keyed array.
390 * @param &$form_state
391 * The state of the form.
392 *
393 * @return
394 * Nothing is returned.
395 */
396 function _validation_api_validator($element, &$form_state) {
397 static $validators;
398 static $validation_api_fields;
399
400 if (!isset($validators)) {
401 $validators = _validation_api_validators();
402 }
403 if (!isset($validation_api_fields)) {
404 $validation_api_fields = _validation_api_fields($form_state['values']['form_id']);
405 }
406
407 if (isset($element['#tree']) && $element['#tree']) {
408 foreach ($element as $field) {
409 if (isset($field['#name'])) {
410 if (isset($validation_api_fields[$field['#name']])) {
411 unset($field['#tree']);
412 _validation_api_validator($field, $form_state);
413 }
414 $pos = strpos($field['#name'], '[');
415 if ($pos !== FALSE && isset($validation_api_fields[substr($field['#name'], 0, $pos)])) {
416 $field['#name'] = substr($field['#name'], 0, $pos);
417 unset($field['#tree']);
418 _validation_api_validator($field, $form_state);
419 }
420 }
421 }
422 }
423 else {
424 foreach ($validation_api_fields[$element['#name']] as $validation_api_field) {
425 $value = (is_array($element['#value']) ? $element['#value']['value'] : $element['#value']);
426 if (!(is_null($value) || $value == '') || !$validation_api_field->allow_empty) {
427 if (isset($validation_api_field->arg)) {
428 $arg = $validation_api_field->arg;
429 }
430
431 $validator = $validators[$validation_api_field->vavid];
432
433 switch ($validator->type) {
434 case 'php':
435 // Run the PHP code validation.
436 if (!eval($validator->rule)) {
437 $message = $validation_api_field->message;
438 // Set up the substitution strings for the message.
439 $substitutes['%field'] = $element['#name'];
440 if (isset($arg)) {
441 $substitutes['%arg'] = $arg;
442 }
443
444 form_set_error($element['#name'], t($message, $substitutes));
445 }
446 break;
447 case 'regex':
448 // Make argument change, if applicable, in regex code.
449 $rule = (isset($arg) ? str_replace('%arg', $arg, $validator->rule) : $validator->rule);
450
451 // Run the regular expression validation.
452 if (!preg_match($rule, $value)) {
453 $message = $validation_api_field->message;
454 // Set up the substitution strings for the message.
455 $substitutes['%field'] = $element['#name'];
456 if (isset($arg)) {
457 $substitutes['%arg'] = $arg;
458 }
459
460 // Validator rule is in this message just for testing purposes.
461 form_set_error($element['#name'], t($message, $substitutes));
462 }
463 break;
464 }
465 }
466 }
467 }
468 }
469
470 /**
471 * This function is only here for testing purposes. This will be deprecated, when testing is finished.
472 * Implementation of hook_add_validator().
473 */
474 function validation_api_add_validator() {
475 $validators[0]->name = 'length';
476 $validators[0]->type = 'regex';
477 $validators[0]->rule = '/^((.)|(\s)){%arg,}$/';
478 $validators[0]->message = '%field must be at least %arg characters.';
479
480 return $validators;
481 }
482
483 /**
484 * This is a page callback that is called for running AJAX submissions
485 */
486 function validation_api_ajax_page() {
487 // This is just for testing purposes. This will be cleared.
488 $obj->test = '';
489 foreach ($_POST as $key => $value) {
490 $obj->test .= "$key = $value\n";
491 }
492
493 // Inside this if statement is revised code from drupal_get_form and drupal_process_form
494 if (!empty($_POST['form_id']) && !empty($_POST['form_build_id'])) {
495 $form_id = $_POST['form_id'];
496
497 $form_state = array('storage' => NULL, 'submitted' => FALSE);
498
499 // Prepare arguments for drupal_retrieve call later on
500 $menu_item = menu_get_item($_GET['action']);
501 $args = $menu_item['page_arguments'];
502 foreach ($args as $key => $arg) {
503 $args[$key] = (array) $arg;
504 }
505 array_unshift($args, NULL);
506
507 $cacheable = FALSE;
508
509 // If the incoming $_POST contains a form_build_id, we'll check the
510 // cache for a copy of the form in question. If it's there, we don't
511 // have to rebuild the form to proceed. In addition, if there is stored
512 // form_state data from a previous step, we'll retrieve it so it can
513 // be passed on to the form processing code.
514 if (isset($_POST['form_id']) && $_POST['form_id'] == $form_id && !empty($_POST['form_build_id'])) {
515 $form = form_get_cache($_POST['form_build_id'], $form_state);
516 }
517
518 // If the previous bit of code didn't result in a populated $form
519 // object, we're hitting the form for the first time and we need
520 // to build it from scratch.
521 if (!isset($form)) {
522 $form_state['post'] = $_POST;
523 // Use a copy of the function's arguments for manipulation
524 $args_temp = $args;
525 $args_temp[0] = &$form_state;
526 array_unshift($args_temp, $form_id);
527 $form = call_user_func_array('drupal_retrieve_form', $args_temp);
528 $form_build_id = 'form-'. md5(mt_rand());
529 $form['#build_id'] = $form_build_id;
530 drupal_prepare_form($form_id, $form, $form_state);
531 // Store a copy of the unprocessed form for caching and indicate that it
532 // is cacheable if #cache will be set.
533 $original_form = $form;
534 $cacheable = TRUE;
535 unset($form_state['post']);
536 }
537 $form['#post'] = $_POST;
538 $form_state['values'] = array();
539
540 $form = form_builder($form_id, $form, $form_state);
541 // Only process the form if it is programmed or the form_id coming
542 // from the POST data is set and matches the current form_id.
543 if ((!empty($form['#programmed'])) || (!empty($form['#post']) && (isset($form['#post']['form_id']) && ($form['#post']['form_id'] == $form_id)))) {
544 drupal_validate_form($form['#post']['form_id'], $form, $form_state);
545 }
546
547 $obj->success = is_null(form_get_errors());
548 if (!$obj->success) {
549 $obj->errors->elements = array_keys(form_get_errors());
550 $obj->errors->messages = array_values(form_get_errors());
551 }
552 }
553 // If it is not a valid submission, then return an error.
554 else {
555 $obj->success = FALSE;
556 $obj->errors->elements = array('form');
557 $obj->errors->messages = array('There is a problem with validating this form. You may need to reload the page.');
558 }
559
560 //header('Content-Type: application/json; charset=UTF-8');
561 //echo json_encode($obj);
562 drupal_json($obj);
563 unset($_SESSION['messages']); // Clears messages, so errors do not show up on the next page
564
565 exit;
566 }

  ViewVC Help
Powered by ViewVC 1.1.2