Yii Framework Forum: jformvalidate extension validate required field even when it shouldn't - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

jformvalidate extension validate required field even when it shouldn't Rate Topic: -----

#1 User is offline   Jaime 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 33
  • Joined: 15-August 09

Posted 19 August 2009 - 10:32 PM

Hello..

I have a form that allows to create or update a user.

When the form is in insert mode all works perfect. The problem is when the form is in update mode. The rule says that password field is not required in edit mode and in fact, when the form appears, no asterisk is shown, meaning that YII framework recognize that the field is not required.

When the form is submitted, jformvalidate displays the error telling that password field is required. Is this a bug or there's something I miss to configure?

This is the whole rule for the model:

public function rules()
	{
        return  array(
    		    array('username, nombres, apellidos, email', 'required'),
    		    array('password, password_repeat', 'required', 'on' => 'insert'),
    			array('password','length','max'=>50, 'min'=>6, 'on' => 'insert'),
			    array('password_repeat','length','max'=>50, 'min'=>6, 'on' => 'insert'),
			    array('password_repeat', 'compare', 'compareAttribute'=>'password', 'on' => 'insert'),
    			array('username','length','max'=>50),
    			array('username', 'filter', 'filter'=>'strtolower'), 
    			array('username, nombres, apellidos', 'filter', 'filter'=>'trim'),
    			array('email','length','max'=>80),
    			array('email','email'));
	}


And this is the part of the form that renders the password fields:

<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password'); ?>
<?php echo EHtml::activePasswordField($model,'password',array('value'=>'', 'size'=>50,'maxlength'=>50)); ?>
</div>
<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password_repeat'); ?>
<?php echo EHtml::activePasswordField($model,'password_repeat',array('size'=>50,'maxlength'=>50)); ?>
</div>


Any help will be greatly appreciated

Thanks
Jaime
0

#2 User is offline   pestaa 

  • past Yii dev member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 705
  • Joined: 07-May 09
  • Location:Hungary

Posted 20 August 2009 - 04:17 AM

View PostJaime, on 19 August 2009 - 10:32 PM, said:

no asterisk is shown, meaning that YII framework recognize that the field is not required.

Are you sure?

echo EHtml::activePasswordField($model,'password',array('value'=>'', 'size'=>50,'maxlength'=>50));
0

#3 User is offline   Jaime 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 33
  • Joined: 15-August 09

Posted 20 August 2009 - 08:27 AM

Yes... I have to add that because when I am in edit mode, I don't want the password field to be filled. If that is the cause of the problem, how can I avoid the password to be filled automatically? if I use EHtml::passwordField the field is not filled but it is not connected to the database.

The password field is shown in update page so that a user can change the password. If he doesn't enter nothing into that field, the password must remain intact.

Jaime


View Postpestaa, on 20 August 2009 - 04:17 AM, said:

Are you sure?

echo EHtml::activePasswordField($model,'password',array('value'=>'', 'size'=>50,'maxlength'=>50));

0

#4 User is offline   pestaa 

  • past Yii dev member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 705
  • Joined: 07-May 09
  • Location:Hungary

Posted 20 August 2009 - 08:36 AM

Make password and password_repeat unsafe in update scenario (so your safeAttributes might look like this: array(... 'insert'=>'password, password_repeat', ...)).

This way it won't be overwritten by massive assignment. ($user->attributes=...)

However, you still have to handle the case when these fields are filled.
0

#5 User is offline   Jaime 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 33
  • Joined: 15-August 09

Posted 21 August 2009 - 08:17 PM

Hello... I have done it, but safeAttributes function is not called when form appears. The password field is filled with something (actually, the md5 value stored in the database) when the update form appears.

How can avoid that?
Jaime


View Postpestaa, on 20 August 2009 - 08:36 AM, said:

Make password and password_repeat unsafe in update scenario (so your safeAttributes might look like this: array(... 'insert'=>'password, password_repeat', ...)).

This way it won't be overwritten by massive assignment. ($user->attributes=...)

However, you still have to handle the case when these fields are filled.

0

#6 User is offline   pestaa 

  • past Yii dev member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 705
  • Joined: 07-May 09
  • Location:Hungary

Posted 22 August 2009 - 04:13 AM

In this case you should avoid activeTextField.

