Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

Snippets by user Alex Oroshchuk Snippets by user Alex Oroshchuk

jsValidator integration helper

A real client-side validation with some nice features, without Ajax tricks provided by sfYzAjaxValidationPlugin may be easily done using jsValidator (http://sourceforge.net/projects/jsformutils/) and little helper that follows.

<?php
/**
 * Generates JavaScript code to validate a form using 
 * jsValidator as client-side validation engine (see http://sourceforge.net/projects/jsformutils/)
 * 
 * @param string $targetForm id attribute of the form to be validated
 * @param mixed $options associative array of options
 * @param string $action action to validated, defaults to current
 * 
 * Options are:
 *  stopOnFirstError: boolean, default: false
 *  labelMessageDelimiter: string, default: ' : ',
 *  messageSeparator: string, default: "\n",
 *  messageHeader: string, default: 'These fields are invalid:\n---\n' + 
 *  highlightErrors: boolean, whether to mark erroneous fields 
 *  errorElementClass: string, CSS class name to be applied to wrong fields
 *  highlightLabels: boolean, whether to mark fields or fields' labels
 */
function generate_validator($targetForm, $options, $action)
{
  $NL = "\n";
  $funcPrefix = 'validate_';
  $labelsKey = 'labels';
  $fieldsKey = 'fields';
  $jsCode = '';
 
  $paramHolder = sfContext::getInstance()->getRequest()->getParameterHolder();  
  $rulesFilePath = sfConfig::get('sf_app_module_dir').'/'.$paramHolder->get('module').'/'.
    sfConfig::get('sf_app_module_validate_dir_name').'/';
 
  // Load rules from YAML file.   
  if (file_exists($rulesFilePath.$paramHolder->get('action').'.yml'))
    $rules = sfYaml::load($rulesFilePath.$paramHolder->get('action').'.yml');
  else
    $rules = sfYaml::load($rulesFilePath.$action.'.yml');
 
  // Generate jsValidator compliant rules.  
  $jsRules = array();
  foreach ($rules['fields'] as $fieldId => $validationRule)
  {
    foreach ($validationRule as $validator=>$rule)
    {
      // Remove server-side sfCallbackValidator.
      if ($validator == 'sfCallbackValidator')
      {
        unset($validationRule[$validator]);
        continue;
      }
      // Map Symfony validators to jsValidator.
      $jsvalidator = preg_replace('/^sf(\w+Validator)$/', 'js\\1', $validator);
      if ($jsvalidator != $validator)
      {
        $validationRule[$jsvalidator] = $validationRule[$validator];
        unset($validationRule[$validator]); 
      }
    }
    $jsRules[] = array_merge ( 
      array ('field' => $fieldId, 'label' => $rules['labels'][$fieldId]),
      $validationRule
    );    
  }
 
  // Generate final JavaScript code. 
  $jsCode .= 'function '.$funcPrefix.$targetForm.'()'.$NL;
  $jsCode .= 
  '{'.$NL.
  ' var options = '.json_encode($options).';'.$NL.
  ' var rules = '.json_encode($jsRules).';'.$NL.
  ' var jsv = new jsValidator();'.$NL.
  ' jsv.SetOptions(options);'.$NL.$NL.
  ' if (!jsv.Validate(rules))'.$NL.
  ' {'.$NL.
  '   alert(jsv.GetErrorMessage());'.$NL.
  '   return false;'.$NL.  
  ' }'.$NL.
  ' return true;'.$NL.  
  '}'.$NL;
 
  return javascript_tag($jsCode);
}
?>
 

However, I need to clear this out. Besides placing this code into jsValidatorHelper.php either in modules' lib directory or symfony's one, we need to call it properly in the corresponding view.

First of all, include the helper (use JavaScript as well, jsValidator depends on it)

<?php use_helper('JavaScript', 'jsValidator') ?>
 

Validation is performed based on the same simple rule mechanism that Symfony provides. The only difference is that JavaScript validator needs these rules to be in JSON format and it needs some more options, that configure it's behavior.

<?php
// Here we set validation options.
// For more information please refer to documentation of jsValidator
$options = array(
  'stopOnFirstError' => false,
  'labelMessageDelimiter' => ' : ',
  'messageSeparator' => "\n",
  'messageHeader' => "These fields are invalid:\n---\n",
  'highlightErrors' => true,
  'errorElementClass' => 'errClass',
  'highlightLabels' => true
  ); 
// Output auto-generated JavaScript code.
echo generate_validator('editComment', $options, 'update'); 
?>
 

We also have to set up form to point to our validator before submitting. Note, that callback in onsubmit is named by concatenating "validate_" and form's id attribute.

<?php echo form_tag('comment/update', array('id'=>'editComment','onsubmit' => 'return validate_editComment()')) ?>
 

Each field must be somehow identified in the resulting error message. We achieve this by adding some extra information to <action>.yml configuration file.

# define labels for erroneous fields
labels:
  <field_id>: <field_label_text>
 

There is a limitation to validation *.yml file structure. The syntax should be something like this:

# define labels for erroneous fields
labels:
  author: Author
  email: E-mail
  body: Body
 
fields:
  author:
    required:
      msg: The name field cannot be left blank
  email:
    sfEmailValidator:
      email_error: The email address is not valid.
  body:
    required:
      msg: The text field cannot be left blank
 
fillin:
  enabled:       on
 

And finally, don't forget to place jsValidator into /web/js folder, and include it in view.yml

<actionTemplate>:
  javascripts: [jsvalidator]
 

Feel free to modify the snippet code and validator to achieve best results!

by Alex Oroshchuk on 2007-12-04, tagged helper  javascript  validation 
(1 comment)