Symfony 2 unique validator - php

I'm trying to validate a form with some fields that need to be unique - username and email address. If I submit the form I get a database error. I want to use a validator like I did for everything else - right now I'm trying to use custom getters and isvalidUsername functions in the object and I'm not sure if using the entity manager in the object is the best way to do this. Heres what I'm working with so far...
Frontend\UserBundle\Entity\User:
properties:
email:
- NotBlank: ~
- Email: ~
username:
- NotBlank: ~
getters:
validUsername:
- "True": { message: "Duplicate User detected. Please use a different username." }
validEmail:
- "True": { message: "Duplicate email detected. Please use a different email." }
There are built in unique validators in the fosuserbundle but I haven't been able to figure out how to use them.

I know that this is an old question but I've just had to work this out so I thought I would share my solution.
I prefer not to use any bundles to handle my users so this is my manual approach:
<?php
namespace MyCorp\CorpBundle\Entity;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** User - Represent a User object */
class User implements AdvancedUserInterface {
/** #var integer $id */
private $id;
/** #var string $email */
private $email;
/** Constructor, Getters, Setters etc... */
/** Set a list of rules to use when validating an instance of this Class
#param Symfony\Component\Validator\Mapping\ClassMetadata $metadata */
public static function loadValidatorMetadata(ClassMetadata $metadata) {
$metadata->addPropertyConstraint('email', new MaxLength(255));
$metadata->addPropertyConstraint('email', new NotBlank());
$metadata->addPropertyConstraint('email', new Email());
$metadata->addConstraint(new UniqueEntity(array(
"fields" => "email",
"message" => "This email address is already in use")
));
}
}
As you can see I define my validation in the model itself. Symfony will call loadValidatorMetadata to let you load validators.

First of all, I'd recommend you using FOSUserBundle. It's quite flexible and you can save yourself some time you'd spend by fixing subtle bugs and testing if everything really works as intended.
Anyway, if you really want to build it yourself, you can at least inspire by bundle I mentioned above. They define custom validator and check for uniqueness in UserManager (validateUnique). Additionally, you have to register it as a service to provide UserManager via constructor injection. Then you just use it as a normal class validator.

There's the UniqueEntity validation constraint for ensuring that the user provides a unique value for a particular property.
Please refer to the documentation for examples using the various formats that Symfony supports. Here's an example using annotations:
// Acme/UserBundle/Entity/Author.php
namespace Acme\UserBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
// DON'T forget this use statement!!!
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #UniqueEntity("email")
*/
class Author
{
/**
* #var string $email
*
* #ORM\Column(name="email", type="string", length=255, unique=true)
* #Assert\Email()
*/
protected $email;
// ...
}

Related

Symfony - Optional inheritance with Doctrine