Use something like: CHtml::textField('User[password & password_repeat]', '', ...); so that it fits your active elements (check the generated source if you're not sure).
0

#7 User is offline   Jaime 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 33
  • Joined: 15-August 09

Posted 22 August 2009 - 11:47 AM

Hello.... that partially worked.. I finally wrote:

<?php if ($update) :?>
<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password'); ?>
<?php echo EHtml::passwordField('Usuario[password]','',array('size'=>50,'maxlength'=>50)); ?>
</div>
<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password_repeat'); ?>
<?php echo EHtml::passwordField('Usuario[password_repeat]','',array('size'=>50,'maxlength'=>50)); ?>
</div>
<?php else: ?>
<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password'); ?>
<?php echo EHtml::activePasswordField($model,'password',array('size'=>50,'maxlength'=>50)); ?>
</div>
<div class="simple">
<?php echo EHtml::activeLabelEx($model,'password_repeat'); ?>
<?php echo EHtml::activePasswordField($model,'password_repeat',array('size'=>50,'maxlength'=>50)); ?>
</div>
<?php endif; ?>


But I have problems again with jformvalidate extension. It validates the passwords to have certain length, but if I enter "password" field, "password_repeat" field is not compared to "password" field if "password_repeat" is empty.

These are the validation rules:

	public function rules()
	{
        return  array(
    		    array('username, nombres, apellidos, email', 'required'),
    		    array('password, password_repeat', 'required', 'on' => 'insert'),
    			array('password','length','max'=>50, 'min'=>6),
			    array('password_repeat','length','max'=>50, 'min'=>6),
			    array('password_repeat', 'compare', 'compareAttribute'=>'password'),
    			array('username','length','max'=>50),
    			array('username', 'filter', 'filter'=>'strtolower'), 
    			array('username, nombres, apellidos', 'filter', 'filter'=>'trim'),
    			array('email','length','max'=>80),
    			array('email','email'));
	}


Then I tried by modifying safeAttributes method this way:

       return array('username, nombres, apellidos, administrador, email, password_repeat',
                     'insert'=> 'password',
                     'login' => 'username, password');


The password_repeat validates false, even if the password and password_repeat are the same.

I think this is the last problem to solve in order to finish the user administration form :rolleyes:

I'm wondering why documentation says nothing about this, although this is a very common task in user administration.

Thanks
Jaime

View Postpestaa, on 22 August 2009 - 04:13 AM, said:

In this case you should avoid activeTextField.

Use something like: CHtml::textField('User[password & password_repeat]', '', ...); so that it fits your active elements (check the generated source if you're not sure).

0

#8 User is offline   Raoul 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 636
  • Joined: 29-November 08
  • Location:Paris, France

Posted 23 August 2009 - 03:46 PM

Hi Jaime,
I will take a look to this issue as soon as possible and if needed, release a new version with a fix.
I'll keep you inform
ciao
8)
0

#9 User is offline   Raoul 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 636
  • Joined: 29-November 08
  • Location:Paris, France

Posted 25 August 2009 - 12:33 PM

Hi Jaime,
after some investigation, I may have found a small bug on the current jformvalidate version on the way rules are applied depending in the scenario (or more exactly, the absence of scenario). Anyway, I wrote a small sample to reproduce the incorrect behavior you described (see below). With the attached version of the EJFValidate.php file the behaviour was (I think) correct. So please, could you try to replace your version of EJFValidate.php (it is located in protected/extensions/jformvalidate) by the one attached to this post and let me know if it works. If it does, I'll release a new version this week-end.

ciao
8)


Here is the model (I use a CFormModel based model for the sample) :
models/UserForm.php
class UserForm extends CFormModel
{
	public $name;
	public $password;
	public $password_repeat;
	
	public function rules()
	{
		return array(
			array('name', 'required'),
			array('password', 'required', 'on' => 'insert'),
			array('password','compare', 'compareAttribute' => 'password_repeat'),
		);
	}
}


..and here are the view files both for create (insert) and update :
views/site/createUser.php
<h2>Create User</h2>
<?php 
	
	$this->renderPartial('_form', array(
		'user'=>$form,
		'update'=>false,
	)); 
?>

views/site/updateUser.php
<h2>Update User</h2>
<?php 
	$this->renderPartial('_form', array(
		'user'=>$form,
		'update'=>true,
	)); 
?>


views/site/_form.php
<div class="yiiForm">
<?php echo EHtml::beginForm(); ?>
<?php		
	
	EHtml::setScenario(($update ? '':'insert'));
	EHtml::setOptions(array(
		'errorContainer'=> "div.container",
		'wrapper' => 'li',
		'errorLabelContainer' => "div.container ul",
		'errorClass' => "invalid",	
		'onkeyup' 				=> false,
		'onfocusout' 			=> false
	));
?>


<?php echo EHtml::errorSummary($user); ?>
<div class="container errorSummary" style="display:none">
	<p>Please fix the following input errors:</p>
	<ul>
	</ul>
</div>
<div class="simple">
<?php echo EHtml::activeLabel($user,'name'); ?>
<?php echo EHtml::activeTextField($user,'name',array('size'=>20,'maxlength'=>128)); ?>
</div>
<div class="simple">
<?php echo EHtml::activeLabel($user,'password'); ?>
<?php echo EHtml::activeTextField($user,'password',array('rows'=>20, 'cols'=>50)); ?>
</div>
<div class="simple">
<?php echo EHtml::activeLabel($user,'password_repeat'); ?>
<?php echo EHtml::activeTextField($user,'password_repeat',array('rows'=>20, 'cols'=>50)); ?>
</div>
<div class="action">
<?php echo EHtml::submitButton($update ? 'Save' : 'Create', array('name'=>'submitPost')); ?>
</div>

