I have a model with title, subtitle, date and am building a form that will allow a user to submit a change request.
How can I validate to ensure at least one edit is made comparing the input fields to database values?
I think the below would ensure the title entered is different from the value in 'different:', but how would I only do this for at least one field?
public function rules()
{
return [
'title' => [
'required',
'different:Dynamic Title name here',
'string',
'max:60',
'not_regex:/[\x{1F600}-\x{1F64F}]/u'
],
'subtitle' => [
'string',
'nullable',
'max:90',
'not_regex:/[\x{1F600}-\x{1F64F}]/u'
]
];
}
e.g.
Title, Subtitle, Date fields are shown. A user must edit at least one of them from the current set database values in order to submit.
I don't know your solution, but I'd recommend to take a look at isDirty() function.
/**
* this will return false, because after we get the record from
* database, there's no attribute of it that we changed. we just
* print if it's dirty or not. so it tells us: "I'm clean, nobody has
* changed my attributes at all.
*/
$role = Role::findOrFail(1);
return $role->isDirty();
/**
* lets say We fetched this role with id=1 and its status was 1. what
* this returns is still false, because even though we set the status
* attribute equal to 1, we still didn't change it. It was 1 when we
* received it from the database and it's still 1.
*/
$role = Role::findOrFail(1);
$role->status = 1;
return $role->isDirty();
/**
* now if the status was 1 in the db, and we set it to 2, it will
* print the true.
*/
$role = Role::findOrFail(1);
$role->status = 2;
return $role->isDirty();
You can also pass an argument to isDirty() function which will only check that specific column value.
Related
I have a request that takes several input. I want the 'salary' input to be validated only if the salary_type is equal to "exact". Else, I don't want to have any message about it.
However, now, even if salary_type is equal to "range", I still get an error that "salary must be an integer".
How can I make sure there isn't any error unless the field is required?
Thanks!
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreJobOfferRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'title' => 'required|string|min:3',
'description' => 'required|string|min:10',
'city' => 'required|string|min:3',
'salary_type' => 'required|in:range,exact',
'min_salary' => 'required_if:salary_type,range|integer|min:0',
'max_salary' => 'required_if:salary_type,range|integer|min:0',
'salary' => 'required_if:salary_type,exact|integer|min:0',
'fieldsOfWork' => 'required|exists:field_of_works,id',
'job_type.*' => 'required|exists:job_types,id',
"trainings.*" => 'required|exists:trainings,id',
"availability.*" => 'required|exists:trainings,id'
];
}
}
required and required_if do not stop the rest of the validation rules from being executed. It just expects the value not to be null, an empty string, and empty Countable object or an uploaded file with no path. If the field is set, the required rule will just be skipped and the next rule is applied.
So, the required_if rule for salary will skip if salary_type is not 'exact', and continue validating if it's an integer and min 0. This behavior is confusing to a lot of new Laravel developers.
There is an exclude_if rule that does what you probably expect:
'salary' => 'exclude_if:salary_type,exact|integer|min:0',
This will exclude the whole field under validation from the request data that will be returned by validate() and $request->validated() methods if the condition is not met. So if salary_type is not 'exact', the salary field will be gone but the validation will pass.
If salary_type is 'exact', however, it will be validated for being a min 0 integer value.
Please note that the exclude_if rule was added in Laravel 6, so this doesn't work for previous versions of Laravel. See https://laravel.com/docs/8.x/validation#conditionally-adding-rules for details on conditional validation.
I have this assertion inside my entity :
/**
* #Assert\Choice(choices = {"fiction", "non-fiction"}, message = "Choose a valid genre.")
*/
protected $genre;
And the documentation says for the message parameter :
type: string
default: The value you selected is not a valid choice.
This is the message that you will receive if the multiple option is set to false and the underlying value is not in the valid array of choices.
And in my form type, I have :
->add('genre', ChoiceType::class, [
'multiple' => false,
])
But, when the value of gender field isn't in the valid array of choices ("fiction", "non-fiction"), the message error is "This value is not valid."
It isn't not the default value, nor the value I set in the entity.
I know I can override it in the form type with the "invalid_message" parameter,
but I want to if there is an explanation on this ?
Why the "message" parameter oth the Assert/Choice doesn't work?
How can I make it work like its expected in the symfony doc ?
In the docs, it's not speficied that you can pass the possible values in this place.
You need to create a function in the class (for example "getGender()") that returns an array with the valid values.
Then, with the assert, you can call this function like this :
class Author
{
/**
* #Assert\Choice(callback = "getGender", message = "Choose a valid genre.")
*/
protected $genre;
public function getGender() {
return array("fiction", "non-fiction");
}
}
And be carefull, you used "choices" instead of "callback" in the annotation ;)
My first remark would be that
/**
* #Assert\Choice(choices = {"fiction", "non-fiction"}, message = "Choose a valid genre.")
*/
protected $genre;
attribute's name is genre but on the form type you're calling it gender.
I guess this is just mistyping problem.
Just rename the attribute gender instead of genre .
I have a table/model that contains multiple albums per user.
Is there a way to say that the column title should be unique, but only for the rows that have the same user_id?
Example: http://pastebin.com/8dvM4a1T
As you can see in the example, the user with the id of 2 has created 2 albums, with the same title. I don't want that to be allowed, that's why I'm wondering if there's a way to deny that with the validator from Laravel?
I tried this, but that did not work.
// Validator
$validator = Validator::make($input, [
'title' => 'required|min:1|max:255|unique:galleries,title,'. Auth::user() -> id .',user_id',
'description' => 'min:1|max:255'
]);
Any help appreciated, thanks.
Your code should be something like:
'title' => 'unique:galleries,title,NULL,id,user_id,'.Auth::user() -> id.'',
Or, you can write a custom rule
Reference here
The approach with the default unique rule does not work because the rule expects the column value to be passed as the third parameter, so in your case it would check if the title column is equal to the Auth::user()->id value which is not what you want.
You can create you own custom validation rule by adding the following code to the boot method of the App\Providers\AppServiceProvider class:
Validator::extend('unique_custom', function ($attribute, $value, $parameters)
{
// Get the parameters passed to the rule
list($table, $field, $field2, $field2Value) = $parameters;
// Check the table and return true only if there are no entries matching
// both the first field name and the user input value as well as
// the second field name and the second field value
return DB::table($table)->where($field, $value)->where($field2, $field2Value)->count() == 0;
});
Now you can use the unique_custom (or you can name it whatever you like) rule like so:
$validator = Validator::make($input, [
'title' => 'required|min:1|max:255|unique_custom:galleries,title,user_id,' . Auth::id(),
'description' => 'min:1|max:255'
]);
The rule expects the parameters to be the following:
the 1st parameter to be the table name, which in this case is galleries
the 2nd parameter to be the field name that is supposed to be unique and for which the value comes from the user input, which in this case is title
the 3rd parameter to be the second field name that will be added to the query conditions, which in this case is user_id
the 4th parameter to be the value of the field name passed as the third parameter
Also you can use Auth::id() since that is the short form of Auth::user()->id.
You can read more about Custom Validation rules in the Laravel Documentation.
Laravel 5.3 and above
use Illuminate\Validation\Rule;
'email' => Rule::unique('galleries')->where(function ($query) {
$query->where('user_id', Auth::id());
})
Laravel 9
use Illuminate\Validation\Rule;
Rule::unique('galleries')->where(fn ($query) => $query->where('user_id', Auth::id()))
I'm pretty deep into a complex Symfony2 project, with many entities and join tables in forms etc. but I'm having a strange issue with the "multiple" attribute within the form builder.
Basically I have a form where a user can add an illness to the CRM, and each illness can be attached to a specific store (depending on the language used). There is a list of stores that can be chosen by the user within this form, and the values are stored in a join table. However I only want one store to be chosen (i.e. a select drop down) rather than a multiple select list but using the false value for the multiple attribute throws an error which I will outline later.
Firstly, here is the buildForm() code in my Type.php file:
$builder->add('name' , 'text');
$builder->add('description' , 'textarea');
$builder->add('store', 'entity',
array(
'class' => 'AppBundle:Store',
'empty_value' => 'Choose store',
'property' => 'name',
'multiple' => false,
));
$builder->add('save', 'submit', array(
'attr' => array(
'class' => 'btn btn-primary'
),
));
And the entry for the store field in my Entity:
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Store", inversedBy="illness", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="store_id", referencedColumnName="id")
* })
*/
public $store;
However, if I used the false declaration for the multiple attribute in the form Type, when the form is submitted I receive the following error:
Warning: spl_object_hash() expects parameter 1 to be object, string given
because it looks like it's passing the text value of the select box, rather than the relevant Entity. When set as a multiple select box (i.e. set to true) then it works fine and persists as it should.
My controller code:
$addIllness = new Illness();
$form = $this->createForm(new IllnessType($em), $addIllness);
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($addIllness);
$em->flush();
return $this->redirect($this->generateUrl('app_illness_table'));
}
Having it as a multiple select box is not the end of the world, though I'd rather have it as a drop down select so the user cannot select more than one store - rather than me having to add an error message or note to tell them otherwise.
If anyone has an ideas as to why this may be happening, or has encountered it before please let me know, I would be very grateful!
Thank you
Michael
I need to know how to apply the "matches" validation rule in Kohana 3.1. I've tried the following rule in my model with no success:
'password_confirm' => array(
array('matches', array(':validation', ':field', 'password')),
)
But it always fails. I put a var_dump($array) in the first line of the Valid::matches() method. I paste it below:
/**
* Checks if a field matches the value of another field.
*
* #param array array of values
* #param string field name
* #param string field name to match
* #return boolean
*/
public static function matches($array, $field, $match)
{
var_dump($array);exit;
return ($array[$field] === $array[$match]);
}
It prints an object of type Validation and if I do var_dump($array[$field]) it prints null.
Thanks a lot in advance.
UPDATE: Also I figured out by the validation message that the order of the parameters of the rule should be inverted to this:
'password_confirm' => array(
array('matches', array(':validation', 'password', ':field')),
)
Your syntax is correct, but I'm going to guess and say that your DB schema does not have a 'password_confirm' column so you are trying to add a rule to a field that doesn't exist.
Regardless, the right place to perform password confirm matching validation is not in your model but as extra validation that is passed to your model in your controller when you attempt to save.
Put this in your user controller:
$user = ORM::Factory('user');
// Don't forget security, make sure you sanitize the $_POST data as needed
$user->values($_POST);
// Validate any other settings submitted
$extra_validation = Validation::factory(
array('password' => Arr::get($_POST, 'password'),
'password_confirm' => Arr::get($_POST, 'password_confirm'))
);
$extra_validation->rule('password_confirm', 'matches', array(':validation', 'password_confirm', 'password'));
try
{
$user->save($extra_validation);
// success
}
catch (ORM_Validation_Exception $e)
{
$errors = $e->errors('my_error_msgs');
// failure
}
Also, see the Kohana 3.1 ORM Validation documentation for more information