Sonata admin – blank page on production when ModelManagerException is thrown - symfony

I have defined unique constraint on one property of my entity.
/**
* #var string
* #ORM\Column(type="string", length=10, unique=true)
*/
protected $customID;
In Sonata admin, when new object is created with same ID, blank page on production is shown (in dev production, I can see that ModelManagerException is thrown, which is expected result).
How can I display an error on production?

Maybe use https://symfony.com/doc/current/reference/constraints/UniqueEntity.html for that field and it will show validation error before saving so no exception will be thrown.
Example:
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity
* #UniqueEntity("customID")
*/
class YourEntity {}

Related

Doctrine throw error: "A new entity was found through the relationship" after removing entity

Let's say I have two entities, Project and User with relation.
Project.php
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(onDelete="SET NULL")
*/
private $creator;
When I remove the User entity, the doctrine leaves the User object(without ID) in the Project entity. In a normal situation, this is fine but I am using DomainEvents. In this scenario, after removing the User entity, DomainEvent triggers saving some data in the DB and secondary saving data(after removing) throw this error. This happens because of now in the Project entity we have the detached(from the EM) User object without ID.
I thought about a listener, that will remove empty objects in the entity after removing, but I am not sure that is a good variant
What is the best variant for solving this error?
The onDelete option doesn't apply a cascade removing.
If you want to do so I think you should have to add the cascade={"remove"} option to the ManyToOne.
Try as following :
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", cascade={"remove"})
* #ORM\JoinColumn(onDelete="SET NULL")
*/
private $creator;
Removing entity in doctrine

SonataAdminBundle: set permission depending on field value

I have a working SonataAdmin+FOSUser (WITHOUT SonataUserBundle) setup with roles and ACL enabled. This is working fine, every user has access to different admins depending on their roles.
Now I need to go a bit deeper. I would like to restrict access to one of the admin depending on the value of an association of the underlying entity.
Lets say I have this:
/**
* #ORM\Entity
*/
class Content
{
/**
* #var string
*
* #ORM\ManyToOne(targetEntity="ContentType", inversedBy="contents")
*/
private $type;
}
/**
* #ORM\Entity
*/
class ContentType
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
}
I would like the following:
Users with ROLE_XXXXX : have access to all contents with content type name 'XXXXX'
Users with ROLE_YYYYY : have access to all contents with content type name 'YYYYY'
...
Of course it also means that when creating a new content or filtering the list of contents, users should not be able to select a content type on which they don't have any permission.
I have tried this with no luck:
php app/console acl:set --role=ROLE_XXXXX MASTER MyBundle/ContentType:2

using of unique constraint making the user unable to login in symfony2

I have used an unique constraint for the username in the registration form of the user.
User entity has following code
/*
* #UniqueEntity(fields="username",message="Username is already in use")
*/
class users
{
/**
* #var string
* #Assert\NotBlank(message="username should not be blank")
* #ORM\Column(name="username", type="string", length=40)
*
*/
private $username;
/**
* #var string
* #Assert\NotBlank(message="password should not be blank")
* #ORM\Column(name="password", type="string", length=40)
*/
private $password;
}
For registration every thing went fine with this entity when comes to login it is showing error username already in use. Can we keep the unique constraint within controller i.e within form.so that only for registration form uniqueness is applied.
Use validation groups:
http://symfony.com/doc/2.1/book/validation.html#validation-groups
(when you follow the link - you'll see very similar case: user and registration)
edit:
I assume that you have an "user_type" field in your user entity (for example possible values could be: "normal_user" and "affiliate"). If so, then you just need specify these two fields combination as a unique. Like this:
#UniqueEntity(fields={"username", "user_type"},message="Username is already in use") */

Doctrine2 doesn't load Collection until a method is called

When does Doctrine2 loads the ArrayCollection?
Until I call a method, like count or getValues, I have no data
Here is my case. I have a Delegation entity with OneToMany (bidirectional) relation to a Promotion Entity, like this:
Promotion.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Promotion
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions", cascade={"persist"})
* #ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
*/
protected $delegation;
}
Delegation.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Delegation
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Promotion", mappedBy="delegation", cascade={"all"}, orphanRemoval=true)
*/
public $promotions;
public function __construct() {
$this->promotions = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Now I do something like the following (with a given delegation)
$promotion = new Promotion();
$promotion = new Promotion();
$promotion->setDelegation($delegation);
$delegation->addPromotion($promotion);
$em->persist($promotion);
$em->flush();
Looking for the relation into the database is ok. I have my promotion row with the delegation_id set correctly.
And now my problem comes: if I ask for $delegation->getPromotions() I get an empty PersistenCollection, but if I ask for a method of the collection, like $delegation->getPromotions()->count(), everything is ok from here. I get the number correctly. Asking now for $delegation->getPromotions() after that I get the PersistenCollection correctly as well.Why is this happening? When does Doctrine2 loads the Collection?
Example:
$delegation = $em->getRepository('Bundle:Delegation')->findOneById(1);
var_dump($delegation->getPromotions()); //empty
var_dump($delegation->getPromotions()->count()); //1
var_dump($delegation->getPromotions()); //collection with 1 promotion
I could ask directly for promotions->getValues(), and get it ok, but I'd like to know what is happening and how to fix it.
As flu explains here Doctrine2 uses Proxy classes for lazy loading almost everywhere. But acessing $delegation->getPromotions() should automatically invoke the corresponding fetch. A var_dump get an empty collection, but using it- in a foreach statement, for example- it is working ok.
Calling $delegation->getPromotions() only retrieves the un-initialized Doctrine\ORM\PersistentCollection object. That object is not part of the proxy (if the loaded entity is a proxy).
Please refer to the API of Doctrine\ORM\PersistentCollection to see how this works.
Basically, the collection itself is again a proxy (value holder in this case) of a real wrapped ArrayCollection that remains empty until any method on the PersistentCollection is called. Also, the ORM tries to optimize cases where your collection is marked as EXTRA_LAZY so that it is not loaded even when you apply some particular operations to it (like removing or adding an item).

Symfony: How do I annotate entity properties that are objects to get Doctrine to store a foreign key?

I'm still getting to grips with Symfony and Doctine and I appreciate this might sound overly simple.
I have at present two basic entities: WebSite (having id and canonicalUrl properties) and Job which has, as one property, a WebSite.
A Job has one WebSite; a WebSite can be referenced by many Jobs. Both are under the same namespace.
Relevant here is the Job entity:
/**
*
* #ORM\Entity
*/
class Job
{
/**
*
* #var integer
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #var WebSite
*/
protected $website;
}
In database terms, a persisted Job should be storing the id of the relevant WebSite.
Without any changes to the above, calling php app/console doctrine:migrations:diff generates a new migration for a table named Job with a single id field.
How do I annotate Job::website such that Doctrine knows to create an integer field and to get the value as the id of the Website object?
You must explicitly define the relationship. The shortest would be
/**
* #ORM\Entity
*/
class Job
{
/**
* #var WebSite
*
* #ORM\ManyToOne(targetEntity="Website")
*/
protected $website;
}
However, should you find yourself wanting to tweak the relationship to better suit your needs, have a look at the annotation reference (ManyToOne and JoinColumn for this particular case). There's also quite a comprehensive article about association mapping, which you might find interesting.

Resources