Checking if at least one field is set using CakePHP 3 validation - php

I am trying to write a validation rule in CakePHP 3 that checks, if the prename and lastname OR the company name is set.
Validators:
$validator
->add('prename', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('lastname', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('name', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
Rule definition:
public function validateName($check, array $context)
{
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return true;
} else {
return false;
}
}
But the validation does not behave as expected. If I enter the company name, I get validation errors for prename and lastname saying that the fields is required. Same when I enter the prename and lastname, it says the company name is required.
What am I doing wrong?

I have also faces this type of weird behaviors with cakePhp 3.x.I manage to solve this problem.
Below is the code to solve the asked question
$validator
->notEmpty('company_name', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('prename', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('lastname', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
I hope this will be the solution for your problem.

The provided answers all did not work 100%, so I am going to post what I have come up with. I am using conditional validation as described in the CakePHP 3 docs.
CustomersTable.php:
public function validationDefault(Validator $validator)
{
$validator->notEmpty('name', __("Required when prename and lastname is empty."), function ($context) {
return !$context['data']['prename'] && !$context['data']['lastname'];
});
$validator->notEmpty('prename', __('Required when company or lastname is empty.'), function ($context) {
return !$context['data']['name'];
});
$validator->notEmpty('lastname', __('Required if company or prename is empty.'), function ($context) {
return !$context['data']['name'];
});
return $validator;
}
This approach correctly validates the data when it is submitted. However, some browsers say that those fields have to be filled because they are required. To avoid that, we have to define the fields as required => false:
add.ctp view file:
echo $this->Form->input('prename', [
'label' => ['text' => __('Prename (*): ')],
'required' => false,
]);
echo $this->Form->input('lastname', [
'label' => ['text' => __('Lastname (*): ')],
'required' => false,
]);
echo $this->Form->input('name', [
'label' => ['text' => __('Company name (*): ')],
'required' => false,
]);

We have the following code running in production, which is much alike yours:
$validator
->add('various_fee_text', 'custom', [
'rule' => [$this, 'variousFieldsChecker'],
'message' => __('Udfyld både Tekst og DKK feltet'),
])
->allowEmpty('various_fee_text');
Vaildation rule:
/**
* Method checks whether or not various fee text and various fee prices are either both empty, both set or "dirt",
* meaning only one of them is set and the other is empty. We want either both to be set or both to be empty.
*
* #return bool depending on it's OK or not
*/
public function variousFieldsChecker($value, $context)
{
$varioustext = $context['data']['various_fee_text'];
$variousPrice = $context['data']['various_fee_price'];
if (!empty($varioustext) && !empty($variousPrice)) {
return true;
} elseif ((empty($varioustext) && empty($variousPrice))) {
return true;
}
return false;
}
I think what you need is to append the ->allowEmpty() like suggested previously.

For this CakePhp provide create custom validation. You need to create two validation function on your model class and call them conditionally on controller function. You can create validation function like as
public function validationName($validator){
$validator
->requirePresence('prename')
->notEmpty('prename', 'Prename must be set.')
->requirePresence('lastname')
->notEmpty('lastname', 'Lastname must be set.')
->allowEmpty('name');
return $validator;
}
public function validationCompany($validator){
$validator
->requirePresence('name')
->notEmpty('name', 'Company name must be set.')
->allowEmpty('prename')
->allowEmpty('lastname');
return $validator;
}
On controller you can call these function conditionally like as
$validator = 'company';
if(empty($this->request->data[''])){
$validator = 'name';
}
$entity = $this->{$this->modelClass}->newEntity();
$entitydata = $this->{$this->modelClass}->patchEntity($entity, $this->request->data, ['validate' => $validator]);
$this->{$this->modelClass}->save($entitydata);

Related

CodeIgniter 4 Model Callbacks not hashing password before insert

I am totally new to CI4 but do have some experience with PHP. I having trouble getting the Model class callback functions to work when inserting a new user row.
Here is the Controller:
<?php use App\Models\UserModel;
class Users extends BaseController
{
public $users_model;
public function __construct() {
$this->users_model = new UserModel();
}
public function register() {
$data = [
'page_title' => 'Register An Account',
'validation' => NULL //must have this set to null until/if any validation rules are broken
];
if ($this->request->getMethod() == 'post') {
//validation rules
$rules = [
'username' => [
'rules' => 'required|min_length[4]|max_length[20]|validateUsername[username]',
'errors' => [
'required' => 'A username is required',
'min_length' => 'Username must be at least {param} characters long',
'max_length' => 'Username cannot be more than {param} characters long',
'validateUsername' => 'Username can only contain letters and numbers',
],
] ,
'email' => [
'rules' => 'required|valid_email|is_unique[users.email]',
'errors' => [
'required' => 'An Email is required',
'valid_email' => 'Enter a valid email',
'is_unique' => 'That email has already been registerd',
],
],
'password' => [
'rules' => 'required|min_length[6]|max_length[16]|validatePassword[password]',
'errors' => [
'required' => 'A password is required',
'min_length' => 'Password must contain at least {param} characters',
'max_length' => 'Password cannot be more than {param} characters in length',
'validatePassword' => 'Password must have at least 1 numeric value',
],
],
'confirm_password' => [
'rules' => 'required|matches[password]',
'errors' => [
'required' => 'Must confirm password',
'matches' => 'Passwords do not match'
],
]
];
if ($this->validate($rules)) {
//all fields passed validation so need to save to the db
$user_data = [
'username' => $this->request->getVar('username', FILTER_SANITIZE_STRING),
'email' => $this->request->getVar('email', FILTER_SANITIZE_EMAIL),
'password' => $this->request->getVar('password')
];
if ($this->users_model->createUser($user_data)) {
echo 'user stored in the db.';
} else {
echo 'user not stored in the db.';
}
} else {
//there are some validation errors
$data['validation'] = $this->validator;
}
}//post request check ends here
return view('users/register', $data);
}// register method ends here.
public function login() {
$data = [
'page_title' => 'Login'
];
return view('users/login', $data);
}
public function logout() {
//not implemented yet
}
}
And here is the Model class:
<?php
namespace App\Models;
use CodeIgniter\Model;
class UserModel extends Model
{
protected $table = 'users';
protected $allowedFields = ['username', 'email', 'password'];
protected $beforeInsert = ['beforeInsert'];
protected $beforeUpdate = ['beforeUpdate'];
protected $allowCallbacks = TRUE;
protected $builder;
public function createUser(array $data) {
$this->builder = $this->db->table($this->table);
$this->db->transStart();
$this->builder->insert($data);
$this->db->transComplete();
if($this->db->affectedRows() == 1) {
return TRUE;
} else {
return FALSE;
}
}
protected function beforeInsert(array $data) {
if (isset($data['data']['password']))
$data['data']['password'] = password_hash($data['data']['password'], PASSWORD_DEFAULT);
return $data;
}
protected function beforeUpdate(array $data) {
if (isset($data['data']['password']))
$data['data']['password'] = password_hash($data['data']['password'], PASSWORD_DEFAULT);
return $data;
}
}
What is weird to me is that the record does get stored in the database but the password is plain text and not hashed. Also, in the controller class, the if statement:
if ($this->users_model->createUser($user_data)) {
echo 'user stored in the db.';
} else {
echo 'user not stored in the db.';
}
Always echo's the 'user not stored in the db' message and the user is stored in the db.
In the model:
if($this->db->affectedRows() == 1) {
return TRUE;
} else {
return FALSE;
}
I have echoed out the result of $this->db->affectedRows()
and it is 1 on a successful insert (although the password is not hashed) so I thought this would cause the method to return true, therefore over in the controller, I would see the truthy part of the if condition, 'user stored in the db'.
Can anyone tell me where I am going wrong in all of this?
I have successfully used the password_hash() function in the controller itself on the $this->request->getVar('password') data so I know it works. But I wanted to leverage the in-built Model callbacks and take care of the hashing for inserts and updates there.
I have also shared/posted this question in the CodeIgniter forums as well.
Thanks for any help.
Codeigniter4 documentation is not really clear about it, but whenever you want a model callback to be triggered, you need to use directly the model functions and not the builder ones.
For example, inside your model, using $this->builder->insert() will NOT trigger the beforeInsert nor the afterInsert functions of your model but using $this->insert() will do the trick.
So in your case you should replace your createUser function with
public function createUser(array $data) {
$this->db->transStart();
$this->insert($data);
$this->db->transComplete();
if ($this->db->affectedRows() == 1) {
return TRUE;
} else {
return FALSE;
}
}

Custom Laravel validation messages

I'm trying to create customized messages for validation in Laravel 5. Here is what I have tried so far:
$messages = [
'required' => 'Harap bagian :attribute di isi.',
'unique' => ':attribute sudah digunakan',
];
$validator = Validator::make($request->all(), [
'username' => array('required','unique:Userlogin,username'),
'password' => 'required',
'email' => array('required','unique:Userlogin,email'),$messages
]);
if ($validator->fails()) {
return redirect('/')
->withErrors($validator) // send back all errors to the login form
->withInput();
} else {
return redirect('/')
->with('status', 'Kami sudah mengirimkan email, silahkan di konfirmasi');
}
But it's not working. The message is still the same as the default one. How can I fix this, so that I can use my custom messages?
Laravel 5.7.*
Also You can try something like this. For me is the easiest way to make custom messages in methods when you want to validate requests:
public function store()
{
request()->validate([
'file' => 'required',
'type' => 'required'
],
[
'file.required' => 'You have to choose the file!',
'type.required' => 'You have to choose type of the file!'
]);
}
If you use $this->validate() simplest one, then you should write code something like this..
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.'
];
$this->validate($request, $rules, $customMessages);
You can provide custom message like :
$rules = array(
'URL' => 'required|url'
);
$messages = array(
'URL.required' => 'URL is required.'
);
$validator = Validator::make( $request->all(), $rules, $messages );
if ( $validator->fails() )
{
return [
'success' => 0,
'message' => $validator->errors()->first()
];
}
or
The way you have tried, you missed Validator::replacer(), to replace the :variable
Validator::replacer('custom_validation_rule', function($message, $attribute, $rule, $parameters){
return str_replace(':foo', $parameters[0], $message);
});
You can read more from here and replacer from here
For Laravel 8.x, 7.x, 6.x
With the custom rule defined, you might use it in your controller validation like so :
$validatedData = $request->validate([
'f_name' => 'required|min:8',
'l_name' => 'required',
],
[
'f_name.required'=> 'Your First Name is Required', // custom message
'f_name.min'=> 'First Name Should be Minimum of 8 Character', // custom message
'l_name.required'=> 'Your Last Name is Required' // custom message
]
);
For localization you can use :
['f_name.required'=> trans('user.your first name is required'],
Hope this helps...
$rules = [
'username' => 'required,unique:Userlogin,username',
'password' => 'required',
'email' => 'required,unique:Userlogin,email'
];
$messages = [
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
];
$request->validate($rules,$messages);
//only if validation success code below will be executed
//Here is the shortest way of doing it.
$request->validate([
'username' => 'required|unique:Userlogin,username',
'password' => 'required',
'email' => 'required|unique:Userlogin,email'
],
[
'required' => 'The :attribute field is required.',
'unique' => ':attribute is already used'
]);
//The code below will be executed only if validation is correct.
run below command to create a custom rule on Laravel
ı assuming that name is CustomRule
php artisan make:rule CustomRule
and as a result, the command was created such as PHP code
if required keyword hasn't on Rules,That rule will not work
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//return true or false
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
}
}
and came time using that
first, we should create a request class if we have not
php artisan make:request CustomRequest
CustomRequest.php
<?php
namespace App\Http\Requests\Payment;
use App\Rules\CustomRule;
use Illuminate\Foundation\Http\FormRequest;
class CustomRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules(): array
{
return [
'custom' => ['required', new CustomRule()],
];
}
/**
* #return array|string[]
*/
public function messages(): array
{
return [
'custom.required' => ':attribute can not be empty.',
];
}
}
and on your controller, you should inject custom requests to the controller
your controller method
class FooController
{
public function bar(CustomRequest $request)
{
}
}
You can also use the methods setAttributeNames() and setCustomMessages(),
like this:
$validation = Validator::make($this->input, static::$rules);
$attributeNames = array(
'email' => 'E-mail',
'password' => 'Password'
);
$messages = [
'email.exists' => 'No user was found with this e-mail address'
];
$validation->setAttributeNames($attributeNames);
$validation->setCustomMessages($messages);
For those who didn't get this issue resolve (tested on Laravel 8.x):
$validated = Validator::make($request->all(),[
'code' => 'required|numeric'
],
[
'code.required'=> 'Code is Required', // custom message
'code.numeric'=> 'Code must be Number', // custom message
]
);
//Check the validation
if ($validated->fails())
{
return $validated->errors();
}
$rules = [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|max:250',
];
$customMessages = [
'required' => 'The :attribute field is required.',
'max' => 'The :attribute field is may not be greater than :max.'
];
$this->validate($request, $rules, $customMessages);
In the case you are using Request as a separate file:
public function rules()
{
return [
'preparation_method' => 'required|string',
];
}
public function messages()
{
return [
'preparation_method.required' => 'Description is required',
];
}
Tested out in Laravel 6+
you can customise the message for different scenarios based on the request.
Just return a different message with a conditional.
<?php
namespace App\Rules;
use App\Helpers\QueryBuilderHelper;
use App\Models\Product;
use Illuminate\Contracts\Validation\Rule;
class ProductIsUnique implements Rule
{
private array $attributes;
private bool $hasAttributes;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct(array $attributes)
{
$this->attributes = $attributes;
$this->hasAttributes = true;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
$brandAttributeOptions = collect($this->attributes['relationships']['brand-attribute-options']['data'])->pluck('id');
$query = Product::query();
$query->when($brandAttributeOptions->isEmpty(), function ($query) use ($value) {
$query->where('name', $value);
$this->hasAttributes = false;
});
return !$query->exists();
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return ($this->hasAttributes) ? 'The Selected attributes & Product Name are not unique' : 'Product Name is not unique';
}
}
Laravel 10.x
If you are using Form Requests, add another method called messages(): array in your request.
class YourRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required',
'email' => 'required|email',
...
];
}
//Add the following method
public function messages(): array
{
return [
'email.required' => 'Custom message for Email Required',
];
}
}
Then the message will be displayed automatically once the request is send from the form.

