PersistentCollection not initialized but data in database with Symfony and Doctrine - php

I have a problem with a PersistentCollection.
I have an Object User (herited of FOSUserbundle user class) who have an EmdebedDocument Seance. The Seance have an Array of Event.
My Seance Class:
/**
* #MongoDB\EmbeddedDocument
*/
class Seance
{
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\EmbedMany(targetDocument="Event")
*/
protected $dispos ;
/**
* #MongoDB\Field(type="string")
*/
protected $rayonDeplacement;
/**
* #MongoDB\Field(type="string")
*/
protected $lieu;
/**
* #MongoDB\Field(type="string")
*/
protected $prix;
/**
* #MongoDB\Field(type="string")
*/
protected $nbPersonne;
And my class Event
/**
* #MongoDB\EmbeddedDocument
*/
class Event extends BaseEvent
{
/**
* #var integer
* #MongoDB\Id
*/
protected $id;
/**
* #var \DateTime
* #MongoDB\Field(type="date")
* #Assert\NotNull()
*/
protected $startDate;
/**
* #var \DateTime
* #MongoDB\Field(type="date")
* #Assert\NotNull()
*/
protected $endDate;
I give the event from user with:
$user->getSeance()->getDispos()
This function returns a empty PersistentCollection while they are events in database.
When dump the return of getDispos() method I have:
I dont't understant why I have mongoData field with my data but arrayCollection empty.
Thank you for yout help.

PersistentCollection is initialized lazily - for performance reasons, the data from database is held in mongoData. The collection is initialized during the first time you need some data from it (or try to modify it) - then the data held in mongoData is hydrated into your embedded documents and that is added to decorated coll. All this is happening transparently to you, just try using your collection instead of dumping it.

Related

Symfony $this->getUser() without doctrine associations (OneToMany)

In Symfony, we can get current logged-in user data using $this->getUser(), but my problem is when I access this statement, I am getting all the user-associated data set. which has OneToMany relationships with another entity, and it has a lot of data.
Example:
User Entity
`
class User implements UserInterface
{
/**
* #var string
* #ORM\Id
* #ORM\Column(type="string", length=10)
*
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string")
*/
protected $email;
/**
* #var array
* #ORM\Column(type="json")
*/
protected $roles;
/**
* One User has Many Posts.
* #ORM\OneToMany(targetEntity="App\Entity\Post", mappedBy="user", fetch="LAZY")
*
*
*/
private Collection $posts;
`
Post Entity
`
class Post
{
/**
* #var string
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", length=11)
*/
private $id;
/**
* Many posts have one user.
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="post", fetch="EXTRA_LAZY")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
`
I am looking to get rid of the user-associated data set or limit the associated data set to limit 1.
Thank you for the help in advance. :)
found solution after hours of search.
You will be required to add Symfony Serializer #Ignore attribute on the Entity class.
Example
use Symfony\Component\Serializer\Annotation\Ignore;
class User implements UserInterface
{
/**
* #var string
*
*/
#[ORM\Id]
#[ORM\Column(type: 'string', length: 10)]
protected $id;
/**
* #var string
*/
#[ORM\Column(type: 'string')]
protected $email;
/**
* #var array
*/
#[ORM\Column(type: 'json')]
protected $roles;
/**
* #var Post
*/
#[ORM\OneToMany(targetEntity: 'App\Entity\Post', mappedBy: 'user', fetch: 'LAZY')]
#[Ignore]
private Collection $posts;
I hope this help someone. Cheers!

Symfony 4 entity getters return types

I'm currently using Symfony 4.1 on PHP 7.1 with Sonata Admin and there is a little problem with entity getters return types... Since I know which fields are nullable, I can set mandatory or optional return type. But this aproach doesn't work when I'm binding entity on the create form of sonata admin, because entity is not initialized and all fields are set to null. Solution is obvious, but which is more correct?
Solution 1:
Make return type optional (nullable)
/**
* #ORM\Table(name="banner__banner_zone_relation")
* #ORM\Entity()
*/
class BannerZoneRelation implements TimestampableInterface
{
/**
* #var Banner
* #ORM\ManyToOne(targetEntity="App\Entity\Banner\Banner", inversedBy="bannerZoneRelations", cascade={"persist"})
* #ORM\JoinColumn(name="banner_id", referencedColumnName="id")
*/
protected $banner;
/**
* #var Zone
* #ORM\ManyToOne(targetEntity="App\Entity\Banner\Banner",inversedBy="bannerZoneRelations", cascade={"persist"})
* #ORM\JoinColumn(name="zone_id", referencedColumnName="id")
*/
protected $zone;
/
/**
* #return Banner|null
*/
public function getBanner(): ?Banner
{
return $this->banner;
}
/**
* #return Zone|null
*/
public function getZone(): ?Zone
{
return $this->zone;
}
}
Solution 2:
Creating instance of Banner and Zone in constructor
/**
* #ORM\Table(name="banner__banner_zone_relation")
* #ORM\Entity()
*/
class BannerZoneRelation implements TimestampableInterface
{
/**
* #var Banner
* #ORM\ManyToOne(targetEntity="App\Entity\Banner\Banner", inversedBy="bannerZoneRelations", cascade={"persist"})
* #ORM\JoinColumn(name="banner_id", referencedColumnName="id")
*/
protected $banner;
/**
* #var Zone
* #ORM\ManyToOne(targetEntity="App\Entity\Banner\Banner",inversedBy="bannerZoneRelations", cascade={"persist"})
* #ORM\JoinColumn(name="zone_id", referencedColumnName="id")
*/
protected $zone;
public function __construct()
{
$this->banner = new Banner();
$this->zone = new Zone();
}
/
/**
* #return Banner
*/
public function getBanner(): Banner
{
return $this->banner;
}
/**
* #return Zone
*/
public function getZone(): Zone
{
return $this->zone;
}
}
Which solution is better? Thanks for any answer!
I would think option 1 (return null) so that zone and banner records aren't created in the database if they're not necessary.

Doctrine ODM association not loaded

I've started working with Doctrine MongoDB ODM. I have a Document called Document which has an association originalFile to another document called File.
class Document extends AbstractDocument
{
/**
* #var integer $id
*
* #MongoDB\Id
*/
protected $id;
/**
* #var ImportSource
*
* #MongoDB\ReferenceOne(targetDocument="ImportSource", cascade="all", simple=true)
*/
protected $importSource;
/**
* #var DocumentState
*
* #MongoDB\ReferenceOne(targetDocument="DocumentState", cascade="all", simple=true)
*/
protected $state;
/**
* #var \DateTime $created
*
* #MongoDB\Date
*/
protected $created;
/**
* #var \DateTime $modified
*
* #MongoDB\Date
*/
protected $modified;
/**
* #var File $formattedFile
*
* #MongoDB\ReferenceOne(targetDocument="File", cascade="all")
*/
protected $formattedFile;
/**
* #var File $originalFilename
*
* #MongoDB\ReferenceOne(targetDocument="File", cascade="all")
*/
protected $originalFile;
//getters, setters etc..
}
File:
class File
{
/**
* #var string
*
* #MongoDB\Id
*/
protected $id;
/**
* #var FileType
*
* #MongoDB\ReferenceOne(targetDocument="FileType", cascade="all", simple=true)
*/
protected $type;
/**
* #var string
*
* #MongoDB\String
*/
protected $basename;
/**
* #var \DateTime
*
* #MongoDB\Date
*/
protected $created;
/**
* #var \DateTime
*
* #MongoDB\Date
*/
protected $deleted;
/**
* #var \MongoGridFSFile
*
* #MongoDB\File
*/
protected $file;
Storing the Document works without any problems. The Document and the File-Document are stored in MongoDB. When I'm loading the Document the $originalFile property is null. I have no clue what's missing. Is the mapping wrong or is this simply a bug in Doctrine?
Edit:
This is how I'm storing the documents:
//create if not exists
if ($documentObj === null) {
$documentObj = new Document();
$documentObj->setCreated(new \DateTime());
//create file
$file = new File();
} else {
$documentObj->setModified(new \DateTime());
//get file
$file = $documentObj->getOriginalFile();
}
$file->setFile($pathToFile);
//set file
$documentObj->setOriginalFile($file);
//set import source
$documentObj->setImportSource($source);
//store document
$documents[] = $this->storeDocument($documentObj, $documentFields);
//... method storeDocument fills other properties of the document and finally persits the document:
$this->manager->persist($documentObj);
$this->manager->flush();
I have no clue why, but it's working now... I was occupied with other projects for a few days, returned to this projects, ran my unit tests again and everything worked. Only thing I've done was a composer update. Maybe a bug correlating with my setup.
I got such problem, it is related to metadata cache, just run
bin/console cache:clear
bin/console doctrine:cache:clear-metadata
Also good to know these commands, if you are using symfony built-in cache
bin/console doctrine:cache:clear-query
bin/console doctrine:cache:clear-result

Doctrine 2 - How to have an association class with a mapped superclass?

I'm having trouble with a Doctrine 2 mapped superclass, to define a ManyToMany Relation.
My code is :
use Doctrine\Common\Collections\ArrayCollection;
/** #MappedSuperclass */
abstract class MyAbstractClassA
{
/**
* #Id
* #GeneratedValue
* #Column(type="integer")
* #var int
*/
protected $id;
/**
* #ManyToMany(targetEntity="MyClassE")
* #var MyClassE[]
*/
protected $my_class_es;
// ... Other fields and methods
}
/** #Entity() */
class MyConcreteClassAa extends MyAbstractClassA
{
/**
* #Column(type="string")
* #var string
*/
public $aa_param;
// ... Other fields and methods
}
/** #Entity() */
class MyConcreteClassAb extends MyAbstractClassA
{
/**
* #Column(type="string")
* #var string
*/
public $ab_param;
// ... Other fields and methods
}
/** #Entity() */
class MyClassE
{
/**
* #Id
* #Column(type="integer")
* #var int
*/
protected $id;
/**
* #Column(type="string")
* #var string
*/
protected $e_param;
/**
* #ManyToOne(targetEntity="MyClassF")
* #var MyClassF
*/
protected $my_class_f;
// ... Other fields and methods
}
/** #Entity() */
class MyClassF
{
/**
* #Id
* #Column(type="integer")
* #var int
*/
protected $id;
// ... Other fields and methods
}
So here is the schema of what i have : http://pix.toile-libre.org/upload/original/1385651287.png
And there is what i want : http://pix.toile-libre.org/upload/original/1385651300.png
I don't know how to obtain this result, could someone tell me if it's possible ?
Thank you for helping me.

Doctrine Entities and traits. Right way

I have a Comment entity (for user comments) and I want to add a new feature (Commentable) in my old entities.
I created a trait Commentable:
trait Commentable
{
/**
* List of comments
*
* #var Comment[]|ArrayCollection
*
* #ORM\OneToMany(targetEntity="Comment")
*/
protected $comments;
/**
* Constructor
*/
public function __construct()
{
$this->comments = new ArrayCollection();
}
/**
* Get Comments
*
* #return Comment[]|ArrayCollection
*/
public function getComments()
{
return $this->comments;
}
/**
* Add comment to the entity
*
* #param Comment $comment
*/
public function addComment(Comment $comment)
{
$this->comments->add($comment);
}
}
and in the old entities I do something like this:
class Image
{
use Commentable {
Commentable::__construct as private __commentableConstruct;
}
/** some stuff **/
}
The Comment class looks like:
class Comment
{
/**
* Identifier
*
* #var int
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* Comment owner
*
* #var User
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="comments")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* Comment content
*
* #var string
*
* #ORM\Column(type="text")
*/
protected $content;
/**
* #var Image
*
* #ORM\ManyToOne(targetEntity="Image", inversedBy="comments")
*/
protected $image;
/** all the classes using Commentable **/
/** some stuff */
}
I think the idea is not bad. I can create new behaviours and easily add it to entities.
But I don't like the idea on the Comment entity. Adding all the classes using the commentable trait is not 'usefull'.
I'm receiving this error... but I don't know how I can fix that with traits:
OneToMany mapping on field 'comments' requires the 'mappedBy' attribute.
I fixed the problem using
trait Commentable
{
/**
* List of comments
*
* #var Comment[]|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="XXXX\Entity\Comment")
* #ORM\OrderBy({"createdAt" = "DESC"})
*/
protected $comments;
/**
* Constructor
*/
public function __construct()
{
$this->comments = new ArrayCollection();
}
/**
* Get Comments
*
* #return Comment[]|ArrayCollection
*/
public function getComments()
{
return $this->comments;
}
/**
* Add comment to the entity
*
* #param Comment $comment
*/
public function addComment(Comment $comment)
{
$this->comments->add($comment);
}
}
It's not a trait matter, it's a mapping / doctrine related problem.
Your annotation "#OneToMany" misses a configuration according to the documentation
I guess that in your Image class, you should overwrite the property that you use for mapping.

Categories