Inheritance of Symfony Lifecycle Callback annotations - symfony

I am on Symfony 4, and I have a problem with Lifecycle callbacks. I have two classes, one model and a child of this model. I would like that every child of the model have the same PrePersist callback but the callback is not triggered. Is it normal or did I do something wrong ?
<?php
// src/Models/QuestionModel.php
namespace App\Models;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ODM\MappedSuperclass
* #ODM\HasLifecycleCallbacks
*/
class QuestionModel
{
/**
* #ODM\Id(strategy="AUTO")
*/
protected $id;
/**
* #ODM\Field(type="date")
*/
protected $createdAt;
/**
* #ODM\PrePersist
*/
public function setCreatedAtValue() {
$this->createdAt = new \DateTime();
}
and the child:
<?php
// src/Document/CDN/Question.php
namespace App\Document\CDN;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use App\Models\QuestionModel;
/**
* #ODM\Document(collection="CDNQuestion")
* #ODM\HasLifecycleCallbacks
*/
class Question extends QuestionModel
{
}
If it is normal that it does not work, do you have a solution for my problem ?
Thx

I would recommend to create separate class for that. Trait should be excellent choice. I have something like that in my projects.
trait TimestampableTrait
{
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", nullable=false)
*/
protected $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", nullable=true)
*/
protected $updatedAt;
/**
* #ORM\PrePersist
*/
public function updateCreatedAt()
{
$this->createdAt = new \DateTime();
}
/**
* #ORM\PreUpdate
*/
public function preUpdate()
{
$this->updatedAt = new \DateTime();
}
/**
* #return \DateTime|null
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* #return string
*/
public function getCreatedAtFormatted()
{
if ($this->createdAt instanceof \DateTime) {
return $this->createdAt->format('d/m/Y h:i:s A');
}
return '';
}
}

Related

Cannot create an instance of DateTime from serialized data

I have a problem with the date.
Maybe I don't understand something in the process of serialization, but, when, I send a datetime to Api-Platform (Symfony) for example
dateEvaluation: "2017-12-05T11:52:00.000Z"
I obtain this message of error
Cannot create an instance of DateTime from serialized data because its constructor requires parameter "time" to be present.
This is my Entity
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ORM\Entity(repositoryClass="App\Repository\EvaluationRepository")
* #ORM\HasLifecycleCallbacks()
* #ApiResource(attributes={
* "normalization_context"={
* "groups"={"Evaluation"}
* }
* })
*/
class Evaluation
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"NotesEvaluations", "Evaluation"})
*/
private $id;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $created;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $updated;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
* #Groups({"Evaluation"})
*/
private $dateEvaluation;
/**
* #var string
*
* #ORM\Column(type="text")
* #Groups({"Evaluation"})
*/
private $commentaire;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\Personnel")
* #Groups({"NotesEvaluations", "Evaluation"})
*/
private $auteur;
/**
* #var
*
* #ORM\ManyToMany(targetEntity="App\Entity\Personnel")
*/
private $autorises;
/**
* #var integer
*
* #ORM\Column(type="integer")
*/
private $annee;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\Module", inversedBy="evaluations")
* #Groups({"Evaluation"})
*/
private $module;
/**
* #var Boolean
*
* #ORM\Column(type="boolean")
* #Groups({"NotesEvaluations"})
*/
private $visible;
/**
* #var Boolean
*
* #ORM\Column(type="boolean")
* #Groups({"NotesEvaluations"})
*/
private $modifiable;
/**
* #var
*
* #ORM\ManyToOne(targetEntity="App\Entity\TypeGroupe")
* #Groups({"Evaluation"})
*/
private $typegroupe;
/**
* #var float
*
* #ORM\Column(type="decimal")
* #Groups({"Evaluation"})
*/
private $coefficient;
/**
* #return float
*/
public function getCoefficient(): float
{
return $this->coefficient;
}
/**
* #return mixed
*/
public function getTypegroupe()
{
return $this->typegroupe;
}
/**
* #param mixed $typegroupe
*/
public function setTypegroupe($typegroupe): void
{
$this->typegroupe = $typegroupe;
}
/**
* #return \DateTime
*/
public function getDateEvaluation(): \DateTime
{
return $this->dateEvaluation;
}
/**
* #param \DateTime $dateEvaluation
*/
public function setDateEvaluation(\DateTime $dateEvaluation): void
{
$this->dateEvaluation = $dateEvaluation;
}
/**
* #return string
*/
public function getCommentaire(): string
{
return $this->commentaire;
}
/**
* #param string $commentaire
*/
public function setCommentaire(string $commentaire): void
{
$this->commentaire = $commentaire;
}
/**
* #param float $coefficient
*/
public function setCoefficient(float $coefficient): void
{
$this->coefficient = $coefficient;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return \DateTime
*/
public function getCreated(): \DateTime
{
return $this->created;
}
/**
* #param \DateTime $created
*/
public function setCreated(\DateTime $created): void
{
$this->created = $created;
}
/**
* #return \DateTime
*/
public function getUpdated(): \DateTime
{
return $this->updated;
}
/**
* #param \DateTime $updated
*/
public function setUpdated(\DateTime $updated): void
{
$this->updated = $updated;
}
/**
* #return mixed
*/
public function getAuteur()
{
return $this->auteur;
}
/**
* #param mixed $auteur
*/
public function setAuteur($auteur): void
{
$this->auteur = $auteur;
}
/**
* #return mixed
*/
public function getAutorises()
{
return $this->autorises;
}
/**
* #param mixed $autorises
*/
public function setAutorises($autorises): void
{
$this->autorises = $autorises;
}
/**
* #return int
*/
public function getAnnee(): int
{
return $this->annee;
}
/**
* #param int $annee
*/
public function setAnnee(int $annee): void
{
$this->annee = $annee;
}
/**
* #return mixed
*/
public function getModule()
{
return $this->module;
}
/**
* #param mixed $module
*/
public function setModule($module): void
{
$this->module = $module;
}
/**
* #return bool
*/
public function isVisible(): bool
{
return $this->visible;
}
/**
* #param bool $visible
*/
public function setVisible(bool $visible): void
{
$this->visible = $visible;
}
/**
* #return bool
*/
public function isModifiable(): bool
{
return $this->modifiable;
}
/**
* #param bool $modifiable
*/
public function setModifiable(bool $modifiable): void
{
$this->modifiable = $modifiable;
}
/**
* #ORM\PreUpdate
*/
public function updateDate(): void
{
$this->setUpdated(new \Datetime());
}
public function __construct()
{
$this->setCreated(new \Datetime());
$this->setUpdated(new \Datetime());
}
}
I don't understand why "time" is missing. Maybe it is for created or updated fields ? Anyway, created and updated fields return with ApiPlatform an object with timezone ...
created:
{timezone: {name: "Europe/Paris",…}, offset: 561, timestamp: -62169984561}
offset:561
timestamp:-62169984561
timezone:{name: "Europe/Paris",…}
Thanks for your help.
David
I've found a way to manage this error that works for me. I declare the DateTimeNormalizer in my config.yml like that :
datetime_normalizer:
class: Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
public: false
tags: [serializer.normalizer]
I hope that will help you !
In my case, I was using Symfony's Serializer Component without Symfony project and on the process of denormalization I had that issue so I had to add the DateTimeNormalizer before the ObjectNormalizer on the array of normalizers like this:
$serializer = new Serializer([new DateTimeNormalizer(), new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter())]);
Note that the order here is important.
In v1.1, using the class \DateTimeImmutable instead of \DateTime is what api-platform wait by default.
class Evaluation {
public function __construct()
{
$this->setCreated(new \DateTimeImmutable());
$this->setUpdated(new \DateTimeImmutable());
}
}
Change \DateTime in your entity to \DateTimeInterface. It should work.