We encounter an issue with inheritance on Symfony 5.
We created a UserBundle bundle which includes a simple User entity (id, email, password): the purpose of this bundle is to be able to easily reimport it into our various projects.
In some projets, we want to extend this entity to add some specific fields (phone, address, ...), but that's not always the case.
Here is the code we had set up:
UserBundle > User class:
<?php
namespace MyCompany\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\MappedSuperclass()
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
...
User entity inherited:
<?php
namespace App\Entity;
use MyCompany\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #UniqueEntity(fields={"email"})
*/
class User extends BaseUser
{
/**
* #ORM\Column(type="string", length=50)
*/
private $phone;
...
The inheritance works fine: the problem comes from projects for which the User entity of the bundle is sufficient for us.
=> The User class of the bundle is defined as Mapped superclass in order to be able to extend it but Doctrine can't create an associated table if there is no class which inherits from it...
We could systematically create an empty User class in src/ which inherits from the User class of the bundle, but that doesn't seem super clean to me...
I went on this post but that doesn't seem to work: Doctrine Inheritance replacement
Could anyone help us on this problem? I imagine that a solution must exist...
Thank you in advance!
The idea below does not work.
As #Cerad already pointed out, the best approach probably really is to define the concrete User in each app. Thats also what FOSUserBundle does.
I'd go with the following approach: Declare the mapped superclass abstract.
/**
* #ORM\MappedSuperclass()
*/
abstract class AbstractBaseUser implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
...
And implement a concrete empty child class User inside your bundle.
/**
* #ORM\Entity
*/
class User extends AbstractBaseUser
{
}
That way each app can either use the User of your library or inherit from it.

Doctrine ODM Unique constraint not validating property

I can't figure out why Doctrine's ODM Unique constraint isn't working for me.
Below is a Page Class with the property "title", that needs to be unique amongst all Pages.
namespace App\Document;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique as MongoDBUnique;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use App\Repository\PageRepository;
use App\Document\Embeded\Section;
/**
* #ODM\Document(repositoryClass=PageRepository::class)
* #MongoDBUnique(fields="title")
*/
class Page
{
/** #ODM\Id() */
private $id;
/** #ODM\ReferenceOne(targetDocument=Site::class) */
private $site;
/** #ODM\Field(type="string")
* #ODM\UniqueIndex(order="asc")
*/
private $title;
// ...
Within the controller, $form->handleRequest($request) is called, followed by the query: if ($form->isSubmitted() && $form->isValid())
The form is always returned as valid. The ODM Unique constraint seems to be ignored. I've also tried to add a custom Validation Constraint and was met with the same issue.
Do I need to add any additional configuration to get this to work?
Symfony forms only validate the top-level object by design. In this case, the Page Class was attached to an embedded form.
Solution: add Symfony's #Valid() constraint to the property, within the top-level object.
/** #ODM\ReferenceOne(targetDocument="App\Document\Page", cascade={"persist"}, orphanRemoval=true)
* #ODM\Index
* #Assert\Valid()
*/
private $page;

How to use the symfony2 validator component in a legacy PHP project?

I have a legacy project that is not a symfony2 project, yet has the symfony2 components available.
I have Doctrine entities, and I want to be able to assert them via annotations. I do not have a container and cannot just call:
$container->get('validator')->validate($entity);
You can initialize the Validator via:
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator()
And you validate an entity via:
$violations = $validator->validate($entity);
If $violations is an empty array, the entity was validated, otherwise you will get the violations and can:
if (count($violations) > 0)
foreach($violations as $violation) {
$this->getLogger()->warning($violation->getMessage());
}
}
You assert your entity and make sure that all the annotations are used. The legacy project I was using e.g. did not include the #Entity annotation, and while it didn't bother Doctrine, it did bother the validation process.
<?php
namespace Hive\Model\YourEntity;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\Table;
use Symfony\Component\Validator\Constraints\NotNull;
/**
* Class AdGroupAd
* #Entity(repositoryClass="YourEntityRepository")
* #Table(name="your_entity_table_name")
*/
class AdGroupAd
{
...
/**
* #Column(type="string")
* #var string
* #NotNull()
*/
protected $status;
...
And finally, you must autload the annotations. Doctrine will not use the default autoloader, you have to specifically use the Doctrine\Common\Annotations\AnnotationRegistry
You can do it via:
AnnotationRegistry::registerAutoloadNamespace(
"Symfony",
PATH_TO_YOUR_WEB_ROOT . "/vendor/symfony/symfony/src"
);

Symfony2: several bundles to access name values stored in a database

I am new to Symfony2 and I am porting an old Symfony1 app to v2.
In my old app, I defined all of my models in one great big YML file. So the various 'components' were able to reference the same name value pairs (stored in the YML file).
I am now factoring out the functionality into bundles, and I want to completely decouple the bundles. I still need to access the name value pairs, but I want to store it centrally - in a database this time.
I want to keep my code DRY and so want to write the code for accessing the name value pairs only ONCE and some how use that in the separate bundles.
I also, want to provide centralised CRUD facilities for maintaining the name value pairs.
To summarise, my 2 questions are as follows:
How can I provide functionality (implemented once) to access name value pairs stored in a database, and make this functionality available to bundles that require it?
What is the best way to provide CRUD functionality for maintainance of the name value pairs? (is it by creating yet another bundle?)
I am not sure
You can create a Doctrine entity and request the keys you need. In order to code DRY, use a base entity and extend it to each pair type:
Pair entity:
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #MappedSuperclass
*/
class Pair
{
/**
* #Column(type="string", unique=true)
* #var string
*/
protected $name;
/**
* #Column(type="string")
* #var string
*/
protected $value;
// Getters & setters
// ...
}
SportPair entity:
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #Entity(repositoryClass="MyBundle\Entity\PairRepository")
* #Table(name="sport_pairs")
*/
class SportPair extends Pair
{
/**
* #Id
* #GeneratedValue(strategy="AUTO")
* #Column(name="id", type="integer")
* #var int
*/
protected $id;
}
Pair repository:
namespace MyBundle\Entity;
use Doctrine\ORM\EntityRepository;
class PairRepository extends EntityRepository
{
private $cache = array();
public function getValue($key)
{
if (!isset($this->cache[$key])) {
$pair = $this->findOneBy(array('name' => $key));
if (null !== $pair) {
$this->cache[$key] = $pair->getValue();
}
}
return $this->cache[$key];
}
}
Use SensioGenerationBundle to generate CRUD to manager Pair entities.
That's how you should proceed:
Create your application bundle (MyAppBundle).
(optional) Create a shared bundle (MySharedBundle)
Reference the bundles into the application kernel.
Create Pair and PairRepository into MyAppBundle.
(optional) Move those classes to MySharedBundle
Create derived pair classes into MyAppBundle.

Symfony2 __toString() generation

Does Symfony2 have an automatic __toString() generation based on the entity fields, or an annotation to say that the __toString() should be generated, similar to Java Roo?
I cannot find such a feature under the annotations reference, and the consensus among the Google Group seems to side with defining __toString() on the object.
If you use an IDE such as Net Beans, a simple CTRL+SPACE hotkey and click will automatically generate the __toString() for you, you'd simply need to fill out the refence to whichever attribute you want to use to represent the object.
Furthermore, you could take that one step further and define an Entity template (which is what I do in Net Beans). Something like this could save you some time, keeping in mind Doctrine2 is my ORM in this example, and I use the annotations method of defining my entities:
<?php
namespace Foo\BarBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
//use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class ${name}
{
/**
* #ORM\Id #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
public function __toString()
{
//return $this->get();
}
}
This automatically fills out the class name and has ArrayCollection commented out (so I can easily add that in if the entity requires it). This would leave you with simply needing to fill in the rest of whatever method you'd like to use for __toString();
${name} is a template variable in NetBeans.

Categories