Doctrine ODM Unique constraint not validating property - php

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;

Related

Symfony Doctrine ORM not a valid entity or mapped super class

I'm just making a new Entity as usual, but something goes wrong and console report this error and I couldn't generate the entity setter/getter:
[Doctrine\ORM\Mapping\MappingException]
Class "AppBundle\Entity\Admin_Actions" is not a valid entity or mapped super class.
Here is my Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="admin_actions")
*/
class Admin_Actions
{
/**
* #ORM\Column(name="id",type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="uid",type="string",length=100)
*/
private $uid;
/**
* #ORM\Column(name="type",type="integer")
*/
private $type;
/**
* #ORM\Column(name="linedate",type="datetime")
*/
private $linedate;
}
If I do doctrine:mapping:info:
[Exception]
You do not have any mapped Doctrine ORM entities according to the current configuration. If you have
entities or mapping files you should check your mapping configuration for errors.
I've just waste an hour trying to investigate the problem and I've already tried to rewrite it from new but I'm missing something. What's wrong with this?
May be datetime field has same name as function/implementation in doctrine, I have got same mistake by naming a table "condition" which may be condition function in MySql query

Doctrine MappedSuperclass and unique constraints

I have a scenario where I need to use the MappedSuperclass functionality of Doctrine (using Symfony2), and also create a unique constraint on some superclass columns. Let's say:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
class Base
{
/**
* #ORM\Column(type="integer", nullable=false)
*/
private $someColumn;
}
/**
* #ORM\Entity
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="column_idx", columns={"someColumn"})})
*/
class Concrete extends Base
{
}
The problem is at processing of #ORM\Table annotation during schema generation:
[Doctrine\DBAL\Schema\SchemaException]
There is no column with name 'someColumn' on table 'Concrete'.
Is there a way to define a unique constraint of a mapped superclass?
Since the answer author didn't post the answer himself, let me quote him:
Try to use protected instead of private for entity field. You should always use protected or public for entity fields

Symfony2: Custom identifier in Sonata entities

I have an entity with a custom id (i.e. UUID) generated on __construct function.
namespace AppBundle\Entity;
use Rhumsaa\Uuid\Uuid;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Person
{
/**
* #ORM\Id
* #ORM\Column(type="string")
*/
private $id;
/**
* #ORM\Column(type="string")
*/
private $name;
public function __construct()
{
$this->id = Uuid::uuid4()->toString();
}
This entity is used in sonata and also in other part of the project. I need this entity to have id before persisting and flushing it, so I can not use a an auto-increment.
So, the problem is sonata don't let me create entities because it takes the create option as and edit on executing because that entity already has an id, but this entity does not exists at this moment, so it fails.
The problem isn't the library for generating UUID, any value for 'id' fails.
Anyone know how to solve it? Another similar approach to solve the problem?
You shouldn't set your id in the constructor, but rather use the prePersist Doctrine event to alter your entity before persisting it for the first time.
You may use annotations to do so, see the Doctrine Documentation on prePersist.
The issue with setting the id in the constructor is that you may override it when you're retrieving it from the database, in which case it will be incorrect.

Symfony 2 + Doctrine 2 + inheritance

I'm searching for a solution for the following problem with a database inheritance using Doctrine 2 built in Symfony 2 framework. This is what I want to do...
I want to create two tables (UredniHodiny, KonzultacniHodiny) with the same interface as the abstract class Hodiny. This is how I'm trying to do it
<?php
// src/CvutPWT/ImportBundle/Entity/Hodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
abstract class Hodiny
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Osoba")
*/
protected $osoba;
/**
* #ORM\ManyToOne(targetEntity="Mistnost")
*/
protected $mistnost;
/**
* #ORM\Column(type="datetime")
*/
protected $zacatek;
/**
* #ORM\Column(type="datetime")
*/
protected $konec;
}
<?php
// src/CvutPWT/ImportBundle/Entity/KonzultacniHodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="konzultacnihodiny")
*/
class KonzultacniHodiny extends Hodiny
{
}
<?php
// src/CvutPWT/ImportBundle/Entity/UredniHodiny.php
namespace CvutPWT\ImportBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="urednihodiny")
*/
class UredniHodiny extends Hodiny
{
}
Now when I run php app/console doctrine:generate:entities CvutPWTImportBundle Symfony generates all variables (more precisely columns) from class Hodiny as private variables to both child classes. Now when I'm trying to create those tables with app/console doctrine:schema:update --force I'm getting errors that $id must be protected or weaker. When I change this protection manually I am able to create tables but there is only one column (id). But this is not what I was hoping for. Can somebody give me any advice what I'm doing wrong?
This is not table inheritance. Mapped super classes are just mapping inheritance.
The tables corresponding to your final entities will not be relied together in any way.
If you want real table inheritance (single table or joined table), use this: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#single-table-inheritance
If you still want to use mapped super classes, then you will have to put the #ORM\Id definition in both final classes. You can not put ids in mapped super classes.

Symfony 2 unique validator

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;
// ...
}

Categories