How to exclude a perticular field from unique validation in edit mode in cakephp3.0 validation - validation

I want to validate a field called survey_id which is an input from user for uniqueness. It is working properly and giving the correct response when adding the new record, but when I tried to edit this record it is giving an error [unique] => Provided value already exist. So what I want is to exclude the survey_id of the current record from uniqueness check and if user input some other value for survey_id it should check for uniqueness search.
Currently I am using the CakePHP 3.0 validation with on create validation. Here is the validation rule that I am using:
validator
->requirePresence('survey_id', __('msg_required'))
->notEmpty('survey_id', __('msg_required'))
->maxlength('survey_id', 32, __('msg_maxlength'))
->add('survey_id', 'unique', ['rule' => ['validateUnique',['id']], 'provider' => 'table', 'message' => 'Provided value already exist', 'on'=>'create']);
return $validator;
Is there anything wrong with this code?
Thanks in advance.
`

It will work with this validation rule
$validator
->requirePresence('survey_id', __('msg_required'))
->notEmpty('survey_id', __('msg_required'))
->maxlength('survey_id', 32, __('msg_maxlength'))
->alphaNumeric('survey_id', __('msg_surveyid_format'))
->add('survey_id', 'custom', [
'rule' => function ($value, $context) {
if (!empty($context['data']['projectId'])) { $values = array($context['data']['projectId']); } else { $values = array(); }
$data = $this->getSurveyId($value, $values);
return (!empty($data)) ? false : true;
},
'message' => __('msg_surveyid_exsist')]);
return $validator;
}
public function getSurveyId($surveyId = null, $exclude = null) {
$where = array('p.survey_id' => $surveyId);
if (!empty($exclude) && is_array($exclude)) {
$where[] = array('p.id NOT IN' => $exclude);
}
return $this->db->newQuery()
->select('*')
->from(['p' => 'projects'])
->where($where)
->execute()
->fetch('assoc');
}

Related

How can i skip unique field in Yii2?

I have a unique field that I check when editing or adding a new training course. But, for some reason, when I enter a value in a field, it does not show me a hint that the field is already taken.
In addition, I need to do this: when I change the values and did not change this unique field, but left it as it is, then the validor should not swear that the field is already taken.
Thank.
InfCourses Model:
public function rules()
{
return [
[['name', 'short_description', 'price', 'favorite', 'active', 'course_order', 'link'], 'required'],
[['price', 'active'], 'integer'],
[['favorite'], 'string'],
[['name', 'short_description', 'link'], 'string', 'max' => 255],
[['active'], 'exist', 'skipOnError' => true, 'targetClass' => InfStatuses::className(), 'targetAttribute' => ['active' => 'id']],
[['course_order'], 'integer', 'min' => 1],
[
['course_order'], 'unique',
'targetAttribute' => ['course_order'],
'filter' => ['!=', 'id', Yii::$app->request->get('id')],
],
];
}
Validator in InfCoursesController:
public function actionValidate()
{
$model = new InfCourses();
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
}
Part of form code:
<?php $form = ActiveForm::begin([
'enableAjaxValidation' => true,
'validationUrl' => 'validate',
'options' => [
'data-pjax' => true,
]
]); ?>
Your validation is simply incorrect. You're using Yii::$app->request->get('id') in your rules, which is probably main source of your problems. Model should not access request or web user component directly - it breaks MVC pattern. Also putting values directly in rules in this way may give you unexpected results. You should check what query is generated by this validator, because it is hard to guess what is happening with such twisted rule.
But it may be easier to fix actionValidate() and distinguish between validating of new record and validating existing record:
public function actionValidate($id = null) {
if (empty($id)) {
$model = new InfCourses();
} else {
$model = $this->findModel($id);
}
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
}
Then you can limit your unique rule to:
[['course_order'], 'unique'],
Validator will be smart enough to detect that it is validating existing record and will not report unchanged fields values as duplicates. You just need to provide record ID in this action URL.
Well... I cut code below to each action: create/update.
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
Then remove validationUrl from form component. Inside model i make this rule [['course_order'],'unique']... Working fine...

how to create Custom Validation Rule for during Update a record in CakePHP

I have added a rule to check the previous password on update user record, but the rule also applies to creating a record, I have added 'update' but still, it's not working.
$validator
->scalar('password')
->maxLength('password', 25)
->notEmpty('password', 'Password is required', 'create')
->allowEmpty('password', 'update')
->add('password', 'validFormat', [
'rule' => ['custom', '/^(?=.*[!#$])(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{6,16}$/i'],
'message' => __('Minimum 6 character & alphanumeric with one symbol(!#$) is Required.'),
'allowEmpty' => true
])
->add('password', 'custom', [
'rule' => function($value, $context){
$user = $this->get($context['data']['id']);
if ($user) {
if (!(new DefaultPasswordHasher)->check($value, $user->password)) {
return true;
}
}
return false;
},
'message' => 'You cannot use your previous password',
'allowEmpty' => true
], 'update');
Adding updated does not do anything as it is not something that CakePHP supports there.
If you read Custom Validation Rules you will see that you can use $context['newRecord'] to determine if this is an update or create.
So, the first line in your validation function could be something like
if ($context['newRecord']){
return true; //new passwords are always valid!
}
Alternative way would be to check the $user variable and add an else branch
if($user){
//you already have code here
}else{
//add this else to return TRUE because for new user, new password is OK
return true;
}

How to add unique validation on combination of firstname and lastname in laravel5?

I need to validate user table in which not repeated combination of (firstname and lastname). for example:- firstname=dc lastname=patel already exist in table. i need to prevent same entry next time.
Finally I have perfect solution for this.
$validationRule = ['first_name' => 'required','last_name'=>'required'];
$validationMsg = ['first_name.required' => 'First Name is required', 'last_name.required' => 'Last Name is required'];
$validation = Validator::make(['first_name' => $firstName, 'last_name' => $lastName], $validationRule, $validationMsg);
$validation->after(function ($validation) use ($firstName, $lastName) {
$checkName = User::where('first_name', $firstName)->where('last_name', $lastName)->get();
if (count($checkName) > 0) {
$validation->errors()->add('first_name', 'User already exists, please enter another user.');
}
});
if ($validation->fails()) {
foreach ($validation->errors()->all() as $error) {
$message = $error;
}
return response(\Helpers::makeAjaxResponse(false, $message));
} else {
//Save record code here
}
You can use something simular to composite UNIQUE key in table if database provide this possibility.
http://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html
with using laravel unique validation rule
how can you allow users with same lastname but not firstname for registeration?
unique.firstname
First check records count with the given firstname and lastname.
If the count is '0' save the record or else show message.
Here is some code hint
$users = DB::table('users')
->where(['firstname' => 'dc', 'lastname' => 'patel'])
->count();
if($users === 0) {
// save the record.
} else {
// Show message
}
Since Laravel 5.5 you can use elegant Rule class like:
use Illuminate\Validation\Rule;
// ...
$firstNameUniqueRule = Rule::unique('users')->where('last_name', request()->get('last_name', ''));
$rules = [
'first_name' => ['required', $firstNameUniqueRule],
'last_name' => 'required',
];

Cakephp-3 conditional notEmpty validation behaviour

I need to do a conditional validation on a field: if other_field = 1 then this_field = notBlank. I can not find a way to do this.
My validator in table class:
public function validationDefault(Validator $validator) {
$validator->allowEmpty('inst_name');
$validator->add('inst_name', [
'notEmpty' => [
'rule' => 'checkInstName',
'provider' => 'table',
'message' => 'Please entar a name.'
],
'maxLength' => [
'rule' => ['maxLength', 120],
'message' => 'Name must not exceed 120 character length.'
]
]);
return $validator;
}
public function checkInstName($value, array $context) {
if ($context['data']['named_inst'] == 1) {
if ($value !== '' && $value !== null) {
return true;
} else {
return false;
}
} else {
return true;
}
}
Trouble here is, if i note, in the start of the method, that the field is allowed to be empty, when the entered value is empty, Cake doesn't run through any of my validations, because it's empty and allowed to be such. If i do not note that the field can be empty, Cake just runs "notEmpty" validation before my custom validation and outputs "This field cannot be left empty" at all time when it's empty.
How do i make Cake go through my conditional "notEmpty" validation?
I did try validation rule with 'on' condition with the same results.
Successfully tested, this might help you and others. CakePHP 3.*
$validator->notEmpty('event_date', 'Please enter event date', function ($context) {
if (!empty($context['data']['position'])) {
return $context['data']['position'] == 1; // <-- this means event date cannot be empty if position value is 1
}
});
In this example Event Date cannot be empty if position = 1 . You must put this condition if (!empty($context['data']['position'])) because the $context['data']['position'] value only will exist after the user click submit button. Otherwise you will get notice error.

CakePHP custom Validation rule checks unique field combination only on create

I have a Database with a User model. These Users should be unique by their name and birthday.
So I wrote a custom validation function called checkUnique
public function checkUnique($check){
$condition = array(
"User.name" => $this->data["User"]["name"],
"User.lastname" => $this->data["User"]["lastname"],
"User.birthday" => $this->data["User"]["birthday"]
);
$result = $this->find("count", array("conditions" => $condition));
return ($result == 0);
}
The validation rule in the model:
"name" => array(
"checkUnique" => array(
"rule" => array("checkUnique"),
"message" => "This User already exists.",
"on" => "create"
),
)
I have two problems.
The first: This validation rule also triggers on update action, implemented as
public function edit($id = null) {
if (!$this->User->exists($id)) {
throw new NotFoundException(__('Invalid User'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('Update done.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user can't be saved.'));
}
} else {
$options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
$this->request->data = $this->User->find('first', $options);
}
}
But I wrote "on" => "create", so why it triggers also on update?
The second problem:
If the validation rule only triggers on create, how can I manage, to trigger an validation error, if someone change the name, lastname and birthday like an other user in the Database? Then the unique validation rule should be triggered.
Remove the 'on' => 'create'. (You want to validate in both events).
Modify your custom validation rule to this
public function checkUnique() {
$condition = array(
"User.name" => $this->data["User"]["name"],
"User.lastname" => $this->data["User"]["lastname"],
"User.birthday" => $this->data["User"]["birthday"]
);
if (isset($this->data["User"]["id"])) {
$condition["User.id <>"] = $this->data["User"]["id"];
//your query will be against id different than this one when
//updating
}
$result = $this->find("count", array("conditions" => $condition));
return ($result == 0);
}

Resources