Symfony2 Override Constraints - php

I have BaseEntity class:
class BaseEntity
{
/**
* The name.
*
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true, nullable=false)
* #Assert\Length(min=2, max=255, minMessage="default.name.short", maxMessage="default.name.long")
* #Assert\NotBlank(message = "default.name.not_blank")
*/
private $name;
}
and
class UserEntity extends BaseEntity
{
/**
* {#inheritDoc}
*
* #Assert\Length(min=2, max=255, minMessage="user.name.short", maxMessage="default.name.long")
* #Assert\NotBlank(message = "user.name.not_blank")
*/
private $name;
}
Now, When I post a new UserEntity into the form with long or short name Symfony gives me 2 errors: (for long:)
default.name.long
user.name.long
But I want it to show only ONE error, so :
- user.name.long
e.g. I want to override, but do not add another one

I think what you are looking for a validator group. So you can split up you validation rules into groups.
There is a excellent documentation about this feature:
http://symfony.com/doc/current/validation/groups.html

Maybe a Custom Validation Constraint could help you if you could (depending of your application logic) remove those two validations and make your own.
Something like this maybe?
http://symfony.com/doc/current/cookbook/validation/custom_constraint.html

If you're happy to set up at least some of your validation rules via a YAML file rather than annotations, you can override the base class's validation settings without needing to edit the class file itself.
Your YAML file would look something like this and would need to be in a location like src/YourApp/YourBundle/Resources/config/validation.yml to be picked up automatically:
BaseEntity:
properties:
name:
- NotBlank:
message: user.name.not_blank
- Length:
min: 2
minMessage: user.name.short
max: 255
maxMessage: default.name.long
If you want to put your validation file in a non-standard location, see https://stackoverflow.com/a/24210501/328817

Related

Is doctrine Entity validation enough?

I have an Entity class which already has constrains:
/**
* #ORM\Column(type="string", length=255)
*/
private $X;
/**
* #ORM\Column(type="integer")
*/
private $Y;
In my controller i'm getting post data from form and using setMethods on entity class:
$property = new PropertyEntity();
$property->setX($request->request->get('X'));
$property->setY($request->request->get('Y'));
next step - save to db.
Do I need to do additional validation on post data ? I though I need to use validation library but i'm not sure if it will only add unnecessary overhead since "#ORM" is already form type is already doing some validation.
Any general idea how and where to write validation ?(pseudocode is enough)
Good question!
ORM mapping map the PHP class to the doctrine metadata (Model).
Assert is a mechanism to validate objects received from form (View/Controller).
This means that you can use assert on objects that are not entities or that you cannot use a mapped field in your formType
You can make validation in the annotation of the field. example:
/**
* #Assert\NotBlank
* #ORM\Column(type="string", length=255)
*/
private $X;
/**
* #Assert\NotBlank
* #ORM\Column(type="integer")
*/
private $Y;
Don't forget to add:
use Symfony\Component\Validator\Constraints as Assert;
More validation constraints are in this link:
https://symfony.com/doc/current/validation.html#basic-constraints

FOSUserBundle ignore password field

So I'm using the FOSUserBundle with LDAP as my authentication method, and I'm wondering whether there is a way to remove/ignore the password field for my FOSUser entity?
I realize removal might not be ideal (in case it messes with internal logic), but the column is never used, and I'm forced to fill it when I'm creating FOSUsers from fixtures:
$user = new FOSUser();
$user->setDn($item["dn"]);
$user->setEnabled(1);
$user->setUsername($item["samaccountname"][0]);
$user->setUsernameCanonical(strtolower($item["samaccountname"][0]));
$user->setEmail($item["mail"][0]);
$user->setEmailCanonical(strtolower($item["mail"][0]));
$user->setDepartment($ldap_groups[$matches[1]]);
$user->setDepartmentDn($group);
$user->setPassword('blank'); // Is there away to avoid this?
$manager->persist($user);
You could actually remove the password, but you have to keep a getPassword() as that is defined in the UserInterface. In case you want to keep it, e.g. when you allow for multiple login types where you will need it again. I recommend setting the field as nullable. If you are using annotations it's as simple as adding nullable=true to the column:
/**
* #ORM\Column(type="string", name="password", nullable=true)
*/
So to override a column doctrine allows for Inheritance Mapping:
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #ORM\AttributeOverrides({
* #ORM\AttributeOverride(name="password",
* column=#ORM\Column(
* name = "password",
* type = "string",
* nullable=true
* )
* )
* })
*/
class FOSUser extends BaseUser implements LdapUserInterface
{
// Extended logic.
}
The password field still resides in BaseUser, but is overwritten by the #ORM\AttributeOverride annotation.

Use UniqueEntity on a Gedmo\Blameable field

