Im tying to add communication parts to a rootCommunication in my data-fixture, there is no error, but only just NULL in the database field 'root_communication_id'. Why?
Parts of my Model 'Communication'
/**
* Communication
*
* #ORM\Table(name="communication")
* #ORM\Entity(repositoryClass="Mother\BaseBundle\Entity\Repository\CommunicationRepository")
*/
class Communication
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="message", type="text", nullable=true)
*/
private $message;
/**
* #ORM\ManyToOne(targetEntity="Communication", inversedBy="childrenCommunication", cascade={"persist"})
* #ORM\JoinColumn(name="root_communication_id", referencedColumnName="id", nullable=true)
*
*/
private $rootCommunication;
/**
* #ORM\OneToMany(targetEntity="Communication", mappedBy="rootCommunication")
*
*/
private $childrenCommunication;
}
In a first data-fixture i added three communications to the database, in this secound fixture i add the childrenCommunication to the rootCommunication.
/**
* {#inheritDoc}
*/
public function load( ObjectManager $manager ){
$contentRepo = $this->container->get('doctrine')->getManager()->getRepository('MotherBaseBundle:Communication');
$communication1 = $contentRepo->find( $this->getReference('communication1')->getId() );
$communication1->addChildrenCommunication( $this->getReference('communication2') );
$communication1->addChildrenCommunication( $this->getReference('communication3') );
$manager->persist( $communication1 );
$manager->flush();
}
I assume you are not setting the rootCommunication when you are adding the child.
You should add an auto setter to the add method, like..
public function addChildrenCommunication(CommunicationInterface $communication)
{
if (!$this->childrenCommunication->contains($communication)) {
$this->childrenCommunication->add($communication);
$communication->setRootCommunication($this);
}
return $this;
}
.. and the same for the remove..
Related
I'm trying to upload a file via vichuploader bundle on my Users entity.
Using hwioauthbundle that implements UserInterface, and i think the errors comes from that bundle...
So every time i try to uplod a file i got this exception :
Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile'
is not allowed
I already tried this solution but also same exception.
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use Symfony\Component\Security\Core\User\UserInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUser;
/**
* Users
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UsersRepository")
*
*/
class Users extends OAuthUser
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="first_name", type="string", length=255)
*/
private $firstName;
/**
* #var string
*
* #ORM\Column(name="last_name", type="string", length=255)
*/
private $lastName;
/**
* #var string
*
* #ORM\Column(name="civility", type="string", length=255, nullable=true)
*/
private $civility;
/**
* #var string
*
* #ORM\Column(name="avatar", type="string", length=255, nullable=true)
*/
private $avatar;
/**
* #var string
*
* #ORM\Column(name="qualification", type="string", length=255, nullable=true)
*/
private $qualification;
/**
* #var string
*
* #ORM\Column(name="level", type="string", length=255, nullable=true)
*/
private $level;
/**
* #var \DateTime
*
* #ORM\Column(name="birth_date", type="date", nullable=true)
*/
private $birthDate;
/**
* #var \DateTime
*
* #ORM\Column(name="hiring_date", type="date", nullable=true)
*/
private $hiringDate;
/**
* #var string
*
* #ORM\Column(name="country", type="string", length=255, nullable=true)
*/
private $country;
/**
* #var string
*
* #ORM\Column(name="city", type="string", length=255, nullable=true)
*/
private $city;
/**
* #var string
*
* #ORM\Column(name="linkedin_profil", type="string", length=255, nullable=true)
*/
private $linkedinProfil;
/**
* #var string
*
* #ORM\Column(name="web_site", type="string", length=255, nullable=true)
*/
private $webSite;
/**
* #var \DateTime
*
* #ORM\Column(name="date_last_cnx", type="datetimetz", nullable=true)
*/
private $dateLastCnx;
/**
*
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Files",cascade={"persist"})
* #ORM\JoinColumn(name="file_id", referencedColumnName="id")
*/
public $cv;
/** #ORM\Column(name="google_id", type="string", length=255, nullable=true) */
private $google_id;
Files.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* Files
* #Vich\Uploadable
* #ORM\Table(name="files")
* #ORM\Entity(repositoryClass="AppBundle\Repository\FilesRepository")
*/
class Files
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="product_image", fileNameProperty="imageName", size="imageSize")
*
* #var File
*/
protected $imageFile;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
protected $imageName;
public function getId()
{
return $this->id;
}
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*
* #return Product
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
/**
* #return File|null
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*
* #return Product
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* #return string|null
*/
public function getImageName()
{
return $this->imageName;
}
}
My form Userstype:
use AppBundle\Form\FilesType;
->add('cv',FilesType::class)
My form Filestype:
-> add('imageFile',
VichFileType::class, [
'required' => false,
'allow_delete' => true,
'download_link' => true,
'label' => false,
]);
You are serializing ImageFile entity within this code that's why you are getting the error , try removing that and add updatedAt field so that doctrine can track changes on the entity:
/**
* Files
* #ORM\Table(name="files")
* #ORM\Entity(repositoryClass="AppBundle\Repository\FilesRepository")
* #Vich\Uploadable
*/
class Files implements \Serializable
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="product_image", fileNameProperty="imageName", size="imageSize")
*
* #var File
*/
protected $imageFile;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
protected $imageName;
/**
* #ORM\Column(type="datetime")
*
* #var string
*/
protected $updatedAt;
public function getId()
{
return $this->id;
}
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*
* #return Product
*/
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
if ($image) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
return $this;
}
/**
* #return File|null
*/
public function getImageFile()
{
return $this->imageFile;
}
/**
* #param string $imageName
*
* #return Product
*/
public function setImageName($imageName)
{
$this->imageName = $imageName;
return $this;
}
/**
* #return string|null
*/
public function getImageName()
{
return $this->imageName;
}
/** #see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->id,
$this->imageName,
));
}
/** #see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
) = unserialize($serialized);
}
/**
* #return string
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* #param string $updatedAt
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
}
}
for Symfony5
Class User implement UserInterface
public function __serialize(): array
{
return [
'id' => $this->id,
'email' => $this->email,
//......
];
}
public function __unserialize(array $serialized): User
{
$this->id = $serialized['id'];
$this->email = $serialized['email'];
// .....
return $this;
}
Check this out, one of your Users's relation has an UploadedFile property, which is essentially a File aka a filestream which aren't allowed to be serialized. Therefore you need to specify what you want to serialized:
https://symfony.com/doc/3.3/security/entity_provider.html
Basically you only neeed to serialized id, username and password (three is an example code on the above page)
I have two entities:
1)
/**
* Post
*
* #ORM\Table(name="article")
* #ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
*/
class Post
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
/**
* #var string
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Image", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinColumn(name="image", referencedColumnName="id", nullable=true)
*/
private $image;
}
and 2)
/**
* Image
*
* #ORM\Table(name="image")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ImageRepository")
*/
class Image
{
/**
* #var int
*
* #ORM\Column(name="id", type="string", length=40)
* #ORM\Id
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="small", type="blob", nullable=true)
*/
private $small;
/**
* #var string
*
* #ORM\Column(name="medium", type="blob", nullable=true)
*/
private $medium;
/**
* #var string
*
* #ORM\Column(name="large", type="blob", nullable=true)
*/
private $large;
...
}
Both entities have getters and setters.
The controller sets the post to update
$requestFile = $request->files->get('image');
$em = $this->getDoctrine()->getManager();
$record = $em->getRepository('AppBundle:Post')->find($id);
if (!$record) {
throw $this->createNotFoundException(
'No product found for id '.$record
);
}
$record->setTitle($request->request->get('title'));
$record->constructAlias($request->request->get('title'));
...
if ($request->files->get('image')) {
// check if image already exists
$imgGeneratedId = sha1_file($request->files->get('image')->getPathName());
$imageRepo = $this->getDoctrine()->getRepository('AppBundle:Image');
$isPresent = $imageRepo->find($imgGeneratedId);
$image = $isPresent;
if (!$isPresent) {
$image = new Image();
$image->setId($imgGeneratedId);
$image->setLarge(file_get_contents($request->files->get('image')->getPathName()));
$mediumImage =
...
$em->persist($image);
}
$record->setImage($em->getReference('AppBundle:Image', $image->getId()));
}
$em->persist($record);
$em->flush();
Please ignore any syntax errors or other kinds; there are none.
The problem is that even if image already exists it is trying to create one which causes error in database. So, in order to avoid this I used getReference, but this causes other issues.
So, how can I force doctrine, not to insert an image if already exists and just set the article image with the image id?
Thanks.
Here some context information: I'm building a Symfony2 application with Doctrine2 and FOSRestBundle.
My problem: I want to be able to create a parent with his children with just one JSON and one database access.
My JSON looks like this:
{
"name": "TEST_NAME",
"info": "TEST_INFO",
"cmts": [
{
"cmt": "CMT1",
"info": "INFO1"
},
{
"cmt": "CMT2",
"info": "INFO2"
},
{
"cmt": "CMT3",
"info": "INFO3"
}
]
}
Here is my TEST entity:
<?php
namespace App\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Test
*
* #ORM\Table(name="Test")
* #ORM\Entity(repositoryClass="App\Bundle\DemoBundle\Entity\TestRepository")
*/
class Test
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="info", type="string", length=255, nullable=true)
*/
private $info;
/**
* #ORM\OneToMany(targetEntity="TestCmt", mappedBy="test", fetch="EAGER", orphanRemoval=true, cascade={"merge", "remove", "persist"})
*/
protected $cmts;
/**
* Constructor
*/
public function __construct()
{
$this->cmts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add cmts
*
* #param \App\Bundle\DemoBundle\Entity\TestCmt $cmts
* #return Test
*/
public function addCmt(\App\Bundle\DemoBundle\Entity\TestCmt $cmts)
{
$this->cmts[] = $cmts;
return $this;
}
/**
* Remove cmts
*
* #param \App\Bundle\DemoBundle\Entity\TestCmt $cmts
*/
public function removeCmt(\App\Bundle\DemoBundle\Entity\TestCmt $cmts)
{
$this->cmts->removeElement($cmts);
}
/**
* Get cmts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCmts()
{
return $this->cmts;
}
// other getters/setters...
}
And my TESTCMT entity:
<?php
namespace App\Bundle\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TestCmt
*
* #ORM\Table(name="TestCmt")
* #ORM\Entity(repositoryClass="App\Bundle\DemoBundle\Entity\TestCmtRepository")
*/
class TestCmt
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="cmt", type="string", length=255)
*/
private $cmt;
/**
* #var string
*
* #ORM\Column(name="info", type="string", length=255, nullable=true)
*/
private $info;
/**
* #var Test
*
* #ORM\ManyToOne(targetEntity="Test", inversedBy="cmts")
* #ORM\JoinColumn(name="test_id", referencedColumnName="id")
**/
private $test;
/**
* Set test
*
* #param \App\Bundle\DemoBundle\Entity\Test $test
* #return TestCmt
*/
public function setTest(\App\Bundle\DemoBundle\Entity\Test $test = null)
{
$this->test = $test;
return $this;
}
/**
* Get test
*
* #return \App\Bundle\DemoBundle\Entity\Test
*/
public function getTest()
{
return $this->test;
}
}
And finaly my postTestAction():
public function postTestAction(Request $request)
{
$entity = $this->deserialize($request, 'App\DemoBundle\Entity\Test');
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $entity;
}
When I send the JSON, TEST and TESTCMTs are created. Nevertheless, all "test_id" from the created TESTCMTs are "null"... And that's my problem!
EDIT: with SQL Server Profiler, I can see that Doctrine make that Transact SQL request:
INSERT INTO TESTCMT (test_id, cmt, info) VALUES (null, 'CMT', 'INFO')
I don't know why Doctrine can't send the test_id... TEST is created before TESTCMT, so "test_id" should be reachable for Doctrine to create the associate TESTCMTs.
Can someone helped me to fix it? :)
Remove #ORM\GeneratedValue(strategy="AUTO") and it won't let the DB generate a new id for the Entity
this is my entity:
/**
* #ORM\Table(name="Animal")
* #ORM\HasLifecycleCallbacks
*/
class Animal {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
private $lctitle;
/**
* #var localizedcontent $lcdescription
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcDescription", referencedColumnName="pkId", nullable=false)
*/
private $lcdescription;
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->lctitle;
$lcd = $this->lcdescription;
}
This is my dql:
SELECT a,lct FROM Animal JOIN e.lctitle lct WHERE a.id=:id
When i'm starting xdebug, it tells me that lcdescription is a proxy object and lctitle doesn't exists. I don't know why.
I think the postLoad event is too early because the localizedcontent isn't loaded at this moment, right? Is there an other listener for reading the value of lctitle in relation to the Animal Object?
Thanks
Doctrine always returns proxies. These classes inherit from the entity-classes. It might help if you declare your relations protected instead of private.
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
protected $lctitle;
or you could write a getter and call this one in your post-load function
public function getLctitle() {
return $this->lctitle;
}
public function getLcdescription() {
return $this->lcdescription;
}
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->getLctitle();
$lcd = $this->getLcdescription();
}
I have this class:
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
class Parameter{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Project\Bundle\Entity\Anthropometry", inversedBy="parameter")
* #ORM\JoinColumn(name="anthropometry_id", referencedColumnName="id")
*
*/
protected $anthropometry;
/**
* #ORM\Column(name="data", type="string", length=255, nullable=true)
*/
protected $data;
...
}
and this:
/**
* #ORM\Table(name="anthropometry")
* #ORM\Entity
*/
class Anthropometry {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\OneToMany(targetEntity="Project\Bundle\Entity\Parameter", mappedBy="anthropometry", cascade={"persist"})
*
*/
protected $parameter;
...
}
In my Controller I am creating a form and validating in the same Action.
To create the form I need instance one Parameter. But not need persist him.
So.. when I call $em->flush I got the error:
A new entity was found through the relationship ...
To solve this I put cascade={"persist"} in annotation:
//Class Anthropometry
...
/**
*
* #ORM\OneToMany(targetEntity="Project\Bundle\Entity\Parameter", mappedBy="anthropometry", cascade={"persist"})
*
*/
protected $parameter;
But now, in my Database, the parameters are being persisted with field 'Data' = NULL
Can I check with prePersist if the field is NULL before persist?
something like this?
//class Parameter
/**
*
* #ORM\prePersist
*/
public function prePersist(){
if($this->getData() == NULL){
return false;
}
}
Thx!
I didn't verify if it works but you could try unsetting the parameter before persisting the Anthropometry (since you don't need to persist parameters):
//class Anthropometry
/**
* #ORM\prePersist
*/
public function prePersist()
{
if(!is_null($this->parameter) && $this->parameter->getData() == null){
$this->parameter = null;
}
}