CakePHP 3 belongsToMany Validation - validation

I am struggling with how to do validation with belongsToMany relationships. Namely, the classic recipes/ingredients relationship. I would like a recipe to always have an ingredient on create or edit. What would my validation look like in my RecipesTable? I have tried:
$validator->requirePresence('ingredients')->notEmpty('ingredients')
As well as
$validator->requirePresence('ingredients._ids')->notEmpty('ingredients._ids')
The second one works in that my form doesn't validate, but it does not add the error class to the input. I am setting up the input with a field name of ingredients._ids.
I am also having trouble with creating the data to pass to $this->post in my tests in order to successfully add a record in my test. My data in my test looks like:
$data = [
'ingredients' => [
'_ids' => [
'2'
]
];
And of course I'm doing the post in my test with $this->post('/recipes/add', $data);
I'm not passing the required rules for ingredients in my test.

I solved how to set up the validators. In the recipe Table validator:
$validator->add('ingredients', 'custom', [
'rule' => function($value, $context) {
return (!empty($value['_ids']) && is_array($value['_ids']));
},
'message' => 'Please choose at least one ingredient'
]);
However, the validation message was not being displayed on the form, so I'm doing a isFieldError check:
<?php if ($this->Form->isFieldError('ingredients')): ?>
<?php echo $this->Form->error('ingredients'); ?>
<?php endif; ?>
I'm using multiple checkboxes in my view file versus a multi-select.
And with that, I'm getting my validation message on the form.
As I thought, my tests fell into place once I figured out the validator. What I show above is indeed correct for passing data in the test.

I will have desired to add this answer as a comment of Kris answer but I do not have enough reputation.
Alternatively, to solve the issue with validation message not being displayed on the form, you can add these two line in your controller.
if(empty($this->request->data['ingredients']['_ids']))
$yourentity->errors('ingredients', 'Please choose at least one ingredient');

Related

Laravel: Adding custom attribute to validation of array of files not working

I am unable to change the attribute for the array of files in Laravel Validation.
in my FormRequest class, I've made the following validation
public function rules() {
return [
'product_images' => 'nullable|array',
'product_images.*' => [nullable, File::image()],
];
}
public function attributes() {
return [
'product_images.*' => 'Showcase images'
];
}
But in validation errors, it still shows as product images.0 must be an image & not as Showcase images must be an image which should be the expected output.
PS: This is happening only in case of file validations and working fine in normal validations
Add a custom validation message to the lang/validation.php. You can put it at the designated array for custom validation message at the very bottom of the file.
example :
'product_images.*' => [
'image' => 'Show case image must be an image',
]
also insead of File::image() change it to image because I don't if it will work if you dont chamge it.

Laravel 5: Validating Edits In-Place

I had previously asked a question here in regards for setting up in-place editing with Laravel 5 and AJAX. I hadn't updated it because I had managed offline to figure out what was wrong with it.
While the table is capable of editing user rows in-place, I'm now trying to add validation on top of it, intending on utilizing Laravel's built-in validator. However, for some reason it doesn't seem to be working. When I try to pass in the failed validator back through the JSON, it spits out every possible error I'm checking for. It's as if the validator is treating every input as empty, which doesn't make sense, as the rest of the function is clearly taking in the inputs as intended.
The code snippets in my previous question are still mostly relevant, but there have been updates to HomeController.php, as can be seen below:
public function updateTable(Users $users){
$user = request()->input('user');
$first_name = request()->input('first_name');
$last_name = request()->input('last_name');
$validator = Validator::make(request()->all(), [
'firstName' => 'required|alpha',
'lastName' => 'required|alpha'
], [
'firstName.required' => 'You need to give a first name!',
'firstName.alpha' => 'A first name can only contain letters!',
'lastName.required' => 'You need to give a last name!',
'lastName.alpha' => 'A last name can only contain letters!'
]);
if ($validator->fails()) {
return response()->json($validator, 404);
}
$employees->editUser($user, $first_name, $last_name);
return response()->json($user);
}
So I realized the issue was twofold. First, what I was trying to return when the validator failed was incorrect. Rather than simply passing the whole validator, I needed to simply pass its messages, like so:
if ($validator->fails()) {
return response()->json($validator->messages(), 404);
}
The second issue actually had to do with calling "request()->all()". I had assumed the array obtained would have worked, but for some reason it didn't. When I created a new array based on the values in "request()" it was able to get the validator results I was expecting.

cakephp 3.x model validation not showing when Saving data into 2 tables

I have two tables employees and user employees has field user_id relation between them us user hasOne employee and employee belongs to user, i have following code in my view file
<?php
echo $this->Form->input('employee.name');
echo $this->Form->input('user.email');
echo $this->Form->input('user.username');
echo $this->Form->input('employee.employee_level');
?>
my EmployeeController code is
<?php
$employee = $this->Employees->newEntity($this->request->data);
$user = $this->Employees->Users->newEntity($this->request->data);
if ($this->request->is('post')) {
$employee = $this->Employees->patchEntity($employee, $this->request->data, [
'associated' => ['Users']
]);
if($this->Employees->save($employee)) {
$this->Flash->success(__('The employee has been saved.'));
} else {
$this->Flash->error(__('The employee could not be saved. Please, try again.'));
}
}
?>
Its saving the data if all thing going good and perfect but if there are some validation errors like username already exist or email already exist than its simple show the flash message that employee could not be saved please try again its not showing the model validation error message under the fields as shown in the attached image when i try to save data in single table
Please tell me what is the problem in my view or controller file so that if any of two model has validation errors than its show error message under the related field
Sorry for my bad english
Thanks
Try this for your form. You shouldn't need to provide the name of the top-level model.
echo $this->Form->input('name');
echo $this->Form->input('user.email');
echo $this->Form->input('user.username');
echo $this->Form->input('employee_level');
And in your controller, you never use $user, so no point in creating it, and since you're patching the employee entity with the request data, you don't need to initialize it the same way.
$employee = $this->Employees->newEntity();
if ($this->request->is('post')) {
$employee = $this->Employees->patchEntity($employee, $this->request->data, [
'associated' => ['Users']
]);
...

How to implement model validation on autocomplete field in yii2?

I am using a jui autocomplete widget in my form. Model validation is not working properly in here.
This is my view
<?php $form = ActiveForm::begin();?>
<div class="members-form">
<div class="col-md-5">
<?php
$data = FamilyName::find()
->select(['name as value', 'name as label','id as id'])
->asArray()
->all();
echo 'Family Name' .'<br>';
echo AutoComplete::widget([
'name' => 'family',
'id' => 'family_name',
'clientOptions' => [
'source' => $data,
// 'minLength'=>'3',
'autoFill'=>true,
'select' => new JsExpression("function( event, ui ) {
$('#members-family_name_id').val(ui.item.id);//#City-state_name is the id of hiddenInput.
}")],
]);
?>
<?= Html::activeHiddenInput($model, 'family_name_id')?>
<?= $form->field($model, 'remarks')->textInput() ?>
<?php ActiveForm::end(); ?>
</div>
</div>
my model code
public function rules()
{
return [
[['family_name_id', 'first_name',
'date_of_birth', 'relation_id', 'is_head','marital_status','remarks',
'gender','address_id'], 'required'],
];
}
Now if i try to create a new member with no data selected in any of the fields, then required fields will show like " ... cannot be blank" in red. But the family_name_id is not showing such validation. The data is not getting saved if leave the auto complete field empty but no validation message is being displayed. How can i show validation messages with jui auto complete ?
I believe you faced the same problem as I had few weeks ago. I experienced similar behavior: I saw autocomplete suggestions and could interact with them, but when I left the input field the client-site validation kept silent.
If you look at the html produced by your view, at the bottom you can see some javascript code, which is responsible for the client-side validation. It looks like:
jQuery(document).ready(function () {
....
jQuery('#app-new-form').yiiActiveForm(
[
{
"id":"application-familyname",
"name":" familyname ",
"container":".field-application-familyname",
"input":"#application-familyname",
"enableAjaxValidation":true,
"validate":function (attribute, value, messages, deferred, $form) {
yii.validation.required(value, messages, {"message":"Field cannot be empty"});
}
}
], []);
.....
});
This code assigns an event handler to your autocomplete field to start the client-side validation. But you have to pay attention, which id is used for the field. Unfortunately, yii2 takes the id provided by you only to construct the <input> element in html. When it produces javascript code the id is always generated from few permanent parts. The most important two are the name of the model and the name of the attribute. In your case id should be something like 'your_modelname -family_name_id'.
Because your explanation is not complete, this is only a guess. So, look at your html source and be sure you have the same id for the input you try to validate and the id in the JavaScript (see above).
You are using Html Hidden Input .. You have to use ActiveForm HiddenInput to show error validation..
use
<?= $form->field($model, 'family_name_id')->hiddenInput()->label(false);>
Why don't you use the family_name_id instead of creating a new select?
<?= $form->field($model, "family_name_id")->dropDownList(
ArrayHelper::map(FamilyName::find()->all(), 'id', 'name'),
['prompt' => 'Select']
) ?>
And you can change the label by using ->label('Family Name'), but i would recommend changing in model (unless you need "Family Name Id" as a label elsewhere).
I know you didn't said anything about that, but can i recommend you to see this answer about using methods that perform sql queries inside your view?

Multiple validation on one attribute in Yii

I want to validate an attribute on multiple CValidator classes.
To be more specific, I want an email address to be validated by the email validator, but I also want it to be required.
I can of course define two separate rules, like so:
array('email', 'email'),
array('email', 'required'),
But when I leave the input blank the validation only returns an error saying the field is required, but it doesn't return an error saying it has to be an email address. When I fill in a non-email string, it then returns the email validation error.
I tried to combine the validators in an array, and a comma separated string but that doesn't work. So I guess the only option is to use a custom validation method.
But how can I use the built-in CValidator validators in this method? And how can I build it, that the two rules are validated together at once instead of one at a time?
If I am getting you right you have an issue with error message. I think you can use following approach to show message.
array('email', 'email', 'message' => 'Please provide valid email.'),
array('email', 'required', 'message' => 'Email is required. Please provide valid email.'),
Hope this will help you....
User interface wise this makes little sense to specify that an email is invalid when left empty. You tell them that the email is required when empty or invalid when it isn't empty but not an email. Doing both seems very confusing to me.
I personally just use:
array('email', 'email', 'allowEmpty' => FALSE),
Use the errorsummary() method:
EDIT:
Changed reference to CHTML
http://www.yiiframework.com/doc/api/1.1/CHtml#errorSummary-detail
In your view, add
<?php echo CHtml::errorSummary($model, NULL, NULL, array ('firstError' => false));
...
<div class="row">
<?php echo $form->labelEx($model,'email'); ?>
<?php echo $form->textField($model,'email'); ?>
<?php echo $form->error($model,'email'); ?>
</div>
From the documentation
additional HTML attributes to be rendered in the container div tag. A
special option named 'firstError' is recognized, which when set true,
will make the error summary to show only the first error message of
each attribute. If this is not set or is false, all error messages
will be displayed. This option has been available since version 1.1.3.
Note that if you are using Ajax validation then you will get the first error only, next to the fields
Actually model validation returns all errors of validation, but CActiveForm::error method shows only first one for selected attribute. I guess you use now something like this:
<?php echo $form->error($model,'attr'); ?>
but instead should use
<?php if ($model->hasErrors('attr')) : ?>
<?php $errorList = $model->getErrors('attr'); ?>
<?php foreach ($errorList as $error) : ?>
// display error
<?php endforeach ?>
<?php endif ?>
Also you can write your own helper method for displaying all errors for single attribute.
You can use skipOnError property of the validator.
array('email', 'email', 'skipOnError' => false),
array('email', 'required', 'skipOnError' => false),

Resources