How to retrieve associated ManyToOne entity?

In controller I try to retrieve all order products:
$products = $this->getDoctrine()->getRepository('AppBundle:Ordr')->find(1)->getOrdrProducts();
var_dump($products);
... but $products contain no products.
I try to imitate this.
Entity\Ordr.php :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="ordr")
* #ORM\Entity
*/
class Ordr
{
public function __construct()
{
$this->ordr_products = new ArrayCollection();
}
/**
* #ORM\Column(name="idOrdr", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idordr;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="OrdrProduct", mappedBy="ordr")
*/
protected $ordr_products;
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getOrdrProducts()
{
return $this->ordr_products;
}
public function getIdordr()
{
return $this->idordr;
}
public function addOrdrProducts(\AppBundle\Entity\OrdrProduct $ordrProducts)
{
$this->ordr_products[] = $ordrProducts;
return $this;
}
public function removeOrdrProducts(\AppBundle\Entity\OrdrProduct $ordrProducts)
{
$this->ordr_products->removeElement($ordrProducts);
}
}
Entity\OrdrProduct.php :
/**
* #ORM\Table(name="ordr_products", indexes={#ORM\Index(name="idOrdr_idx", columns={"idOrdr"})})
* #ORM\Entity
*/
class OrdrProduct
{
/**
* #ORM\Column(name="idOrdrProduct", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idordrproduct;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Ordr", inversedBy="ordr_products")
* #ORM\JoinColumn(name="idOrdr", referencedColumnName="idOrdr")
*/
private $ordr;
public function getIdordrproduct()
{
return $this->idordrproduct;
}
public function setOrdr(\AppBundle\Entity\Ordr $ordr = null)
{
$this->ordr = $ordr;
return $this;
}
public function getOrdr()
{
return $this->ordr;
}
}
My post is mostly code, I apologize for that. I dont know what to add more about the issue.
I can add something more about something else.
Hope this will help you:
Try this to get one order by id (with all order products related to it)
#AppBundle\Repository\OrderRepository.php
public function findOrderById($id)
{
$qb = $this->createQueryBuilder('o')
->join('o.ordr_products', 'r')
->addSelect('r')
->where('o.id = :id')
->setParameter(':id', $id)
;
return $qb->getQuery()
->getOneOrNullResult();
;
}

