Best practice symfony validation - symfony

I'm asking myself about the validation when an user sends a form... I saw the documentation and a tutorial. They explain 2 ways to valid datas:
Documentation:
You have to create the file:
/Resources/config/validation.yml
Then add something like that:
Acme\BlogBundle\Entity\Author:
properties:
name:
- NotBlank: ~
Tutorial I saw on Internet:
They add constraints directly in Entity like:
use Symfony\Component\Validator\Constraints as Assert;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string", length=255)
* #Assert\MinLength(10)
*/
private $title;
There is a best pratice? Should I write all constraints in validation.yml or in my entities? Is it possible to face a form without entity behind?
Benefit from separate file:
You have all constraints in only one file
Benefit from entity file:
You have sql constaints with your form constaints and you have the field type.
So, what should I use? Or no one cares about that?
Edit: I don't find any information about how to add a variable in validation.yml like:
Acme\BlogBundle\Entity\Author:
constraints:
- Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
fields: [name]
message: {{ name }} isn't available
In Entity:
#Assert\UniqueEntity(message='{{ name }} isn't available'
Best regards,

Should I write all constraints in validation.yml or in my entities?
You can, but you don't have to, it is more about personal preference. Personally, I prefer to validate input in my forms, like this:
$builder->add('contactPerson', 'text', array(
'label' => 'Contact person',
'constraints' => array(
new NotBlank(array('message' => 'This field can not be empty.'))
),
'required' => true,
));
Is it possible to face a form without entity behind?
Yes it is, but usually it is better to use entity behind. If you want to leave out the entity behind form, you just remove this line from your form's setDefaultOptions method:
'data_class' => '...'
After submitting the form, you can access form data by using $form->getData().
Benefit from separate file: You have all constraints in only one file
Benefit from entity file: You have sql constaints with your form
constaints and you have the field type.
So, what should I use? Or no one cares about that?
This is more about personal preference. Personally, I prefer to have validation and form in the same time. Searching for the validation in some other file when I want to make a change to some of my fields in form would take me more time.

Related

What does the constraint Required do?

What does the constraint Required do in the form builder? If a field was not submitted (not empty value!), I don't receive a corresponding error message. This field is just ignored.
$builder
->add('firstname', TextType::class, [ 'constraints' => [new NotBlank()], 'required'=>true])
->add('lastname', TextType::class, [ 'constraints' => [new NotBlank(),] ,'required'=>true])
How can say, that the field always MUST be submitted?
Thank you.
Required mean your field need a value tu be be submitted. It's similar to the HTML behaviour.
EDIT:
https://symfony.com/doc/current/reference/forms/types/form.html#constraints
https://symfony.com/doc/current/form/without_class.html#form-option-constraints
The issue is on your constraints, I don't know for sure but if adding those to your form don't fix your problem, have a look att adding assert to your Entity attached to your form
https://symfony.com/doc/current/reference/constraints/NotBlank.html
Then validate this entity in your controller
https://symfony.com/doc/current/validation.html
And relying on this you might add errors to the form.
A colleague has found the solution:
In the related entity, you need to define a callback-function like this:
/**
* Check bank account by "CUSTOMER" - not null
* Because NotNull() not working in form type!
* #Assert\Callback()
*/
public function validateBankaccount(ExecutionContextInterface $context)
{
if ($this->type == self::TYPE_CUSTOMER && is_null($this->bankAccount)) {
$context->buildViolation('Bank account is required!')
->atPath('bankAccount')
->addViolation();
}
}

Require a field in symfony2 server side

I have a form in Symfony2 which I am building with buildForm
I add constraints like so,
$builder
->add('firstName', 'text', [
'required' => true,
'constraints' => [
new NotBlank(),
],
]
)
Everything works fine until I delete the input from my html and submit it without the firstName. I don't get any errors and it submits normally. Is there a way to absolutely require the firstName, even if is not present in the submit data
You must use an assert with your entity as explained in the symfony documentation here
like this:
class User
{
/**
* #orm:Column(type="string", nullable=false)
* #assert:NotBlank
*/
private $firstname;
}
You did not submit any data, the form is not submitted hence no validation is triggered.
Instead of:
$this->handleRequest($request);
Try to always submit the form even if the data is missing:
$form->submit($request->request->all());
I cannot guarantee this code is valid in your context since you did not provide your controller code.

Easyadmin is not recognizing boolean type