Yii2: Either one field is required Validation

I have to implement the validation as mentioned in the title that either one of the two fields (email, phone) is required. I am doing this in my model:
[['email'],'either', ['other' => ['phone']]],
And this is the method:
public function either($attribute_name, $params) {
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->$params['other'])) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
return false;
}
return true;
}
When I access my index page, it gives me this error:
Exception (Unknown Property) 'yii\base\UnknownPropertyException' with
message 'Setting unknown property: yii\validators\InlineValidator::0'
Any help?
If you don't care that both fields show an error when the user provides neither of both fields:
This solutions is shorter than the other answers and does not require a new validator type/class:
$rules = [
['email', 'required', 'when' => function($model) { return empty($model->phone); }],
['phone', 'required', 'when' => function($model) { return empty($model->email); }],
];
If you want to have a customized error message, just set the message option:
$rules = [
[
'email', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->phone); }
],
[
'phone', 'required',
'message' => 'Either email or phone is required.',
'when' => function($model) { return empty($model->email); }
],
];
The rule should be:
['email', 'either', 'params' => ['other' => 'phone']],
And method:
public function either($attribute_name, $params)
{
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->{$params['other']})) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
}
}
Improved variant
['gipsy_team_name', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => 'poker_strategy_nick_name']],
['vkontakte', 'either', 'skipOnEmpty'=>false, 'params' => ['other' => ['odnoklasniki','odnoklasniki']]],
Added 'skipOnEmpty'=>false for forcing validating and 'other' can be array
/**
* validation rule
* #param string $attribute_name
* #param array $params
*/
public function either($attribute_name, $params)
{
/**
* validate actula attribute
*/
if(!empty($this->$attribute_name)){
return;
}
if(!is_array($params['other'])){
$params['other'] = [$params['other']];
}
/**
* validate other attributes
*/
foreach($params['other'] as $field){
if(!empty($this->$field)){
return;
}
}
/**
* get attributes labels
*/
$fieldsLabels = [$this->getAttributeLabel($attribute_name)];
foreach($params['other'] as $field){
$fieldsLabels[] = $this->getAttributeLabel($field);
}
$this->addError($attribute_name, \Yii::t('poker_reg', 'One of fields "{fieldList}" is required.',[
'fieldList' => implode('"", "', $fieldsLabels),
]));
}

