Ordering Validation Constraints in Symfony2 - symfony

Hi working on an admin system. I want to run the Validation Constraint "NotBlank" before running #SecurityAssert\UserPassword. (otherwise there is unneeded database hit and are two different error messages for the user) Is this possible? Thanks!
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\NotBlank;
class YourClassName
/**
* #Assert\NotBlank( message = "For security reasons, please enter your current password.")
* #SecurityAssert\UserPassword(
* message = "Wrong value for your current password"
* )
*/
protected $oldPassword;

As #Qoop said in his comment the use of a sequence group like the example below could suit your needs:
use Symfony\Component\Security\Core\Validator\Constraints as SecurityAssert;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* #Assert\GroupSequence({"YourClassName", "After"})
*/
class YourClassName
/**
* #Assert\NotBlank(
message = "For security reasons, please enter your current password.")
* #SecurityAssert\UserPassword(
* message = "Wrong value for your current password",
groups={"After"}
* )
*/
protected $oldPassword;
Remember to add these validation groups when you build the form.

If you need a solution for one or two fields you could use Validation Callback. You just validate a field for specified constraints in the method and call them in your order.

It is not possible to do constraints with priorities with Symfony validator out of the box. But you can write own wrapper for validation with all features that you need.
See https://github.com/markwilson/symfony2-validator-priority-chain for example.

Related

symfony 5.4 validation constraints with groups are ignored

This annotation of a constraint works:
use App\Api\Dto\DtoInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
use Symfony\Component\Serializer\Annotation\Groups as SerializerGroups;
use Symfony\Component\Validator\Constraints as Assert;
class Report implements DtoInterface
{
/**
* #OA\Property(description="visited house id SAP format 4 character string", type="string")
*
* #SerializerGroups({"create", "update", "view", "collection"})
*
* #Assert\NotBlank
* #Assert\Length(4)
*/
public string $house = '';
and this doesn't
use App\Api\Dto\DtoInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
use Symfony\Component\Serializer\Annotation\Groups as SerializerGroups;
use Symfony\Component\Validator\Constraints as Assert;
class Report implements DtoInterface
{
/**
* #OA\Property(description="visited house id SAP format 4 character string", type="string")
*
* #SerializerGroups({"create", "update", "view", "collection"})
*
* #Assert\NotBlank(groups={"create", "update"})
* #Assert\Length(min=4, groups={"create", "update"})
*/
public string $house = '';
Lucky for me in this case ignoring groups will still work out for me, but in other cases it might not.
The Symfony documentation says that this is how it should work.
What is wrong with my second example? Why are those validators ignored?
Please note that in the second detection, #Assert\NotBlank(groups={"create", "update"}) sterilization groups were detected in the validators, in contrast to the first example, which means that they are presented only to the given groups, and all other requests with unspecified loads are ignored.
In other words, the restrictions in the second example will only work for create and update, and for the view and collection groups they will be ignored, since they are not specified in the annotations.

Trigger entity validation programmatically

Question is simple.
I have an Entity with validation contraints.
I also have a service which is going to create such entities.
Problem is, it does not trigger validations like #Assert\Expression. See below.
This is a huge bummer. How can I trigger such validation programmatically please ?
I need to automatically validate a Booking instance against all the constraints defined in the Booking class definition.
<?php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass="App\Repository\BookingRepository")
*/
class Booking
{
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Slot", inversedBy="bookings")
* #Groups({"booking"})
* #ORM\JoinColumn(nullable=true)
* #Assert\Expression(
* "value == null or (value.getStatus() == constant('App\\Entity\\Slot::STATUS_ACTIVE'))",
* message="Vous ne pouvez pas réserver cette date."
* )
*/
private $slotId;
}
You need to use the validator service from Symfony (documentation about the Validator component).
Call the validate method on your newly created entity in your service.

Symfony Form Validation getters always triggering/failing

I'm using Symfony's Validator Getter Component In conjunction with symfony forms.
In one of my entities files, I have:
use Symfony\Component\Validator\Constraints as Assert;
class StudentPaper
{
.....
/**
* #Assert\IsTrue(message = "You must include a paper with your submission")
*/
public function hasPaper()
{
// I originally had logic that checked the validity, but just
// changed the return value to 'true' to prove that it's not working.
return true;
}
}
Unfortunately, the validation always fails (even when I hardcore the return value to be true). The validation code doesn't seem to be executed, and the form triggers the error. I even tried replacing it with IsFalse and hard coding false. Same result.
Anyone come across this?
Symfony 2.8.
PHP 5.6.15
Well, I can't fully explain what the actual problem is (because I don't know), but I did find a solution.
In my StudentPaper entity I had
/**
* Bidirectional - Student Papers have one file.
*
* #ORM\OneToOne(targetEntity="StudentPaperFile", inversedBy="student_paper", cascade={"persist", "remove"}, orphanRemoval=true)
* #ORM\JoinColumn()
* #Assert\Valid()
*/
protected $paper;
as a property. Turns out that having a property named paper AND a validation getter called hasPaper() was causing unexpected behavior. As soon as I changed the function name from hasPaper() to hasTesting() or hasSubmittedPaper then the getter worked as it was intended.
So the solution is that the getter function cannot be get/is/has + a mapped property name.

symfony2 UniqueEntity constraint on username not working

I am trying to implement something as common as preventing creation of users with same username. The UniqueEntity constraint has worked for me on other entities, but I guess the user is special since it extends an already existing entity.
Code below shows clearly what I want to do. But it behaves as if the constraint wasn't there at all (of course ending up at a MySql error instead since DB won't allow duplicate entries of username).
Could it have something to do with the fact that the username property isn't declared in this file but merely inherited since I am extending the FOS\UserBundle\Model\User? If so how do I get around that?
// src/BizTV/UserBundle/Entity/User.php
namespace BizTV\UserBundle\Entity;
use BizTV\UserBundle\Validator\Constraints as BizTVAssert;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
//use FOS\UserBundle\Entity\User as BaseUser; //deprecated
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use BizTV\BackendBundle\Entity\company as company;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #UniqueEntity(fields = "username", message = "En användare med det namnet finns redan, försök igen.")
*/
class User extends BaseUser implements AdvancedUserInterface
You have to set also at the property username the unique=true flag.
Something like this:
* #ORM\Column(name="username", unique=true)

Symfony2: How to make username of FOSUserBundle user unique

I have my own User Class, which inherits FOS\UserBundle\Entity\User. Additionally I wrote my own registration routine. Now I have the problem that the form does not make sure that the username is unique. I always get:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'myusername' for key 'UNIQ_2DA1797792FC23A8'
I tried adding the #UniqueEntity("email") annotation as stated in the documentation1, but without any effect.
Someone knows what might be wrong?
If you're using the fos_user bundle, you can simply use the UniqueEntity constraint: http://symfony.com/doc/2.0/reference/constraints/UniqueEntity.html.
To implement it, just make sure your User class constains the proper use statements, and then the annotations, like so (assuming you're using annotations):
<?php
// ...
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #UniqueEntity("email")
* #UniqueEntity("username")
*/
class User extends BaseUser
{ /* ... */ }
The constraint exists in the FOS bundle already. You probably need to set the validation_groups option on your form to array('Registration').
You can try this on the validation.yml with your user entity validation:
constraints:
- FOS\UserBundle\Validator\Unique:
property: usernameCanonical
message: 'This username already exists. Please choose another one.'

Resources