I am trying to implement a backend using easyadmin, I think its a great idea and I love the implementation... so far is going well, but I have a little problem, I want to show in the form a boolean field, for ex: 'published', my configuration looks like this:
Blog:
label: 'Posts list'
class: MyCompany\MyBundle\Entity\Post
list:
fields: ['title', 'published']
new:
fields:
- 'title'
- 'summary'
- 'body'
- { property: 'published', type: 'boolean' }
When I run this code, I get the error:
Could not load type "boolean"
This is how I define the field in the Entity:
/**
*
* #ORM\Column(name="published", type="boolean", length=1)
*/
protected $published = 1;
I know it's been a while since this question's posted, but for anyone still getting this error, in easyadmin documentation (https://github.com/javiereguiluz/EasyAdminBundle/blob/master/Resources/doc/book/4-edit-new-configuration.md) it is specified which types we need to use for each scenario (list, edit views).
In your question (edit scenario) so far the only workaround is to use "checkbox"as type in config.yml. Edit view only accepts Symfony Form Types (http://symfony.com/doc/current/reference/forms/types.html).
You don't have to specify type in configuration yml file. It will take automatically from entity.

Disable auto translation for input values in Symfony 2

Symfony2 automatically translate the input field values with type decimal or integer.
I have a two languages for my app: arabic and english
I created an Entity with the following field:
/**
* #var float $price
*
* #ORM\Column(name="price", type="decimal", scale=2, nullable=true)
*
* #Assert\Regex(pattern="/^[0-9]+(\.\d{1,2})?$/",message="Incorrect price.")
* #Assert\Type(type="float")
* #Assert\Min(0)
*/
private $price;
In form I let the sf to guess a field type:
$builder->add('price')
I load the form for editing this entity in Arabic Interface.
In the price field I see ١٢٫٤ instead of 12.40.
I can't save the form because HTML5 validation is failed.
If I enter 12.40 in the current field and save Entity, 12 will be saved, instead of 12.40.
Why? How to disable it? how to validate the Arabic digits?
Any suggestions?
EDIT: solved, see below
I found the answer why it happens here
As you can see, symfony register a ViewTransformer for these widget types:
$builder->addViewTransformer(
new IntegerToLocalizedStringTransformer(
$options['precision'],
$options['grouping'],
$options['rounding_mode']
));
Current transformer transform an integer value to localized string. It happens for the number widget (NumberToLocalizedStringTransformer) and money widget (MoneyToLocalizedStringTransformer) too.
So I think need to register a new FieldType which will not used a ViewTransformer.
EDIT: I solved the problem just disabling intl extension and now all numeric fields are using a default english numbers. If you enable the intl extension you should use only localized numbers in the input values, it's a default behavior.
This is an old post, but i hope my answer will help anyone encounters this issue.
Instead of disabling intl extension as suggested above, you can use Data Transformers in form type to manually set the default locale to English and that will let the fields to be shown with English digits.
1) Use Data Transformers to interrupt (hook into) the process of showing the field data.
2) Manually set Locale to English.
here is what i've done with dateOfBirth field in the form type:
$builder -> add(
$builder -> create(
'dateOfBirth', DateType::class, array(
'label' => 'Date of Birth',
'widget' => 'single_text',
'required' => false,
'html5' => false,
'attr' => ['class' => 'form-control']
)) -> addModelTransformer(new CallbackTransformer(
function($dateOfBirth) {
\Locale::setDefault('en');
return $dateOfBirth;
},
function($dateOfBirth) {
return $dateOfBirth;
}
))
);

How to update an unidirectional ManyToMany mapping in Symfony2?

I have been searching for an answer now for several hours and I can't find a clean solution by myself.
I have an entity called "Tag". You can add these tags to nearly everything, f.e. to an article, a news and so on. Therefor my entites (in this example an article) refer to these tags with an unidirectional ManyToMany mapping:
/**
* #ORM\ManyToMany(targetEntity="Tag")
* #ORM\JoinTable(name="tag2article",
* joinColumns={#ORM\JoinColumn(name="article_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
private $tags;
This relation is unidirectional, because then I don't want to have an articleTag, a newsTag etc. or several entities as joinTables. The doctrine manual calls unidirection ManyToMany relations "less common", because you can build such relations as 3 entities with an additional joinTableEntity. But this would result in too much entities of this kind.
When I create an article, these tags are added by:
foreach ($tagArray as $tagId) {
$tag = $entityManager->getRepository('myBundle:Tag')->findOneById($tagId);
if ($tag != null) {
$article->addTag($tag);
}
}
$entityManager->persist($article);
$entityManager->flush();
This works fine on insert. On update I do the same, but it doesn't work and I don't know why. The only solutions I found was to add this article to the tag, but this isn't possible though I am working with an unidirectonal relation.
In my ArticleForm, I just have a hidden field:
->add('tags', 'hidden', array(
'data' => '',
'property_path' => false
))
In this way I can add tags pretty easy with Ajax and write these tagIds in this hidden field.
My overall question is: Why does this way work on insert, but not on update? What can I do to fix this?
Many thanks for your help or any hints!!

Resources