How to use sometimes rule in Laravel 5 request class

I have the following request class:
<?php namespace App\Http\Requests\User;
use App\Http\Requests\Request;
use Validator;
use Session;
use Auth;
use App\User;
class RegisterStep1Request extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Set up the validation rules
*/
public function rules()
{
Validator::extend('valid_date', function($attribute, $value, $parameters)
{
$pieces = explode('/', $value);
if(strpos($value, '/')===FALSE) {
return false;
} else {
if(checkdate($pieces[1], $pieces[0], $pieces[2])) {
return true;
} else {
return false;
}
}
});
return [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|email|unique:users,email',
'dob' => 'required|regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/|valid_date',
'mobile' => 'required',
'password' => 'required|confirmed'
];
}
public function messages()
{
return [
'first_name.required' => 'The first name field is required.',
'last_name.required' => 'The last name field is required.',
'email.required' => 'The email address field is required.',
'email.email' => 'The email address specified is not a valid email address.',
'email.unique' => 'The email address is already registered with this website.',
'dob.required' => 'The date of birth field is required.',
'dob.regex' => 'The date of birth is invalid. Please use the following format: DD/MM/YYYY.',
'dob.valid_date' => 'The date of birth is invalid. Please check and try again.',
'mobile.required' => 'The mobile number field is required.',
'password.required' => 'The password field is required.',
'password.confirmed' => 'The confirm password field does not match the password field.'
];
}
}
I want to add the following sometimes rule:
Validator::sometimes('dob', 'valid_date', function($input)
{
return apply_regex($input->dob) === true;
});
How would I add this to my request class?
I have amended my rules method to the following:
public function rules()
{
Validator::extend('valid_date', function($attribute, $value, $parameters)
{
$pieces = explode('/', $value);
if(strpos($value, '/')===FALSE) {
return false;
} else {
if(checkdate($pieces[1], $pieces[0], $pieces[2])) {
return true;
} else {
return false;
}
}
});
Validator::sometimes('dob', 'valid_date', function($input)
{
return apply_regex($input->dob) === true;
});
return [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|email|unique:users,email',
'dob' => 'sometimes|required|regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/|valid_date',
'mobile' => 'required',
'password' => 'required|confirmed'
];
}
But I now get the following error when I submit the form:
FatalErrorException in Facade.php line 216:
Call to undefined method Illuminate\Validation\Factory::sometimes()
There is a documented way to make changes to the request's validator instance in Laravel 5.4. You should implement the withValidator method for that.
Based on the example from #lukasgeiter's answer, you may add the following to your request class:
/**
* Configure the validator instance.
*
* #param \Illuminate\Validation\Validator $validator
* #return void
*/
public function withValidator($validator)
{
$validator->sometimes('dob', 'valid_date', function ($input) {
return apply_regex($input->dob) === true;
});
}
By doing this you don't have to worry about overriding internal methods. Besides, this seems to be the official way for configuring the validator.
You can attach a sometimes() rule by overriding the getValidatorInstance() function in your form request:
protected function getValidatorInstance(){
$validator = parent::getValidatorInstance();
$validator->sometimes('dob', 'valid_date', function($input)
{
return apply_regex($input->dob) === true;
});
return $validator;
}
You just need to add the dob key to the array you are returning, along with the validation ruleset to follow, including sometimes.
In this case:
'dob' : 'sometimes|required|regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/|valid_date'
According to your comment
I want the rule valid_date to only run if the regex rule returns true. Otherwise
the valid_date rule errors if the date isnt in the right format.
Validator::extend('valid_date', function($attribute, $value, $parameters)
{
\\use the regex here instead
if (!preg_match('/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/', $value)) return false;
$pieces = explode('/', $value);
if(strpos($value, '/')===FALSE) {
return false;
} else {
if(checkdate($pieces[1], $pieces[0], $pieces[2])) {
return true;
} else {
return false;
}
}
});
$validator = Validator::make($data, [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|email|unique:users,email',
'dob' => 'required|valid_date',
'mobile' => 'required',
'password' => 'required|confirmed'
]);