<?php echo EHtml::endForm(); ?>
</div>


..and eventually the controller Action :
	public function actionCreateUser()
	{
		$form=new UserForm;
		$form->scenario = 'insert';
		// collect user input data
		if(isset($_POST['UserForm']))
		{
			$form->attributes=$_POST['UserForm'];
			// validate user input and redirect to previous page if valid
			if($form->validate())
				$this->redirect(Yii::app()->user->returnUrl);
		}
		// display the login form
		$this->render('createUser',array('form'=>$form));
	}
	public function actionUpdateUser()
	{
		$form=new UserForm;
		//$form->scenario = 'update';
		$form->name     = 'theUserName';
		
		// collect user input data
		if(isset($_POST['UserForm']))
		{
			$form->attributes=$_POST['UserForm'];
			// validate user input and redirect to previous page if valid
			if($form->validate())
				$this->redirect(Yii::app()->user->returnUrl);
		}
		// display the login form
		$this->render('updateUser',array('form'=>$form));
	}	

Attached File(s)


0

#10 User is offline   Jaime 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 33
  • Joined: 15-August 09

Posted 27 August 2009 - 09:52 PM

Hi Raoul !! and thanks for answering.

That problem was solved after I replaced the PHP file with the file you modified. But I got another problem, however this is not related to jformvalidation, I think, but maybe you have the answer :rolleyes:

After the form is submitted and if I leave password fields empty, the password is also cleared in the database table.

Trying to solve it, I used this in safeAttributes method:

return array('username, nombres, apellidos, administrador, email, password_repeat',
             'insert'=> 'password',
             'login' => 'username, password');


If I do that, form validation thinks that password_repeat is not equal to password, so it throws the corresponding error.

The original safeAttributes was:

return array('username, nombres, apellidos, administrador, email, password, password_repeat',
             'login' => 'username, password');


but in this case, validation succeeds, but if password is left blank, it is cleared also in database.

Do you know how to solve this?

Thanks a lot
Jaime
0

#11 User is offline   Raoul 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 636
  • Joined: 29-November 08
  • Location:Paris, France

Posted 29 August 2009 - 08:29 AM

Hola Jaime,
safeAttribute is used to define which ones are the attributes that can be massively assigned depending on the scenario. In your case, it seems to me that if scenario can be used for validation, it is not appropriated for attribute update. The fact that the password should be saved to DB does not only depend on the scenario, but also on the password value.
If I understand well, here is what we've got :

  • scenario : insert - password is always saved to DB
  • scenario : update - password is saved to DB only if not empty


So, to implement this, when in update scenario, I would test if the password is empty, and if yes, call the CActiveRecord.save() method, otherwise call the CActiveRecord.saveAttributes() method in order to save all updated attribute except the password.
If there's a better way to do this, I'll be glad to learn ...

Hope this helps
ciao
8)
0

#12 User is offline   Mike 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 3,013
  • Joined: 06-October 08
  • Location:Upper Palatinate

Posted 29 August 2009 - 09:47 AM

View PostRaoul, on 29 August 2009 - 08:29 AM, said:

So, to implement this, when in update scenario, I would test if the password is empty, and if yes, call the CActiveRecord.save() method, otherwise call the CActiveRecord.saveAttributes() method in order to save all updated attribute except the password.
If there's a better way to do this, I'll be glad to learn ...


Usually passwords should never be saved unencrypted in DB for security reasons. Therefore i would split the job up. Lets say we have a field crypted_password in DB. This can never be assigned from a form, so never use it in safeAttributes().

1. Instead we add a "virtual attribute" $password to the model (not a DB field!):

 class User extends CActiveRecord {
    public $password;
   ...
 


We can now use scenarios to define when this attribute can be massively assigned and which validation rules should apply.

2. Use beforeSafe() to only set/overwrite crypted_password when $password was set:

public function beforeSave() {
     if (!empty($this->password))
         $this->crypted_password=md5($this->password);
     return true;
 }
 


That way, the old value of crypted_password stays unchanged if $password was not set.
0

#13 User is offline   Raoul 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 636
  • Joined: 29-November 08
  • Location:Paris, France

Posted 29 August 2009 - 12:49 PM

That is indeed a much cleaner and better way to handle this case.
thanks Mike
8)
0

#14 User is offline   iridescent 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 14-November 13

Posted 14 November 2013 - 04:56 AM

Hello guys i am fairly new to the yii framework. So, i have a beforeSave function to my user.php file that hashes the password when a new user is created and it works fine.
protected function beforeSave()
        {
            if(parent::beforeSave())
            {
                if($this->isNewRecord)
                {
                    $this->salt = utf8_encode( mcrypt_create_iv(30) );
                    $newPassword = utf8_encode( crypt($this->password, $this->salt) );
                    $this->password = $newPassword;
                }
                return true;
            }
            else
                return false;
        }


But when i update an existing user's password, it is stored to the database unhashed... what can i do?
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users