Apply several constraints in one "validate" pass in Silex - validation

I'm using Silex, and trying to validate some value with validator service. But the problem is that I need apply several constraints to one value, but validator don't let to do this without using Required constraint.
When I just want to validate a choice value (say, 'apple' or 'orange') I have to wrap constraints Choice and NotNull (because Choice allows a null value) into Required and Collection (because Required cannot be used without Collection and it is CollectionValidator who validates series of Required's constraints) like this:
$violations = $app['validator']->validate(array('value'),
new Collection(array(
new Required(array(
new Choice(array('apple', 'orange')),
new NotNull()
))
)));
It looks verbose so I'm looking for more elegant solution (for such explicit use of validator).

You can use the validateValue function that accepts an array of constraints as second parameter.
$violations = $app['validator']->validateValue('value', array(
new Choice(array('apple', 'orange')),
new NotBlank()
));

Related

How to create a custom exclude validation rule in Laravel

I would like to create a custom rule that excludes an attribute under some condition, the only ways I could think about are:
manually verify the condition in the FormRequest and add the 'exclude' rule if my condition is ture (which is, imo, not so elegant)
(I'm not sure if this will work/ won't have side effects) create a custom validation rule that will remove the attribute from the request (request->remove($attribute)) if the condition is true.
Is there any better way to do this ?
I couldn't find the implementation of any of the exclude rules either.
This is a vague answer to match your vague question, but it is easily done with conditional complex validation. Use the withValidator() method to access the validator instance before the rules are applied.
// assuming we're inside a FormRequest
public function withValidator($validator)
{
$validator->sometimes(
'some_field',
'required|string|max64',
fn ($data) => $data->some_other_field !== 1234
);
}
First argument to sometimes() is the field you want to conditionally validate; the second is the rules you want to apply; and the third is a callback. The callback is passed the request data; if it returns true, the rules will be applied.
There are lot of ways to exclude a validation rule based on conditions.
You can use exclude_if, exclude_unless and exclude_without.
Suppose you want to exclude a field validation if its another field's value is null, then you can use
['field1' => 'exclude_if:field2,null|<validation rules for field1>']
Again suppose you want to exclude a field validation unless the other value is not equal to 3, then use,
['field1' => 'exclude_unless:field2,==,3|<validation rules for field1>']
I've just found out that since Laravel 8.55 there is the method 'when' in the Rule object that you can use inside your rules() method as follow to exclude an attribute:
Rule::when(MyCallBackThatReturnsABoolean, [/*RulesIfCallBackReturnsTrue*/], [/*RulesIfCallBackReturnsFalse*/])
For some reason, I can't find the method in the documentation.
for example to exclude an attribute if the condition foo==bar is false I could do:
Rule::when(function() use(foo,bar) { return foo===bar }, ['required', 'string'], ['exclude'])
Pull requests here and here
Example of usage here

Has laravel 7 model a way to get list of all columns?

Has laravel 7 model a way to get list of all columns ?
I found and tried method
with(new ModelName)->columns
but it returns empty string.
I do not mean $fillable var of a model.
Thanks!
If you just want a reliable way to pull the list of attributes from any given instance no matter the state, and assuming the table structure isn't changing often, the path of least resistance might be to set a defaults attributes array to ensure the attributes are always present.
e.g.
class Fish extends Model
{
protected $attributes = [
'uuid' => null,
'fin_count' => null,
'first_name' => null,
];
}
$fishie = app(\Fish::class);
will then result in an instance of Fish with uuid, fin_count, and first_name set. You can then use $fishie->attributes or $fishie->getAttributes() to load the full set.
Assuming the structure doesn't change a lot, setting the attributes on the model like this will save you a database query every time you want to reference the list. The flip side is that instances change from not having the attributes unless explicitly defined to always being present, which may have implications in the project.
Here's the documentation for default attributes:
https://laravel.com/docs/master/eloquent#default-attribute-values

Symfony2: How do i validate an object/array with its constraints in another object/array?

It's built dynamically, annotations are not an option. I have the constraints in an array.
It seems you need to manually construct the validator but I get stuck fast on the point where you need to construct a MetaDataFactory that needs an loader, but all the loaders have the job of loading meta data from a file.. I dont think I'm doing it right.
Simply said:
I have an array/object with keys/values. I want them validated by another array that contains the constraints.
It's not possible to iterate over the keys and call validate on each and every one of them, since some rely on the context values from other keys.
$array = [
'key1' => 'abc',
'key2' => 'def',
];
$constraints = [
'key1' => new All([
new Constraint..,
new CallbackConstraint.., // <- this one checks key2 for its value
]),
'key2' => new NotBlank
];
I can also build one array containing both.
Againt, the object/array is built dynamically, i cant validate the container itself. It's about the keys inside it that are definitions on its own.
So what i basically would want is:
$validator->validate($array, $constraints);
I can imagine you need a custom MetaDataFactory / Loader / Context class or something, the problem is simply that the callback validator needs to access $this->getRoot() to get to the other values
Nevermind that, you would need something like a CallbackLoader in which you create your own properties => constraints mapping. But the LoaderInterface requires a concrete implementation of ClassMetaData, which on his own has no way of dealing with arrays or ArrayObjects, unless you have methods/properties on that ArrayObject. But--since my container is built dynamically, i can't have that. Method methods are not an option because of the property/method_exists calls.

Use Validation in FormType or in Entity / Yaml

Which Differents are when use Validation Entity or in Yaml or in FormType?
form Type
....
->add('email', 'text', array (
'constraints' => array (
new Email(array('message' => 'error Email'))
)
))
....
YAML
properties:
email:
- Email:
message: error Email.
Entity
{
/**
* #Assert\Email(
* message = "error Email",
* )
*/
protected $email;
}
All These methods are the same ?
They are not the same! You mixed up entity validation and form validation:
Entity validation belong to entities. This means that it isn't matter whether the new data come from a form or ajax query or you just set some constant data. Validation is triggered by calling a validation on the entity. Note: entity validation runs on form validation too.
Form validation belong to forms. This means that you can validate form values with them (on calling $form->isValid()). But this can result invalid entities because nothing guarantees that your entities will be consistent (just the forms).
For this reason Symfony recommends using entity validation instead of form validators.
Apart from that, there is no difference among annotation, yml, xml or php format. Only the precedences.
I think they would apply the same validation constraints.
I tend to keep all constraints in validation.yml because in my point of view is the most clean way to do it. Also more compatible with Translations.
But all depends on the context and the project you are working on.
UPDATE: After reading Riska's entry I agree with him. The result at the end is the same, but he has the right point there.
Is there a way to use the same validation.yml so the constraints applied to entites are applied to the formtype as well
for instance, if title field in entity is 50charsm ax length, title field in formttype as well.
so we can avoid specifying max length in the add-method of the formtype.
In summary
how to use entity validation constraint in formtype so same constraitn ( required max length ) etc are auto applied ?

Set values on Symfony2 validation with no form

I'm coding an API and I'm doing the create method. I'm doing the following without needing a form:
$params = array('title' => 'test', 'parent_id' => 781);
// bind data
$place = new Place();
$place->bind($params);
// validate params
$errors = $this->validator->validate($place);
I need to check that parent_id is a correct value (its object exist - i know how to do this) and after that, I need to set some values dependent on the parent. So at the end the Place object will have the fields: title, parent_id, level, country_id for example.
How would you do this? On the validation? How? If not, how to avoid calling two times the DB to get the parent object?
You should first validate & then set any additional values afterward. Anything that modifies the value does not belong in the validator.
If your using doctrine, it should load the parent object into memory when you first access it, so it won't need to actually query the database again when you access the parent object a second time.

Resources