We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Model skipAttributesOnUpdate fails

Hello everyone. Quick question. I am making an email activation of a user after registration and after a user goes to an email sent to him I want to update a column Active in database and set it to 1. However, on update the password gets validated once again because it has to be 8-16 chars, but when I grab user from db to update the password is hashed and is 60 chars in length. I have set the skipAttributesOnUpdate in my initializer of a model, but the password stil gets updated. So is it a bug or I am doing something wrong? The model code :

public function initialize()
{
    $this->hasMany("id", "Achievement", "UserID", NULL);
    $this->hasMany("id", "Message", "FromUser", NULL);
    $this->hasMany("id", "Message", "ToUser", NULL);
    $this->hasMany("id", "Profile", "UserID", NULL);
    $this->hasMany("id", "Record", "Creator", NULL);
    $this->hasMany("id", "Userrelationship", "UserID", NULL);
    $this->hasMany("id", "Userrelationship", "ContactUserID", NULL);
    $this->hasMany("id", "Wall", "UserID", NULL);
    $this->skipAttributesOnUpdate(['Password']);
    //$this->useDynamicUpdate(true);
}

public function validation()
{

    /*
        Validate Email Uniquness
     */
    $this->validate(new Regex([
        'field'     =>  'Name',
        'message'   => 'Name must contain only letters and must be longer than 2 characters',
        'pattern'   => '/^[a-zA-Z]{2,}$/'
    ]));

    $this->validate(new Regex([
        'field'     =>  'LastName',
        'message'   => 'Lastname must contain only letters and must be longer than 2 characters',
        'pattern'   => '/^[a-zA-Z]{2,}$/'
    ]));

    $this->validate(new PresenceOf([
        'field'     =>  'Email',
        'message'   =>  'Email can\'t be empty'
    ]));
    $this->validate(new Email([
        'field'     =>  'Email',
        'message'   =>  'Invalid email format'
    ]));

    $this->validate(new StringLength([
        'field'     =>  'Password',
        'min'       =>  8,
        'max'       =>  16,
        'messageMinimum'=>  'Password must be at least 8 characters long',  
        'messageMaximum'=>  'Password must not exceed 16 characters'    
    ]));
    $res = $this->validationHasFailed();
    return  $this->validationHasFailed() == false;

}  

public function beforeCreate () 
{
    $this->Password = password_hash($this->Password, PASSWORD_BCRYPT);

}

In controller the activation action

public function ActivateAccountAction($email, $activationCode)
{
    $email = trim($email);
    $code = trim($activationCode);

    $user = User::query()
                    ->where(' Email = :email:', ['email' => $email])
                    ->andWhere(' ActivationCode = :activationCode:', ['activationCode' => $activationCode])
                    ->andWhere(' Active = 0')
                    ->execute()
                    ->getFirst();

    if ($user->Email == $email && $user->ActivationCode == $code) 
    {
        $user->save(['Active'   =>  1]);

    } else {
        $this->flash->error('Invalid email or activation code');

    }
    return $this->response->redirect('Signin/ActivationResult');
}

Does anyone know what can be causing a problem ?



98.9k
edited Jul '14

A password generated by password_hash($this->Password, PASSWORD_BCRYPT) will produce a 60 char length string which is validated by StringLength that only allow strings between 8 and 16 characters.

You can enable that validation only when the record is being updated this way:

if (!$this->id) {
    $this->validate(new StringLength([
        'field'     =>  'Password',
        'min'       =>  8,
        'max'       =>  16,
        'messageMinimum'=>  'Password must be at least 8 characters long',
        'messageMaximum'=>  'Password must not exceed 16 characters'
    ]));
}

or

if ($this->getDirtyState() != \Phalcon\Mvc\Model::DIRTY_STATE_PERSISTENT) {
    $this->validate(new StringLength([
        'field'     =>  'Password',
        'min'       =>  8,
        'max'       =>  16,
        'messageMinimum'=>  'Password must be at least 8 characters long',
        'messageMaximum'=>  'Password must not exceed 16 characters'
    ]));    
}


28.4k

Great, thanx. But would the validation will be called even if I call $this->skipAttributesOnUpdate(['Password']);

Or

$this->useDynamicUpdate(true);