Symfony and Doctrine databases

I am working on some new project and the project is nearly done using Symfony framework, but the problem that i am used to CodeIgnitor Framework and basically as a Java developer/Android a lot of stuff i got confused with when working on Web development so here is the situation:
The website have a user end and an admin end (i am working on the Admin end), so there are these tables in the database which i really don't understand why they are built like this but this is not the problem
what i would like to know is how to add a service_category field with the corresponding translations in the service_category_translation using forms or any other way
this is the ServiceCategory Entity
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use JMS\Serializer\Annotation as Serializer;
/**
* class ServiceCategory
*
* #ORM\Table(name="service_category")
* #ORM\Entity
*
* #Serializer\ExclusionPolicy("all")
*/
class ServiceCategory
{
use ORMBehaviors\Timestampable\Timestampable;
use ORMBehaviors\SoftDeletable\SoftDeletable;
use ORMBehaviors\Translatable\Translatable;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
* #Serializer\Expose
* #Serializer\Groups({"general-information", "service-offer"})
*/
private $id;
/**
* #var ServiceGroup
*
* #ORM\OneToMany(targetEntity="ServiceGroup", mappedBy="serviceCategory")
*
* #Serializer\Expose
* #Serializer\Groups({"service-offer"})
*/
private $serviceGroup;
/**
* Constructor
*/
public function __construct()
{
$this->serviceGroup = new ArrayCollection();
}
/**
* {#inheritdoc}
*/
public function __toString()
{
return $this->getName() ? $this->getName() : '';
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Get translated name
*
* #return string
*
* #Serializer\VirtualProperty
* #Serializer\SerializedName("name")
* #Serializer\Groups({"invoice-list", "service-offer"})
*/
public function getName()
{
if($this->getTranslations()->get($this->getCurrentLocale()) == null){
return 'sorry';
}
return $this->getTranslations()->get($this->getCurrentLocale())->getName();
}
/**
* Add serviceGroup
*
* #param ServiceGroup $serviceGroup
*
* #return ServiceCategory
*/
public function addServiceGroup(ServiceGroup $serviceGroup)
{
$this->serviceGroup[] = $serviceGroup;
return $this;
}
/**
* Remove serviceGroup
*
* #param ServiceGroup $serviceGroup
*/
public function removeServiceGroup(ServiceGroup $serviceGroup)
{
$this->serviceGroup->removeElement($serviceGroup);
}
/**
* Get serviceGroup
*
* #return Collection
*/
public function getServiceGroup()
{
return $this->serviceGroup;
}
}
and this is the ServiceCategoryTranslation Entity
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* Class ServiceCategoryTranslation
*
* #package CoreBundle\Entity
*
* #ORM\Entity
* #ORM\Table(name="service_category_translation")
*/
class ServiceCategoryTranslation
{
use ORMBehaviors\Translatable\Translation;
use ORMBehaviors\Timestampable\Timestampable;
use ORMBehaviors\SoftDeletable\SoftDeletable;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/**
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #param string
* #return null
*/
public function setName($name)
{
$this->name = $name;
}
public function __toString() {
return $this->name;
}
}
how can i achieve this ?
please don't guide me to symfony or doctrine documentation i have been lost there for two days now and i am running late on the schedule
Thanks in advance
You have a one-to-many-association from ServiceCategory (1) to ServiceCategoryTranslations (many) since I assume you
will manage the transaltions from the category. This have to be a bidirectional association, have a look
here
You have to add a property to manage the entities and describe the association. I will do it with annotations.
use Doctrine\Common\Collections\ArrayCollection;
class ServiceCategory
{
/**
* #OneToMany(targetEntity="ServiceCategoryTranslation", mappedBy="serviceCategory")
**/
private $translations;
public function __construct()
{
$this->translations = new ArrayCollection();
}
/**
* #return ServiceCategoryTranslation[]
*/
public function getStandort(){
return $this->translations;
}
/**
* #param ArrayCollection $translations
* #return ServiceCategory
*/
public function setTranslations(ArrayCollection $translations)
{
$this->translations->clear();
foreach ($translations as $translation){
$this->addTranslation($translation);
}
return $this;
}
/**
* #param ServiceCategoryTranslation $translation
* #return ServiceCategory
*/
public function addTranslation(ServiceCategoryTranslation $translation){
/* this is a way to keep the integerity */
$translation->setServiceCategory($this);
if(!$this->translation){
$this->translations = new ArrayCollection();
}
$this->translations->add($translation);
return $this;
}
/**
* #param ServiceCategoryTranslation $translation
* #return ServiceCategory
*/
public function removeStandort(ServiceCategoryTranslation $translation){
$this->translations->removeElement($translation);
return $this;
}
}
class ServiceCategoryTranslation
{
/**
* #ManyToOne(targetEntity="ServiceCategory", inversedBy="translations")
* #JoinColumn(name="translatable_id", referencedColumnName="id")
**/
private $serviceCategory;
/**
* #param ServiceCategoryTranslation $translation
* #return ServiceCategoryTranslation
*/
public function setServiceCategory(ServiceCategory $serviceCategory){
$this->serviceCategory = $serviceCategory;
return $this;
}
/* getter analog */
}

Objects return null with DotrineFixturesBundle

I'm working with Symfony2 2.3 and I need sharing data between two entities trough the DotrineFixturesBundle
But the Sharing Objects between Fixtures dont work.
When the command is executed
php app/console doctrine:fixtures:load --purge-with-truncate
the data is load, But the fields with relations are NULL
Table Divterrigral
ID DESCRIPTION
1 description
Table with FK Divterribase
ID DIVTERRIGRAL_ID DESCRIPTION
1 Null descriptionInfo
if I do mysql through I can map the relationship works.
the class LoadDivterrigral.
<?php
namespace Soint\InventarioBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Soint\InventarioBundle\Entity\Divterrigral;
class LoadDivterrigral extends AbstractFixture implements OrderedFixtureInterface{
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager){
$ahuachapan = new Divterrigral();
$ahuachapan->setNombre('Ahuachapan');
$manager->persist($ahuachapan);
$manager->flush();
$this->addReference('dep-ahuachapan', $ahuachapan);
}
/**
* {#inheritDoc}
*/
public function getOrder(){
return 1; // el orden en el cual serán cargados los accesorios
}
}
The class LoadDivTerribase
<?php
namespace Soint\InventarioBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Soint\InventarioBundle\Entity\Divterribase;
class LoadDivterribase extends AbstractFixture implements OrderedFixtureInterface {
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager){
$ahuachapan = new Divterribase();
$ahuachapan->setNombre('Ahuachapan');
$ahuachapan->setDivterrigral($this->getReference('dep-ahuachapan'));
$manager->persist($ahuachapan);
$manager->flush();
}
/**
* {#inheritDoc}
*/
public function getOrder(){
return 2;
}
}
Entity Divterrigral
<?php
namespace Soint\InventarioBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Soint\InventarioBundle\Entity\Divterribase;
/**
* #ORM\Entity
*/
class Divterrigral {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue;
*/
protected $id;
/** #ORM\Column(type="string", length=100) */
protected $nombre;
/**
* #ORM\OneToMany(targetEntity="Divterribase", mappedBy="divterrigral")
*/
protected $divterribases;
public function __construct() {
$this->divterribases = new ArrayCollection();
}
public function addDivterribases(Articulo $articulos){
$this->divterribases[] = $articulos;
}
public function getDivterribases(){
return $this->divterribases;
}
/**
* Get id
* #return integer
*/
public function getId(){
return $this->id;
}
/**
* Set nombre
* #param string $nombre
* #return Divterrigral
*/
public function setNombre($nombre){
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
* #return string
*/
public function getNombre(){
return $this->nombre;
}
public function __toString(){
return $this->getNombre();
}
}
Entity Divterribase
<?php
namespace Soint\InventarioBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Soint\InventarioBundle\Entity\Divterrigral;
/**
* #ORM\Entity
*/
class Divterribase {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue;
*/
protected $id;
/** #ORM\Column(type="string", length=100) */
protected $nombre;
/**
* #ORM\ManyToOne(targetEntity="Divterrigral", inversedBy="divterribases")
* #ORM\JoinColumn(name="divterrigral_id", referencedColumnName="id")
* #return integer
*/
protected $divterrigral;
/**
* Get id
* #return integer
*/
public function getId(){
return $this->id;
}
/**
* Set nombre
* #param string $nombre
* #return Divterribase
*/
public function setNombre($nombre){
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
* #return string
*/
public function getNombre(){
return $this->nombre;
}
/**
* Set divTerriGral
* #param Soint\InventarioBundle\Entity\Divterrigral $divTerriGral
* #return Divterribase
*/
public function setDivterrigral(Divterrigral $divTerriGral = null){
$this->divTerriGral = $divTerriGral;
return $this;
}
/**
* Get divTerriGral
* #return Soint\InventarioBundle\Entity\Divterrigral
*/
public function getDivterrigral(){
return $this->divTerriGral;
}
public function __toString(){
return $this->getNombre();
}
}
Entity Divterrigral
/**
* #ORM\OneToMany(targetEntity="Divterribase", mappedBy="divterrigral",cascade={"persist", "remove"})
*/
protected $divterribases;
Further reading : http://doctrine-orm.readthedocs.org/en/2.0.x/reference/working-with-associations.html#transitive-persistence-cascade-operations

How to use group

I use FOSUserBundle and 'group' function
At first in my User.php
There were such getter and setter
/**
* Add groups
*
* #param \Acme\UserBundle\Entity\Group $groups
* #return User
*/
public function addGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups[] = $groups;
return $this;
}
/**
* Remove groups
*
* #param \Acme\UserBundle\Entity\Group $groups
*/
public function removeGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups->removeElement($groups);
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
but,this error happens
FatalErrorException: Compile Error: Declaration of Acme\UserBundle\Entity\User::addGroup() must be compatible with that of FOS\UserBundle\Model\GroupableInterface::addGroup()
in FOS\UserBundle\Model\GroupableInterface
public function addGroup(GroupInterface $group);
in my Acme\UserBundle\Entity\User
public function addGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups[] = $groups;
return $this;
}
How can I adjust the argument type or correct this error?
For now,I have commented out these three function.
at that time it looked works well.
But now ,I use Sonataadmin bundle and in
#SonataAdminBundle/Admin/UserAdmin.php
protected function configureFormFields(FormMapper $formMapper){
$formMapper
->with('General')
->add('groups','entity',array('property' => 'name',
'multiple' => true,
'class' => 'UserBundle:Group',
))
}
it shows this form correctly but when I push submit button to regist,
it shows
Error: Call to a member function contains() on a non-object in ~~~/FOS/UserBundle/Model/User.php line 572
in /FOS/UserBundle/Model/user.php
there is function likt this
public function addGroup(GroupInterface $group)
{
var_dump($group);# I added to check
if (!$this->getGroups()->contains($group)) {
$this->getGroups()->add($group);
}
return $this;
}
var_dump($group) shows
object(Acme\UserBundle\Entity\Group)#923 (3) { ["id":protected]=> int(2) ["name":protected]=> string(12) "TeacherGroup" ["roles":protected]=> array(0) { } }
I guess it has group information correctly..
How can I fix this problem?
my whole user.php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use FOS\UserBundle\Model\GroupableInterface;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #ORM\HasLifecycleCallbacks
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
protected $id;
/**
*
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\Lesson", mappedBy="teacher")
*/
private $LessonAsTeacher;
/**
*
* #ORM\OneToMany(targetEntity="Acme\UserBundle\Entity\Lesson", mappedBy="student*removethis : name of the variable in Lesson.php*")
*/
private $LessonAsStudent;
/**
*
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\Sex", inversedBy="sex*removethis : name of the variable in user.php*")
* #ORM\JoinColumn(name="sex", referencedColumnName="id",nullable=false)
*/
private $sex;
/**
* #ORM\ManyToMany(targetEntity="Acme\UserBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your first name.", groups={"Registration", "Profile"})
* #Assert\MinLength(limit="0", message="The name is too short.", groups={"Registration", "Profile"})
* #Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"})
*/
protected $firstname;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your last name.", groups={"Registration", "Profile"})
* #Assert\MinLength(limit="0", message="The name is too short.", groups={"Registration", "Profile"})
* #Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"})
*/
protected $lastname;
/**
* #ORM\Column(type="date")
*/
protected $birthday;
/**
* #var \DateTime
*
* #ORM\Column(name="createdAt", type="datetime")
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updatedAt", type="datetime")
*/
private $updatedAt;
public function __construct()
{
parent::__construct();
// your own logic
}
public function getFirstname()
{
return $this->firstname;
}
public function setFirstname($name)
{
$this->firstname = $name;
return $this;
}
public function getLastname()
{
return $this->lastname;
}
public function setLastname($name)
{
$this->lastname = $name;
return $this;
}
public function getSex()
{
return $this->sex;
}
public function setSex($sex)
{
$this->sex = $sex;
return $this;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set age
*
* #param integer $age
* #return User
*/
public function setAge($age)
{
$this->age = $age;
return $this;
}
/**
* Get age
*
* #return integer
*/
public function getAge()
{
return $this->age;
}
/**
* Set birthday
*
* #param \DateTime $birthday
* #return User
*/
public function setBirthday($birthday)
{
$this->birthday = $birthday;
return $this;
}
/**
* Get birthday
*
* #return \DateTime
*/
public function getBirthday()
{
return $this->birthday;
}
/**
* #ORM\PrePersist
*/
public function prePersist()
{
$this->createdAt = new \DateTime;
$this->updatedAt = new \DateTime;
}
/**
* #ORM\PreUpdate
*/
public function preUpdate()
{
$this->updatedAt = new \DateTime;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
* #return User
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
* #return User
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
/**
* Add groups
*
* #param \Acme\UserBundle\Entity\Group $groups
* #return User
*/
// public function addGroup(\Acme\UserBundle\Entity\Group $groups)
// {
// $this->groups[] = $groups;
// return $this;
// }
/**
* Remove groups
*
* #param \Acme\UserBundle\Entity\Group $groups
*/
// public function removeGroup(\Acme\UserBundle\Entity\Group $groups)
// {
// $this->groups->removeElement($groups);
// }
}
my whole Group.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\Group as BaseGroup;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_group")
*/
class Group extends BaseGroup
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
The problem is that you override getGroups() like this:
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
But you never initialized $this->groups, so when you call $this->getGroups()->contains(), it says that $this->getGroups() is a non-object, which is true!
To solve this you have 2 solutions.
You can initialize groups in the constructor of User:
public function __construct()
{
parent::__construct();
&this->groups = new ArrayCollection();
}
Or you can change the getGroups() function to return a new object if groups hasn't been initialized:
public function getGroups()
{
return $this->groups ?: $this->groups = new ArrayCollection();
}
In both cases, don't forget to add use Doctrine\Common\Collections\ArrayCollection; at the beginning of User.php.
I got the same error:
FatalErrorException: Compile Error: Declaration of Acme\UserBundle\Entity\User::addGroup() must be compatible with that of FOS\UserBundle\Model\GroupableInterface::addGroup()
After searching I found out (FOS Git Issue 988) that this special error is a Doctrine 'Bug' or sth.
Doctrine should not generate the method at all because there is an implementation of addGroup() in the base class.
I worked around it by modifying the signature from
public function addGroup(\MyBundleNamespace\Entity\Group $groups)
public function removeGroup(\MyBundleNamespace\Entity\Group $groups)
to
public function addGroup(\FOS\UserBundle\Model\GroupInterface $groups)
public function removeGroup(\FOS\UserBundle\Model\GroupInterface $groups)
This way you prevent Doctrine from generating these two functions with the wrong signature.
Version Infos:
Symfony 2.2.1
DoctrineORM 2.2.3
FOSUserBundle 1.3.1
PHP 5.4.4-14
Maybe this can help someone else!
I came across this problem and the simple solution was to change the declaration of the groups variable from public to protected:
/**
* #var \Doctrine\Common\Collections\Collection
*/
protected $groups;
solution is simply: remove all setters and getters from your own entity in your own userBundle and always run doctrine:generate:entities for specyfic bundle, not for all.

Resources