I am using Gedmo extension in addition with Symfony 3.2 and Doctrine 2.5.6 and I'm encountering an issue. I can't make Gedmo\Blameable and UniqueEntity constraint work together. Indeed, the blamed field is still null at validation time. Is there any way to make it work or a possible work-around ?
Here is my entity
/**
* #UniqueEntity(
* fields={"author", "question"},
* errorPath="question",
* message="This author already has an answer for that Question"
* )
* #ORM\Entity
*/
class TextAnswer
{
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* #Gedmo\Blameable(on="create")
*/
private $author;
/**
* #Assert\NotNull()
* #ORM\ManyToOne(targetEntity="Question", inversedBy="textAnswers")
* #ORM\JoinColumn(name="question_id", referencedColumnName="id")
*/
private $question;
}
Thanks
EDIT : SOLUTION
Rather than manually setting the user (which removes Gedmo\Blameable interests), I created my own entity validator.
I give it doctrine and token storage as arguments so it can make a query on db to validate my criteria with the currently connected user (that will be later used by Gedmo\Blameable).
The BlameableListener is invoked during the Doctrine's flush operation, which normally happens after the entity has been validated. That's why $author is null at validation time.
The most straightforward workaround is to set $author yourself beforehand.

Best practise for placing custom Entity methods in Symfony

I'm creating Symfony project. And now I'm trying to find best practice for adding custom methods.. What is yours?
Visual explanation:
users table
id | name | surname
---+------+--------
1 | John | Smith
2 | Matt | Malone
Entity\User.php
namespace TestBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* User
* #ORM\Table(name="users")
* #ORM\Entity
*/
class User
{
/**
* #ORM\Column(name="id", type="string", length=36)
* #ORM\Id
* #ORM\GeneratedValue(strategy="UUID")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
/**
* #ORM\Column(name="surname", type="string", length=255, nullable=true)
*/
private $surname;
/**
* OneToMany
*/
private $userCompanies;
{{ Setters and Getters }}
}
Where I should store custom method, like:
function getFullName()
{
return sprintf("%s %s", $this->getName(), $this->getSurname());
}
Or more complex:
function getCurrentUserCompany()
{
foreach ($this->getUserCompanies() as $company) {
if ($company->isActive()) {
return $company;
}
}
return null;
}
Please note, that all data returned via JSON
So far I tried extending class, but annotations not working as expected. Placing custom methods in same file looks trashy, since there will be more than one of them.
But.. but if there is repositoryClass - maby there is place for custom methods as well?
Thanks!
If it's about methods that are used mainly for display purposes then they are very similar to the getters, in my opinion they best fit is in the Entity itself, so inside your User.php class.
The repository is for defining methods for getting the entity from your storage level (DB, cache...), but the view level (your twig) should take the data from the entity itself.
If you need something more complicated or you need to reuse it, like a date filter, then it's better to create a Twig extension.
Methods like that belong to entity class and there is no reason to split code. If many entity classes share some methods, you can always create shared base abstract class or trait for them.
If you really want separated files for sake of your aesthetic, then use traits, but remember that it's not proper and conventional use of them.

Symfony2: Duplicate definition of column 'id' on entity in a field or discriminator column mapping

I'm having trouble using entity inheritance in Symfony2. Here are my two classes:
use Doctrine\ORM\Mapping as ORM;
/**
* #Orm\MappedSuperclass
*/
class Object
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
/**
* #Orm\MappedSuperclass
*/
class Book extends Object
{
}
When I run php app/console doctrine:schema:create I get the following error:
[Doctrine\ORM\Mapping\MappingException]
Duplicate definition of column 'id' on entity 'Name\SiteBundle\Entity\Book' in a field or discriminator column mapping.
What may be causing this?
Thanks :)
Update:
You are right I missed this. Now I'm using single table inheritance with both classes being entities:
/**
* #Entity
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"object" = "Object", "book" = "Book"})
*/
But I still get the same error message.
Actually I found yml files in Resources/config/doctrine/, which were defining my entities, instead of just using annotations.
I removed these files and it's working now.
Thanks for your help !
I had same issue even after adding definitions to yml file. I was trying to add weight & max weight to a class and was getting:
Duplicate definition of column 'weight_value' on entity 'Model\ClientSuppliedProduct' in a field or discriminator column mapping.
Then I realized it requires columnPrefix to be different for similar types of fields and adding following in yml solved it for me:
`maxWeight:`
`class: Model\Weight`
`columnPrefix: max_weight_`
I had the same problem and error message but for me it was the other way around as #user2090861 said.
I had to remove the (unused)
use Doctrine\ORM\Mapping as ORM;
from my entity files, cause my real mapping comes from the orm.xml files.
I hope I can help with my answer many other people, cause this exception drove me crazy the last two days!
I ran into this in a different context - in my case, I had set up an entity for single-table inheritence using #ORM\DiscriminatorColumn, but had included the column in my class definition as well:
/**
* #ORM\Entity(repositoryClass="App\Repository\DirectoryObjectRepository")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="kind", type="string")
*/
class DirectoryObject {
// ...
/**
* #ORM\Column(type="string", length=255)
*/
private $kind;
}
Removing the #ORM\Column definition of kind fixed this issue, as Doctrine defines it for me.
Sometimes it's impossible to remove extra config files, because theay are located in third party bundle and auto_mapping is enabled.
In this case you should disable undesirable mappings in app/config.yml
doctrine:
orm:
entity_managers:
default:
mappings:
SonataMediaBundle: { mapping: false }
Any entity must contain at least one field.
You must add at least one field in Book Entity
Example
/**
* #Orm\MappedSuperclass
*/
class Book extends Object
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
I had the same error message but I had made a different mistake:
Class B had an ID and extended Class A which also had an ID (protected, not private). So I had to remove the ID from Class B.

Categories