symfony - unique entity constraint with not mapped field - validation

my goal is to validate an entity with a uniqueEntity constrainte on a field. This field is composed of 2 not mapped fields concatenated using a lifecycle callback PrePersist. The problem is that the validation does not occur and the system allows me to insert data into the database when it should not.
/**
* Recipe
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppBundle\Entity\RecipeRepository")
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(
* ignoreNull = false,
* fields={"amount"},
* message="Not valid"
* )
*/
class Recipe
{...}
...
/**
* #ORM\PrePersist()
*/
public function preSave()
{
$this->amount = $this->getAmountInteger() . '.' . $this->getAmountDecimal();
}

i have a entity with this definition and run fine, but your case is different because your set 'amount' in the preSave...
* #UniqueEntity(fields={"amount"}, message="Not valid")
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="unique_amount", columns={"amount"})})
And in the other entity i used
#ORM\Column(type="string", length=127, nullable=false, unique=TRUE)
The different is in the first case i use compuest key and define key in the fields={field1,field2}.. in the second example i use simple unique key.

Related

Many-to-Many Relations using non-"id" Primary Key in Doctrine

So I'd like to create two entities and make a many-to-many reference. I would love to make this association using a string primary key on one table. This seems to be really hard, at least it took me pretty much time trying without any results yet.
This is my approach:
First entity:
namespace Project\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="User")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $Id;
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="Users")
* #ORM\JoinTable(name="role_user",
* joinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="Id")},
* inverseJoinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="Name")}
* )
*/
private $Roles;
}
And the second:
namespace Project\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="Role")
*/
class Role
{
/**
* #ORM\Id
* #ORM\Column(type="string", length=256)
*/
private $Name;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="Roles")
* #ORM\JoinTable(name="role_user",
* joinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="Name")},
* inverseJoinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="Id")}
* )
*/
private $Users;
}
Output of ./app/console doctrine:schema:validate:
[Mapping] FAIL - The entity-class 'Project\AdminBundle\Entity\User' mapping is invalid:
* The referenced column name 'Id' has to be a primary key column on the target entity class 'Project\AdminBundle\Entity\User'.
* The referenced column name 'Id' has to be a primary key column on the target entity class 'Project\AdminBundle\Entity\Role'.
What do I miss?
Attention upper/lowercase! Doctrine generates its columns as lowercase per default. This solves the issue:
* joinColumns={#ORM\JoinColumn(name="User_Id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="Role_Name", referencedColumnName="name")}
This it over-complicated; it's enough to put this into the Role entity:
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="Roles")
* #ORM\JoinColumn(name="role_user", referencedColumnName="name")
*/
private $Users;
I only thought about this when writing the question.. what a good method to think about the problem again from scratch.
Cheers

Symfony2 - UniqueEntity no action