CakePHP - Password confirmation not allowing user to submit registration

I'm trying to set up validation for user registration but I'm having troubles. When I only have the email,role and password fields in the $validation array (remove the others) it works and will save a new user. When I try to add the other fields it fails and gives the flash message error "The user could not be saved. Please, try again."
I'm pretty sure it's the re_password check. When I remove the validation for that it works. However, the re_password validation does display an error when the passwords are different, so I'm not sure where to look
Here's my users table
id | email | password | location | website | role | created | modified
Here's the validation requirements. To get it to save a new user I have to remove everything but email, password and role.
public $validate = array(
'email' => 'email'
,
'password' => array(
'required' => array(
'rule' => array('minLength', '8'),
'message' => 'A password with a minimum length of 8 characters is required'
)
),
're_password' => array(
'required' => array(
'rule' => array('equalTo', 'password' ),
'message' => 'Both password fields must be filled out'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
),
'location' => array(
'valid' => array(
'rule' => array('notEmpty'),
'message' => 'Please select a location'
)
)
);
Here's the form (the options array is above, figured it's not necessary to show)
echo $this->Form->input('email');
echo $this->Form->input('password');
echo $this->Form->input('re_password', array('type'=>'password', 'label'=>'Re-Enter Password', 'value'=>'', 'autocomplete'=>'off'));
echo $this->Form->input('location', array('options' => $options, 'label' => 'Select Nearest Location'));
echo $this->Form->input('website',array('label'=>'Enter your website, such as www.example.com. '));
echo $this->Form->input('role', array('type' => 'hidden', 'default' => 'user'));
Here's the re_password checking function in the User model
function check_user_password($userid) {
$salt = Configure::read('Security.salt');
$this->User->id = $userid;
$hashed_password = $this->User->field('password');
// check password
if($hashed_password == md5($data['User']['re_password'].$salt)) {
return true;
} else {
return false;
}
}
And finally, here's the add function in UsersController
public function add() {
if ($this->request->is('post')) {
$this->User->create(); //create initiates a form on User/add.ctp
if ($this->User->save($this->request->data)) { //save the form data
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('controller' => 'demos', 'action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
Please let me know if there's anything else you need to see
I believe that your re_passwords valiadtion rule equalTo compares its value to string password and not the actual field. I like to use custom functions for this.
so try replacing re_passwords rule array
//'rule' => array('equalTo', 'password' ),
'rule' => array('equalToField', 'password'),
and declare equalToField function in that model
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
** Also in the future when you seem to have a problem with validation rules
try this in your controllers action (its faster than removing every single rule)
if ($this->User->save($this->request->data)) {
...
} else {
debug($this->User->validationErrors);
...
}
I hope this helps.
Hi Please use following code for your requirement :
override equalTo function by putting your own method in user model:
function equalTo( $field=array(), $compare_field=null )
{
foreach( $field as $key => $value ){
$v1 = $value;
$v2 = $this->data[$this->name][ $compare_field ];
if($v1 !== $v2) {
return FALSE;
} else {
continue;
}
}
return TRUE;
}
Attention, in #luboss answer, where he declares:
function equalToField($array, $field) {
return strcmp($this->data[$this->alias][key($array)], $this->data[$this->alias][$field]) == 0;
}
That cannot work as we are comparing inconsistent fields:
the left member of strcmp has already been hashed, but not the right member.
This happens as a CakePHP automation because the field is called password.
The way I got this to work was to reuse the hashing function in the equalToField helper:
public function equalToField($array, $field) {
$valueFirstOccurrence = $this->data[$this->alias][$field];
$valueSecondOccurrence = Security::hash($this->data[$this->alias][key($array)], $type = 'sha1', $salt = true) ;
return !strcmp($valueFirstOccurrence, $valueSecondOccurrence);
}
Other point :
If you are interested in adding a minLength validation field for your password field, you want to read this good post first:
minLength data validation is not working with Auth component for CakePHP

Categories