Not Null field with SonataAdmin Bundle - symfony

Hi I have a problem with SonataAdminBundle.
I've created "Job" table in DB and I use in backend of my website.
When I insert data, I have an error with "not null" fields in my table Job.
For example I have "nb_comment" that is the number of comments of each job,so when I insert in backend all information about Job I don't use a NOT NULL field "nb_comment",and I have the following error :
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'nb_comment' cannot be null

add in #ORM annotation nullable=true
use Doctrine\ORM\Mapping as ORM;
...
/**
* #var integer $nb_comment
* #ORM\Column(name="nb_comment", type="integer", nullable=true)
*/
private $nb_comment;
or add Constraint validator with #Assert declaration and initialize in construct
use Symfony\Component\Validator\Constraints as Assert;
/**
* #var integer $nb_comment
* #ORM\Column(name="nb_comment", type="integer")
* #Assert\NotNull()
*/
private $nb_comment;
public function __construct()
{
$this->nb_comment = 0;
}

I had the same problem I think and it works for me. You have to initialize the variable nb_comment in the model with null, like this:
/**
* #var integer $nb_comment
*/
private $nb_comment = null;

Related

How to modify Symfony ORM insert\update query

I have project that is migrate to Symfony, that project have multiple tables,and also some tables are migrated to ORM, but now i need to incert/update from Symfony to table that have Entity but not managed by ORM. Problem consist in not null columns that require some value and in Entity I cannot define that value because of table relations.
It posible to edit MySql query before they submited to Database.
For example i have Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="p_user")
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
/**
* #var int
*
* #ORM\Column(name="user_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string|null
*
* #ORM\Column(name="name", type="string", length=55, nullable=true)
*/
private $name;
/**
* #var Permission
*
* #ORM\ManyToOne(targetEntity="Permission", inversedBy="user", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="permission_id", referencedColumnName="permission_id", onDelete="CASCADE")
*/
private $permission;
}
permission_id can be null but in database is not null with default value 0, same for name but with default value ''.
That mean when I make flush, ORM execute INSERT INTO p_user (name, permission_id) VALUES ('name', null), but I want also to execute INSERT INTO p_user (name) VALUES ('name').
It's possible to do that I wanted.
To achieve this you can provide default values.
private $permission = 0;
private $name = '';

Symfony2 DQL How to join the last row in a OneToMany relation

I have two entities related by a OneToMany relation:
<?php
namespace CRMBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* User
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="CRMBundle\Entity\ContactRepository")
*/
class User
{
/*...*/
/**
* #ORM\OneToMany(targetEntity="CRMBundle\Entity\Message", mappedBy="user", cascade={"persist"})
* #ORM\OrderBy({"datetime" = "DESC"})
*/
protected $messages;
/*...*/
}
And
<?php
namespace CRMBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Message
*
* #ORM\Table()
* #ORM\Entity
*/
class Message
{
/*...*/
/**
* #ORM\ManyToOne(targetEntity="CRMBundle\Entity\User", inversedBy="messages")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $user;
/**
* #var \DateTime
*
* #ORM\Column(name="Datetime", type="datetime", nullable=true)
*/
private $datetime;
/*...*/
}
My question is how to create a query in the UserController to get every user with the last message (i.e. the most recent according to the datetime attribute) of each user?
I think what you are looking for is in one of my previous answers to one of my own questions ^^
You have to use a subquery to select dynamically the most recent datetime value of one user's messages, and to join the message having this value.
To do this, you must define the (sub) query selecting the MAX value of message.datetime:
$qb2= $this->createQueryBuilder('ms')
->select('MAX(ms.datetime) maxDate')
->where('ms.user = u')
;
And then use it in your join clause, the whole function being in your UserRepository:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm', 'WITH', $qb->expr()->eq( 'm.datetime', '('.$qb2->getDQL().')' ))
->addSelect('m');
Your User (each of them) will then have a messages Collection, containing one (or null if no message from the user) message, which you will get this way:
$user->getMessages()->first();
But if you use the lazy loading function of Symfony, as you have already defined an orderby annotation on your user.messages attribute, calling
$user->getMessages()->first()
should return to you the most recent message (but will also load all the others silently).
To avoid this silent second DB query, you can join it directly to the query requesting your users:
$qb = $this->createQueryBuilder('u');
$qb ->leftJoin('u.messages', 'm')
->addSelect('m');

Doctrine Composite primary key foreign key