I have an entity named Test with two fields: id and name.
I would like to have the name as unique.
What I did:
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
...
/**
* Company\AppBundle\Entity\Test
*
* #ORM\Table(name="test")
* #UniqueEntity("name")
* #ORM\Entity(repositoryClass="Company\AppBundle\Entity\TestRepository")
*
*/
class Test
{
....
/**
* #var string$name
*
* #ORM\Column(name="name", type="string", length=200, nullable=false, unique=true)
*/
private $name;
....
In my controller, I am using:
if ($form->isValid()) {
....
But the validation goes through. Am I missing something?
The unique annotation is for doctrine, it passes it to the database level and the error gets thrown from there. It will not know that the entity exists until you try to save it. To do the checks in php you have to query for the unique attribute yourself and check if it exists...

Zend framework identical validator does not work with annotations

I'm trying to validate a password confirmation field from another password field using zend validator Identical.
I use annotations to declare validators in my entity class. But it doesn't seem to work...
/**
* #ORM\Column(type="string", nullable = false)
* #Annotation\Attributes({"type":"password", "class":"form-control","name":"mypass"})
* #Annotation\Options({"label":"Password"})
* #Annotation\Filter({"name":"StringTrim", "name":"StripTags"})
*/
protected $password;
/**
* #Annotation\Attributes({"type":"password", "class":"form-control","id":"password_confirm"})
* #Annotation\Options({"label":"Confirmation"})
* #Annotation\Validator({"name":"Identical", "options":{"token" : "mypass"}})
* #Annotation\Filter({"name":"StringTrim", "name":"StripTags"})
*/
protected $password_confirm;
Can' you tell me what's wrong in my declaration ?
You'll need to set strict to false if you want to compare with an element. Otherwise it will just validate it against the string value of "mypass" instead of the object named "mypass".
/**
* #Annotation\Options({"label":"Confirmation"})
* #Annotation\Validator({"name":"Identical", "options":{"strict": false, "token" : "mypass"}})
* #Annotation\Filter({"name":"StringTrim", "name":"StripTags"})
*/
protected $password_confirm;

Symfony2+Doctrine - Validating one-to-many collection of entities

I have a form to create a new entity. That entity has a collection of other entities that are also entered in that form.
I want to use the validation options of the entity in the collection to validate those entities but it does not work. The validation rules of the "main" entity (Person) are checked, but the validation rules of the entities in the addressList collection (Address) are not checked. When I input invalid information in the fields, the submitted form is successfully validated.
In this example, the annotation for street is not used on validation.
class Person
{
...
/**
* #ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
*/
protected $addressList;
....
}
class Address
{
...
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="addressList")
* #ORM\JoinColumn(name="person_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $owner;
/**
* #ORM\Column(type="string", length=75)
* #Assert\MinLength(
* limit=3,
* message="Street must have atleast {{ limit }} characters."
* )
*/
protected $street;
...
}
How can I get the form to validate the supplied Address entities?
I had the same problem but was solved with:
/**
* #ORM\OneToMany(
* targetEntity="Entity",
* mappedBy="mappedEntity",
* cascade={"persist" , "remove"}
* )
* #Assert\Valid
*/
I use this:
use Symfony\Component\Validator\ExecutionContextInterface;
class Person
{
...
/**
* #ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
*/
protected $addressList;
....
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if (!$this->getAddressList()->count()) {
$context->addViolationAt(
'addressList',
'You must add at least one address',
array(),
null
);
}
}
}
http://symfony.com/doc/current/reference/constraints/Callback.html
Just add annotation assert like following
/**
* #Assert\Count(
* min = "1",
* minMessage = "You must specify at least one"
* )
* #Assert\Valid
*
*/
protected $name_of_collection_property;
You could also use the "Valid" constraint with the "All" constraint :
/**
* #ORM\OneToMany(targetEntity="Address", mappedBy="owner", cascade={"persist", "detach"})
* #Assert\All({
* #Assert\Valid
* })
*/
protected $addressList;

Symfony2 validation exception with unique constraint

I have an entity "Movie" which has a unique constraint through doctrine annotation. Based on the movie entity I have auto generated a CRUD layer. When I now try to add a new movie I get the following exception:
Only field names mapped by Doctrine can be validated for uniqueness.
When the constraint is removed everything works fine. Do somebody has an idea where the problem lays and how I can resolve it?
My guessing is the entity, because it is new, is not sync with the EntityManager and therefore could not check the constraint. Am I'close?
I'm using Symfony 2.0.1 with Doctrine 2.1.1, MySQL as Database.
Thanks,
-lony
The "Movie" Entity:
/**
* #ORM\Table()
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="string")
* #ORM\DiscriminatorMap({"movie" = "Movie", "series" = "Series"})
*
* #DoctrineAssert\UniqueEntity("title_orginal")
*/
class Movie {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $titleOrginal
*
* #ORM\Column(name="title_orginal", type="string", length=255, unique="true")
*/
private $titleOrginal;
..
Your syntax is wrong.
Use this:
#DoctrineAssert\UniqueEntity(fields={"title_orginal"})
instead of
#DoctrineAssert\UniqueEntity("title_orginal")
You can then customize the violation message like this :
#DoctrineAssert\UniqueEntity(fields={"title_orginal", message="my.custom.message"})
and translate this message by using a validators.xliff file (it must be named like that).
I tell you this because I struggled the other day with it and was obliged to debug to find about this validators.xliff naming convention.
I think there is a small typo:
#DoctrineAssert\UniqueEntity(fields={"title_orginal", message="my.custom.message"})
should be:
#DoctrineAssert\UniqueEntity(fields={"title_orginal"}, message="my.custom.message")
and for several fields
#DoctrineAssert\UniqueEntity(fields={"title_orginal", "field2"}, message="my.custom.message")

Resources