![]() |
|
Snippets |
|
When using fillin filter, after validation success (all form fields are ok) if you want display page without form, fillin filter is still enabled and throws exception "Exception - No form found in this page". Use this snippet to prevent it.
in sfFillInFormFilter.class.php file
public function execute($filterChain) { // execute next filter $filterChain->execute(); $context = $this->getContext(); $response = $context->getResponse(); $request = $context->getRequest(); // add these two lines if(! $request->hasErrors()) return;
Currently i had to do different validations of data depending the data entered by the user.
The solution i found, using the symfony built-in yml validation was:
action:
$validated = true; $validationConfig = $this->getModuleName().'/'.sfConfig::get('sf_app_module_validate_dir_name').'/'.$validationFile.'.yml'; if (null !== $validateFile = sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$validationConfig, true)) { $context = $this->getContext(); $validatorManager = new sfValidatorManager(); $validatorManager->initialize($context); require($validateFile); $validated = $validatorManager->execute(); }
refactoring:
public function validateParamsYml($validationFile) { $validated = true; $validationConfig = $this->getModuleName().'/'.sfConfig::get('sf_app_module_validate_dir_name').'/'.$validationFile.'.yml'; if (null !== $validateFile = sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$validationConfig, true)) { $context = $this->getContext(); $validatorManager = new sfValidatorManager(); $validatorManager->initialize($context); require($validateFile); $validated = $validatorManager->execute(); } return $validated; }
Then you can call any validations rules at your action:
public function executeXXX() { [...] [...] $this->validateParamsYml('yml_1'); $this->validateParamsYml('yml_2'); [...] }
and finally check if everything was validated then forward/save the data:
if($this->getRequest()->hasErrors()) { return $this->handleErrorXXXX(); }
Cheers
The example is for a blog. The page that displays a post also proposes an AJAX form to add a comment. We want that when the validation of this form fails, it displays again in the page with an error message, and when the validation succeeds, the form is replaced byu the comment just posted.
The idea is to take advantage of the way the update option of the form_remote_tag() helper works. It accepts an associative array, where you can specify different zones to update in case of success and failure. The only problem is that for Prototype, a failure is a return code other than 2XX. So when we return the form showing the error message again, we need to set the status code to 404, for instance, for Prototype to choose to update the correct zone.
That, plus the usual use of partials here and there, and you have a working solution:
in modules/post/actions/action.class.php
// Display the form public function executeShow() { $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); }
in modules/post/templates/showSuccess.php
// Display question detail here ... // Beginning of Comment zone <div id="added_comment" style="display_none"> </div> <div id="add_comment"> <?php include_partial('comment/add_comment', array('post' => $post)) ?> </div>
in modules/comment/templates/_add_comment.php
<?php use_helper('Javascript', 'Validation') ?> <?php echo form_remote_tag(array( 'url' => 'comment/add', 'update' => array('success' => 'added_comment', 'failure' => 'add_comment'), 'script' => true, 'loading' => "Element.show('indicator')", 'success' => "Element.hide('indicator');Element.show('added_comment');Element.hide('add_comment');", 'failure' => "Element.hide('indicator');", )) ?> <?php echo input_hidden_tag('post_id', $post->getId()) ?> <?php echo form_error('body') ?> <label for="body">Your comment</label> <?php echo textarea_tag('body') ?> <?php echo submit_tag('Send') ?> </form>
in modules/comment/validate/add.yml
methods: post: [body] fillin: activate: Yes names: body: required: Yes required_msg: You must provide a comment validators: spamValidator spamValidator: class: sfRegexValidator param: match: No pattern: /http.*http/ match_error: Do not provide more than one URL - It is considered Spam
in modules/comment/actions/action.class.php
public function handleErrorAdd() { $this->post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); $this->getResponse()->setStatusCode(404); return sfView::ERROR; } public function executeAdd() { $post = PostPeer::retrieveByPk($this->getRequestParameter('post_id')); $this->forward404Unless($post); $comment = new Comment(); $comment->setPost($post); $comment->setAuthor($this->getUser()->getAuthor()); $comment->setBody($this->getRequestParameter('body')); $comment->save(); $this->comment = $comment; }
in modules/comment/templates/addError.php
<?php include_partial('comment/add_comment', array('post' => $post)) ?>
in modules/comment/templates/addSuccess.php
Your comment has been added: <div class="comment"> <?php echo $comment->getBody() ?> </div>
As a bonus, the form is still there after a successful submission (but hidden), so with a few more lines of code, you can still provide a Digg-like "edit comment for the next 60 seconds" feature.
This snippet allow to check if an entry allready exists in a database but, at the difference of the sfUniqueValidator, you can provide as many fields as desired to perform the verification.
Installation:
The first thing you need to do is to create the file sfCustomUniqueValidator.php in your project lib directory:
<?php /** * sfCustomUniqueValidator checks if a record exist in the database with all the mentionned fields. * * ex: Check if a companie with company_name exist in country_id * class: sfCustomUniqueValidator * param: * class: Companies //the class on which the search is performed * nb_fields: 2 //the number of fields on which the comparison is done * field_1: company_name //First field of the comparison * field_2: country_id //Other country for the comparison * * @package lib * @author Joachim Martin * @date 15/06/2007 */ class sfCustomUniqueValidator extends sfValidator { /** * Executes this validator. * * @param mixed A file or parameter value/array * @param error An error message reference * * @return bool true, if this validator executes successfully, otherwise false */ public function execute(&$value, &$error) { $className = $this->getParameter('class').'Peer'; //Get fields number $nb_fields = $this->getParameter('nb_fields'); //Define new criteria $c = new Criteria(); //Loop on the fields for($i = 1; $i <= $nb_fields ; $i++) { //Retrieve field_$i $check_param = $this->getParameterHolder()->get("field_$i"); $check_value = $this->getContext()->getRequest()->getParameter($check_param); //If check value defined if ($check_value != '') { //Adding field to the criteria $columnName = call_user_func(array($className, 'translateFieldName'), $check_param, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME); $c->add($columnName, $check_value); } } $object = call_user_func(array($className, 'doSelectOne'), $c); if ($object) { $tableMap = call_user_func(array($className, 'getTableMap')); foreach ($tableMap->getColumns() as $column) { if (!$column->isPrimaryKey()) { continue; } $method = 'get'.$column->getPhpName(); $primaryKey = call_user_func(array($className, 'translateFieldName'), $column->getPhpName(), BasePeer::TYPE_PHPNAME, BasePeer::TYPE_FIELDNAME); if ($object->$method() != $this->getContext()->getRequest()->getParameter($primaryKey)) { $error = $this->getParameter('custom_unique_error'); return false; } } } return true; } public function initialize ($context, $parameters = null) { // initialize parent parent::initialize($context); //Set default parameters value $this->setParameter('custom_unique_error','The value is not unique'); $this->getParameterHolder()->add($parameters); // check parameters if (!$this->getParameter('class')) { throw new sfValidatorException('The "class" parameter is mandatory for the sfCustomUniqueValidator validator.'); } if (!$this->getParameter('nb_fields')) { throw new sfValidatorException('The "nb_fields" parameter is mandatory for the sfCustomUniqueValidator validator.'); } return true; } }
Usage:
The following code check if a companie with the same name and same activity exists in the same country
sfCustomUniqueValidator:
class: Companies
nb_fields: 3
field_1: company_name
field_2: activity_id
field_3: country_id
custom_unique_error: This company already exist for this country
class: the model to test
nb_fields: how many fields will be checked
field_x: a field to test, obviously you need to have as many field_x as the nb_fields value
custom_unique_error: your error message
This is my very first contribution to symfony so feel free to comment/optimize.
This images validations is an extention for the sfFileValidator. You can use it for validate uploaded images maximum width and height, minimum width and height and if the images have square dimensions.
<?php /** * sfFileImageValidator allows you to apply constraints to image file upload, it extend the sfFileValidator functions. * * <b>Optional parameters:</b> * * # <b>max_height</b> - [none] - Maximum images height in pixels. * # <b>max_height_error</b> - [The file height is too large] - An error message to use when * images height is too large. * # <b>max_width</b> - [none] - Maximum images width in pixels. * # <b>max_width_error</b> - [The file width is too large] - An error message to use when * images width is too large. * # <b>min_height</b> - [none] - Minimum images height in pixels. * # <b>min_height_error</b> - [The file height is too small] - An error message to use when * images height is too small. * # <b>min_width</b> - [none] - Minimum images width in pixels. * # <b>min_width_error</b> - [The file width is too small] - An error message to use when * images width is too small. * # <b>is_square</b> - [false] - The image is a square * # <b>is_square_error</b> - [The file is not a square] - An error message to use when * the images is not a square * (The width size is not equal * to the height size). * @package symfony * @subpackage validator * @author Daniel Santiago */ class sfFileImageValidator extends sfFileValidator { /** * Executes this validator. * * @param mixed A file or parameter value/array * @param error An error message reference * * @return bool true, if this validator executes successfully, otherwise false */ public function execute(&$value, &$error) { if (parent::execute($value, $error)) { list($width, $height) = @getimagesize($value['tmp_name']); // File is not a square $is_square = $this->getParameter('is_square'); if ($is_square && $width != $height) { $error = $this->getParameter('is_square_error'); return false; } // File height too large $max_height = $this->getParameter('max_height'); if ($max_height !== null && $max_height < $height) { $error = $this->getParameter('max_height_error'); return false; } // File width too large $max_width = $this->getParameter('max_width'); if ($max_width !== null && $max_width < $width) { $error = $this->getParameter('max_width_error'); return false; } // File height too small $min_height = $this->getParameter('min_height'); if ($min_height !== null && $min_height > $height) { $error = $this->getParameter('min_height_error'); return false; } // File width too small $min_width = $this->getParameter('min_width'); if ($min_width !== null && $min_width > $width) { $error = $this->getParameter('min_width_error'); return false; } return true; } } /** * Initializes this validator. * * @param sfContext The current application context * @param array An associative array of initialization parameters * * @return bool true, if initialization completes successfully, otherwise false */ public function initialize($context, $parameters = null) { // initialize parent parent::initialize($context, $parameters); // set defaults $this->getParameterHolder()->set('max_height', null); $this->getParameterHolder()->set('max_height_error', 'The file height is too large'); $this->getParameterHolder()->set('max_width', null); $this->getParameterHolder()->set('max_width_error', 'The file width is too large'); $this->getParameterHolder()->set('min_height', null); $this->getParameterHolder()->set('min_height_error', 'The file height is too small'); $this->getParameterHolder()->set('min_width', null); $this->getParameterHolder()->set('min_width_error', 'The file width is too small'); $this->getParameterHolder()->set('is_square', false); $this->getParameterHolder()->set('is_square_error', 'The file is not a square'); $this->getParameterHolder()->add($parameters); return true; } }
In the YAML validation file put this:
news{photo}: file: yes sfFileImageValidator: min_height: 100 min_height_error: 'The image height is too small, it must have minimum 100px' min_width: 120 min_width_error: 'The image width is too small, it must have minimum 120px' max_height: 960 max_height_error: 'The image height is too large, it must have maximum 960px' max_width: 450 max_width_error: 'The image width is too large, it must have maximum 450px' is_square: true is_square_error: 'The images must be a square (The height be equal to the width)' max_size: 256000 max_size_error: 'The maximum images size is 250Kb' mime_types_error: 'We only accept GIF, PNG and JPEG.' mime_types: - 'image/jpeg' - 'image/png' - 'image/gif'
I love sfCallbackValidator and use it all the time, but found it was somewhat limiting in that only the value being validated could be passed to the function or method that is doing the validating. So, I've extended it, overriding the execute method:
myCallbackValidator.class.php:
<?php class myCallbackValidator extends sfCallbackValidator { public function execute(&$value, &$error) { $callback = $this->getParameterHolder()->get('callback'); if (!call_user_func($callback, $value, $this->getParameterHolder()->get('parameters'))) { $error = $this->getParameterHolder()->get('invalid_error'); return false; } return true; } }
You can specify the parameters in your validation yaml file like so...
birthdate:
myCallbackValidator:
callback: [myValidationTools, birthDate]
invalid_error: Birthdate is invalid. You must be at least 18 years old to apply.
parameters:
min_age: 18
And then the parameters can be accessed in the callback function like so:
public static function birthDate($string, $params = null) { if (isset($params['min_age'])) { ... etc...
Here is another variation on the credit card validator. In your validate/[action].yml file, you can implement this helper like so:
fields:
cc_type:
required:
msg: Please select a card type
sfStringValidator:
values: [Visa, MasterCard, Discover, American Express]
values_error: Please select a credit card type
insensitive: true
cc_number:
required:
msg: Please provide a credit card number
myCreditCardValidator:
card_name: cc_type # refers to field name in form that contains card type, like Visa, MasteCard, etc.
Place this file, myCreditCardValidator.class.php, in you application's /lib directory and clear the cache.
<?php /** * This class has been converted to a Symfony Validator from original code * created by John Gardner, 4th January 2005. * http://www.braemoor.co.uk/software/index.shtml * * Symfony conversion by Scott Meves, Stereo Interactive & Design, 2007 * http://www.stereointeractive.com * * This routine checks the credit card number. The following checks are made: * * 1. A number has been provided * 2. The number is a right length for the card * 3. The number has an appropriate prefix for the card * 4. The number has a valid modulus 10 number check digit if required * **/ class myCreditCardValidator extends sfValidator { static protected $CARDS = array ( array ('name' => 'American Express', 'length' => '15', 'prefixes' => '34,37', 'checkdigit' => true ), array ('name' => 'Carte Blanche', 'length' => '14', 'prefixes' => '300,301,302,303,304,305,36,38', 'checkdigit' => true ), array ('name' => 'Diners Club', 'length' => '14', 'prefixes' => '300,301,302,303,304,305,36,38', 'checkdigit' => true ), array ('name' => 'Discover', 'length' => '16', 'prefixes' => '6011', 'checkdigit' => true ), array ('name' => 'Enroute', 'length' => '15', 'prefixes' => '2014,2149', 'checkdigit' => true ), array ('name' => 'JCB', 'length' => '15,16', 'prefixes' => '3,1800,2131', 'checkdigit' => true ), array ('name' => 'Maestro', 'length' => '16', 'prefixes' => '5020,6', 'checkdigit' => true ), array ('name' => 'MasterCard', 'length' => '16', 'prefixes' => '51,52,53,54,55', 'checkdigit' => true ), array ('name' => 'Solo', 'length' => '16,18,19', 'prefixes' => '6334, 6767', 'checkdigit' => true ), array ('name' => 'Switch', 'length' => '16,18,19', 'prefixes' => '4903,4905,4911,4936,564182,633110,6333,6759', 'checkdigit' => true ), array ('name' => 'Visa', 'length' => '13,16', 'prefixes' => '4', 'checkdigit' => true ), array ('name' => 'Visa Electron', 'length' => '16', 'prefixes' => '417500,4917,4913', 'checkdigit' => true ) ); public function initialize($context, $parameters = null) { // initialize parent parent::initialize($context); // set defaults $parameterHolder = $this->getParameterHolder(); $parameterHolder->set('cc_error_type', 'Unknown card type'); $parameterHolder->set('cc_error_missing', 'No card number provided'); $parameterHolder->set('cc_error_format', 'Credit card number has invalid format'); $parameterHolder->set('cc_error_number', 'Credit card number is invalid'); $parameterHolder->set('cc_error_length', 'Credit card number is wrong length'); $this->getParameterHolder()->add($parameters); return true; } public function execute(&$value, &$error) { $cardName = $this->getParameterHolder()->get('card_name'); $cardName = $this->getContext()->getRequest()->getParameter($cardName); $cardNumber = $value; // Establish card type $cardType = -1; for ($i=0; $i<sizeof(self::$CARDS); $i++) { // See if it is this card (ignoring the case of the string) if (strtolower($cardName) == strtolower(self::$CARDS[$i]['name'])) { $cardType = $i; break; } } // If card type not found, report an error if ($cardType == -1) { $error = $this->getParameterHolder()->get('cc_error_type'); return false; } // Ensure that the user has provided a credit card number if (strlen($cardNumber) == 0) { $error = $this->getParameterHolder()->get('cc_error_missing'); return false; } // Remove any non-digits from the credit card number $cardNo = preg_replace('/[^0-9]/', '', $cardNumber); // Check that the number is numeric and of the right sort of length. if (!eregi('^[0-9]{13,19}$',$cardNo)) { $error = $this->getParameterHolder()->get('cc_error_format'); return false; } // Now check the modulus 10 check digit - if required if (self::$CARDS[$cardType]['checkdigit']) { $checksum = 0; // running checksum total $mychar = ""; // next char to process $j = 1; // takes value of 1 or 2 // Process each digit one by one starting at the right for ($i = strlen($cardNo) - 1; $i >= 0; $i--) { // Extract the next digit and multiply by 1 or 2 on alternative digits. $calc = $cardNo{$i} * $j; // If the result is in two digits add 1 to the checksum total if ($calc > 9) { $checksum = $checksum + 1; $calc = $calc - 10; } // Add the units element to the checksum total $checksum = $checksum + $calc; // Switch the value of j if ($j ==1) {$j = 2;} else {$j = 1;}; } // All done - if checksum is divisible by 10, it is a valid modulus 10. // If not, report an error. if ($checksum % 10 != 0) { $error = $this->getParameterHolder()->get('cc_error_number'); return false; } } // The following are the card-specific checks we undertake. // Load an array with the valid prefixes for this card $prefix = split(',',self::$CARDS[$cardType]['prefixes']); // Now see if any of them match what we have in the card number $prefixValid = false; for ($i=0; $i<sizeof($prefix); $i++) { $exp = '^' . $prefix[$i]; if (ereg($exp,$cardNo)) { $prefixValid = true; break; } } // If it isn't a valid prefix there's no point at looking at the length if (!$prefixValid) { $error = $this->getParameterHolder()->get('cc_error_number'); return false; } // See if the length is valid for this card $lengthValid = false; $lengths = split(',',self::$CARDS[$cardType]['length']); for ($j=0; $j<sizeof($lengths); $j++) { if (strlen($cardNo) == $lengths[$j]) { $lengthValid = true; break; } } // See if all is OK by seeing if the length was valid. if (!$lengthValid) { $error = $this->getParameterHolder()->get('cc_error_length'); return false; }; // The credit card is in the required format. return true; } }
add this to your validation file for the action.
eg: indexSuccess.php would have have a file called index.yml in the validate directory for that module if you configured validation.
fillin:
activate: on # activate the form repopulation
param:
name: test # name of the form
sfValidator extension based on Credit Card Validator code by Harish Chauhan (from phpclasses.org). With this extension you can validate this type of credit cards: VISA, MASTERCARD, DISCOVER, AMEX, DINERS,JCB, Australian Bankcard, EnRoute And Switch Solo.
IMHO isn't a bad idea to include anything like this in standard sfValidator code. While here you have the source code of my adaptation of credit cards validator.
<?php /* Symfony integration as sfValidator of CCVAL Date - Jun 17, 2006 Author - Oriol Rius (oriol@joor.net) Credit CArd Validator Date - Jan 14, 2005 Author - Harish Chauhan ABOUT This PHP script will calidate credit cards by checking there length and pattern and checksum using mod 10. Supported credit cards are VISA, MASTERCARD, DISCOVER, AMEX, DINERS, JCB, Australian Bankcard, EnRoute And Switch Solo. */ class CCVAL extends sfValidator { public function execute (&$value, &$error) { // Recuperamos parámetros validar $num_param = $this->getParameterHolder()->get('num'); $num = $this->getContext()->getRequest()->getParameter($num_param); $tipo_param = $this->getParameterHolder()->get('tipo'); $tipo = $this->getContext()->getRequest()->getParameter($tipo_param); // Lanzamos la validación $validada=$this->_isVAlidCreditCard($num,$tipo,false); // Informamos de como ha ido la validación sfContext::getInstance()->getLogger()->info("CCVAL.class.php: Tipo: ".$tipo." Num: ".$num." Validada: ".$validada); if ($validada==false) { $error = $this->getParameterHolder()->get('error'); return false; } return true; } public function initialize ($context, $parameters = null) { // initialize parent parent::initialize($context); $this->getParameterHolder()->add($parameters); return true; } /** * Testing checksum * * @param integer $ccnum * @return boolean */ private function _checkSum($ccnum) { $checksum = 0; for ($i=(2-(strlen($ccnum) % 2)); $i<=strlen($ccnum); $i+=2) { $checksum += (int)($ccnum{$i-1}); } // Analyze odd digits in even length strings or even digits in odd length strings. for ($i=(strlen($ccnum)% 2) + 1; $i<strlen($ccnum); $i+=2) { $digit = (int)($ccnum{$i-1}) * 2; if ($digit < 10) { $checksum += $digit; } else { $checksum += ($digit-9); } } if (($checksum % 10) == 0) return true; else return false; } /** * Launch validation * * @param integer $ccnum * @param string $type * @param boolean $returnobj * @return boolean */ private function _isVAlidCreditCard($ccnum,$type="",$returnobj=false) { $creditcard=array( "visa"=>"/^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/", "mastercard"=>"/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/", "discover"=>"/^6011-?\d{4}-?\d{4}-?\d{4}$/", "amex"=>"/^3[4,7]\d{13}$/", "diners"=>"/^3[0,6,8]\d{12}$/", "bankcard"=>"/^5610-?\d{4}-?\d{4}-?\d{4}$/", "jcb"=>"/^[3088|3096|3112|3158|3337|3528]\d{12}$/", "enroute"=>"/^[2014|2149]\d{11}$/", "switch"=>"/^[4903|4911|4936|5641|6333|6759|6334|6767]\d{12}$/"); if(empty($type)) { $match=false; foreach($creditcard as $type=>$pattern) if(preg_match($pattern,$ccnum)==1) { $match=true; break; } if(!$match) return false; else { if($returnobj) { $return=new stdclass; $return->valid=$this->_checkSum($ccnum); $return->ccnum=$ccnum; $return->type=$type; return $return; } else return $this->_checkSum($ccnum); } } else { if(@preg_match($creditcard[strtolower(trim($type))],$ccnum)==0) return false; else { if($returnobj) { $return=new stdclass; $return->valid=$this->_checkSum($ccnum); $return->ccnum=$ccnum; $return->type=$type; return $return; } else return $this->_checkSum($ccnum); } } } } ?>
An example of how you can call CCVAL validator from validate yml file:
methods: post: [ntarjeta] names: ntarjeta: required: Yes required_msg: Credit Card number is required validators: validarCC validarCC: class: CCVAL param: num: ntarjeta tipo: tipoCC error: Your credit card number is invalid
Sorry for my poor english.
This its a password strength validator, with ajax request for checking the password field.
First create a validator in lib/validators/sfPasswordStrengthValidator.class.php
<?php class sfPasswordStrengthValidator extends sfValidator { public function execute (&$value, &$error) { $weakness = $this->Password_Strength($value); if($weakness==1) { $error = $this->getParameter('strength_error'); return false; } return $weakness; } public function initialize ($context, $parameters = null) { // Initialize parent parent::initialize($context); // Set default parameters value $this->setParameter('strength_error', 'Weak password'); // Set parameters $this->getParameterHolder()->add($parameters); return true; } // Thanks for: Alix Axel Weblog // URL: http://www.alixaxel.com/wordpress/wp-content/2007/06/Password_Strength.phps function Password_Strength($password, $username = null) { if (!empty($username)) { $password = str_replace($username, '', $password); } $strength = 0; $password_length = strlen($password); if ($password_length < 5) { return $strength; } else { $strength = $password_length * 4; } for ($i = 2; $i <= 4; $i++) { $temp = str_split($password, $i); $strength -= (ceil($password_length / $i) - count(array_unique($temp))); } preg_match_all('/[0-9]/', $password, $numbers); if (!empty($numbers)) { $numbers = count($numbers[0]); if ($numbers >= 3) { $strength += 5; } } else { $numbers = 0; } preg_match_all('/[|!@#$%&*\/=?,;.:\-_+~^¨\\\]/', $password, $symbols); if (!empty($symbols)) { $symbols = count($symbols[0]); if ($symbols >= 2) { $strength += 5; } } else { $symbols = 0; } preg_match_all('/[a-z]/', $password, $lowercase_characters); preg_match_all('/[A-Z]/', $password, $uppercase_characters); if (!empty($lowercase_characters)) { $lowercase_characters = count($lowercase_characters[0]); } else { $lowercase_characters = 0; } if (!empty($uppercase_characters)) { $uppercase_characters = count($uppercase_characters[0]); } else { $uppercase_characters = 0; } if (($lowercase_characters > 0) && ($uppercase_characters > 0)) { $strength += 10; } $characters = $lowercase_characters + $uppercase_characters; if (($numbers > 0) && ($symbols > 0)) { $strength += 15; } if (($numbers > 0) && ($characters > 0)) { $strength += 15; } if (($symbols > 0) && ($characters > 0)) { $strength += 15; } if (($numbers == 0) && ($symbols == 0)) { $strength -= 10; } if (($symbols == 0) && ($characters == 0)) { $strength -= 10; } if ($strength < 0) { $strength = 0; } if ($strength > 100) { $strength = 100; } return $strength; } }
Then in your view template use:
<?php echo observe_field('password', array( 'update' => 'passwordStatus', 'url' => 'sfGuardAuth/checkPasswordStrength', 'with' => "'id='+encodeURIComponent($('password').value)", 'loading'=>"Element.show('indicator_passwordstatus')", 'complete'=>"Element.hide('indicator_passwordstatus');Element.show('passwordStatus');", )) ?>
That code will monitor changes at password input field, and submit the updated value to the defined route.
Then add the following to your actions file:
public function executeCheckPasswordStrength() { $password = $this->getRequestParameter('id'); $strengthValidator = new sfPasswordStrengthValidator(); $strengthValidator->initialize($this->getContext()); $error='none'; $score = $strengthValidator->execute($password,$error); if(!$score) return $this->renderText('too short'); if($score < 20) { return $this->renderText('not weak'); } else if($score < 50) { return $this->renderText('relevant'); } else { return $this->renderText('strong'); } return true; }
Cheers
Say you wanted to validate that someone was over 18 years of age, its acutally quite simple once you know what your doing, but it took me a while to work out all the bits, so i thought i would put it in here to save some one a bit of time...
on the template you have
<p> <label for="date_of_birth">Date of Birth:</label> <?php echo form_error('day'); ?> <?php echo form_error('month'); ?> <?php echo form_error('year'); ?> <?php echo select_day_tag('day', $sf_params->get('day')) ?> <?php echo select_month_tag('month', $sf_params->get('month')) ?> <?php echo select_year_tag('year', $sf_params->get('year'),array('year_start'=>'1900','year_end'=>date("Y"))) ?> </p>
in signup.yml (due to the way i built my form, you dont actually need to validate the day and month, since there is no way to leave them empty, but i have put the code in for completness)
methods:
post: [day, month, year, gender]
names:
day:
required: true
required_msg: You must verify your age.
month:
required: true
required_msg: You must verify your age.
year:
required: true
required_msg: You must verify your age.
validators: ageValidator
ageValidator:
class: myAgeValidator
param:
too_young_error: You must be over 18 to enter.
now in /lib/AgeValidator.class.php, we put the code to check the dates.
class myAgeValidator extends sfValidator { public function initialize($context, $parameters = null) { // initialize parent parent::initialize($context