I realize a web application with Symfony 2 from an existing database.
I have set up an entity with a primary key consisting of two foreign keys.
example:
Entity1 with a composite primary key: property1 (PK), property2 (PK)
Entity2 primary key consists of two foreign keys: property1 (PK FK), property2 (PK FK), propriete3 (PK)
I don't how to implement this association:
In the entity2 i do :
/**
* #ORM\ManyToOne (targetEntity = "Entity1")
* #ORM\JoinColumns ({
* #ORM\JoinColumn (name = "property1" referencedColumnName = "property1")
* #ORM\JoinColumn (name = "property2" referencedColumnName = "property2")
* #ORM\Id
* #})
*/
private $entity1;
But I get an error:
It is not possible to map entity 'ExempleBundle\Entity\Entite1' with a composite primary key as part of the primary key of another entity 'ExempleBundle\Entity\Entite2#entite1'.
How to properly handle this kind of association with Doctrine
I tried to follow this example but I do not understand : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes
Can you give an example of two entities with a similar case and especially on how to make a joint in this case.
I found a work-around that gets around the issue, by defining a separate foreign key, using the original foreign key columns as the join columns.
/** #Id #Column(...) */
protected $property1;
/** #Id #Column(...) */
protected $property2;
/** #Id #Column(...) */
protected $property3;
/**
* #ManyToOne(targetEntity="Entity1")
* #JoinColumns({
* #JoinColumn(name="property1", referencedColumnName="property1"),
* #JoinColumn(name="property2", referencedColumnName="property2")
* })
**/
protected $foreignObject;
It is a example that works:
<?php
namespace Project\WorkflowBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="opinion")
*/
class Opinion
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="\Project\WorkflowBundle\Entity\Comision_Proyecto", inversedBy="opiniones")
*/
protected $comision;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="\Project\WorkflowBundle\Entity\Persona", inversedBy="opiniones")
*/
protected $persona;
/**
* #ORM\OneToMany(targetEntity="\Project\WorkflowBundle\Entity\Comentario", mappedBy="opinion")
*/
protected $comentarios;
}
the other class:
<?php
namespace Project\WorkflowBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="comentario")
*/
class Comentario
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(type="boolean")
*/
protected $privado;
/**
* #ORM\ManyToOne(targetEntity="\Project\WorkflowBundle\Entity\Opinion")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="comision_id", referencedColumnName="comision_id"),
* #ORM\JoinColumn(name="persona_id", referencedColumnName="persona_id")
* })
*/
protected $opinion;
}
Doctrine2 do not manage foreign composite keys to reference an entity with its composite primary keys
The cases where Doctrine2 manage correctly composite primary keys are mainly :
OneToMany: The associated entity (ArticleAttributes) uses as primary key, the primary key of the referenced entity (Artile) and an other self field (attribute)
Article (id, title, ...),
ArticleAttributes (#article_id, #attribute, value, ...)
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes
ManyToMany: Join-Table with Metadata
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#use-case-3-join-table-with-metadata
In your case, you want to reference an entity which hasn't got a unqiue identifier but a composite keys, Doctrine do not manage this case. You can only have composite key for association entity type.
Generally, I avoid to use composite keys for the main models. I reserved composite keys for model of association type.
So a solution is to use a primary key for your main model Entity1
Hope this helps.

FOS Userbundle - declare own userID field

I have installed the FOS UserBundle.
The problem is: the "id" field of my User-Table is called userID.
I can't change it bc of other Tables and Programming that is dependent on the userID field.
If i try to login, i get an error:
Unrecognized field: id
The problem seems to lie in the call for the id field:
UserManager ->findUserBy (array('id' => 1))
Can I somehow override FOS UserBundle so that the findby() method transfers id to userID?
Or do i get it totally wrong and have to do it another way?
Field names in the entity don't have to be identical to the field names in your sql table. So you can use "id" as field in your doctrine entity and map it to a "userID" field in your sql table.
If you are using Doctrine annotations for your user entity like in the FOSUserBundle documentation, this could do the trick:
/**
* #ORM\Id
* #ORM\Column(name="userID", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
I haven't tested it and there is a chance that it doesn't work, because the id field is always a bit "special", but it may be worth a try.
Generate your own UseBundle and add in define the entity something like this.
<?php
namespace Demo\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="Sciviz\UserBundle\Entity\UserRepository")
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/** #ORM\Column(name="first_name", type="string", length=255, nullable=true) */
protected $first_name;
..................
Also see this tutorial
http://knpuniversity.com/screencast/fosuserbundle-ftw
your column name "USER_ID" can be case sensitive.
/**
* #ORM\Entity
* #ORM\Table(name="user-table")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="USER_ID")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}

Small issue with persist()

I have the following two entities:
<?php
namespace Site\AnnonceBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Site\UserBundle\Entity\User;
/**
* Site\AnnonceBundle\Entity\Sujet
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Site\AnnonceBundle\Entity\SujetRepository")
*/
class Sujet
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
//Some code...
/**
*
* #ORM\ManyToOne(targetEntity="Site\UserBundle\Entity\User")
*/
private $user;
//getter/setter....
user Entity(FOSUserBundle) :
<?php
namespace Site\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table()
*
*/
class User extends BaseUser{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function getId() {
return $this->id;
}
}
when I created a "Sujet", I made(in SujetController.php):
$em = $this->getDoctrine()->getEntityManager();
$sujet->setResolu(false);
$em->persist($sujet);
$em->flush();
its works, But the inserted "Sujet" in the database refer to user null... so in the second version i made this:
$em = $this->getDoctrine()->getEntityManager();
$sujet->setResolu(false);
$sujet->setUser(new User($this->get('session')->get('user_id'))) ;//the user is already in the DB
$em->persist($sujet);
$em->flush();
but i get this error:
A new entity was found through the relationship 'Site\AnnonceBundle\Entity\Sujet#user' that was not configured to cascade persist operations for entity: . Explicitly persist the new entity or configure cascading persist operations on the relationship. If you cannot find out which entity causes the problem implement 'Site\UserBundle\Entity\User#__toString()' to get a clue.
I do not understand, I have already worked with another ORM (JPA) and it works in that way ...
how to tell "Sujet" about what is related to an entity already existing in database?
(sorry if my english is bad)
EDIT : its worked for me :
$user = $this->get('security.context')->getToken()->getUser();
$sujet->setUser($user);
$em->persist($sujet);
$em->flush();
Just in case, the error came from the fact you created a new User and linked it to the sujet without persisting it (as there is no cascade, the entity was linked to a none persisted entity, resulting in the error).
Your edit suggests you found a way to get the current User (this one is persisted, unlike the "new User") you made before.
You could also have done :
$repository = $this->getDoctrine()
->getEntityManager()
->getRepository('YourBundle:User');
$user = $repository->find($iduser);
$sujet->setUser($user);
It would have been a good solution if you wanted to make the edit "for another user".

Resources