I have an article entity belongs to a category entity:
/**
* Article
*
* #ORM\Table(name="articles")
* #ORM\Entity(repositoryClass="App\Repository\ArticlesRepository")
* #ORM\HasLifecycleCallbacks
*/
class Article {
/**
* #ORM\Column(name="category_id", type="integer", nullable=true)
*/
private $categoryId;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="articles")
*/
private $category;
}
and I manually set category_id field in PrePersist event:
/** #ORM\PrePersist */
public function setProperPosition(\Doctrine\ORM\Event\LifecycleEventArgs $event){
$this->categoryId = 1;
}
But is does not work. The field (category_id) remains null on the database.
I'm not sure why you have two properties for the same column. You have $category and $categoryId, which basically reference the same value.
So basically you a declaring the same column twice. That's what's likely giving you trouble.
Anyway, try it this way:
/**
* #ORM\Table(name="articles")
* #ORM\Entity(repositoryClass="ArticlesRepository")
* #ORM\HasLifecycleCallbacks
*/
class Article
{
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="articles")
*/
private $category;
/** #ORM\PrePersist */
public function setProperPosition(LifecycleEventArgs $event)
{
$this->category = $event
->getEntityManager()
->getReference(Category::class, 1);
}
}
I simplified all the required namespaces. Make sure you use them so the are imported and available in the file.
(To make it clear, remove the redundant $categoryId definition)
Related
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.
I'm working on a ZF2/Apigility application using Doctrine v2.4.2.
The model structure looks like this: an Asset has an Attachment (so, it's a 1:1 relationship):
The problem is that I cannot persist an Asset with an embedded Attachment and get the error
23000, 1048, Column 'attachment_linkassetuuid' cannot be null
It seems that Doctrine tries to save the Attachment first, cannot find a value for the column attachment_linkassetuuid, sets it to null, and the foreign key constraint is broken.
How to define the entities correctly and get the cascade persisting working?
Asset
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Asset
*
* #ORM\Table(name="tbl_asset")
* #ORM\Entity
*/
class Asset
{
/**
* #var string #ORM\Column(name="asset_uuid", type="string", length=36, nullable=false)
* #ORM\Id
*/
private $uuid;
/**
* #var \MyDoctrineDataAccess\Model\Entity\Attachment
* #ORM\OneToOne(targetEntity="MyDoctrineDataAccess\Model\Entity\Attachment", mappedBy="asset", cascade={"remove", "persist"}, orphanRemoval=true)
*/
private $attachment;
...
}
/**
* #param \MyDoctrineDataAccess\Model\Entity\Attachment $attachment
*/
public function setAttachment($attachment) {
$this->attachment = $attachment;
return $this;
}
/**
* #return the $attachment
*/
public function getAttachment() {
return $this->attachment;
}
Attachment
namespace MyDoctrineDataAccess\Model\Entity;
...
/**
* Attachment
*
* #ORM\Table(name="tbl_attachment", indexes={#ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})})
* #ORM\Entity
*/
class Attachment
{
/**
*
* #var string #ORM\Column(name="attachment_uuid", type="string", length=36, nullable=false)
* #ORM\Id
*/
private $uuid;
/**
*
* #var \MyDoctrineDataAccess\Model\Entity\Asset
* #ORM\OneToOne(targetEntity="\MyDoctrineDataAccess\Model\Entity\Asset", inversedBy="attachment", cascade={"persist"})
* #ORM\JoinColumn(name="attachment_linkassetuuid", referencedColumnName="asset_uuid")
*/
private $asset;
...
}
/**
*
* #param \MyDoctrineDataAccess\Model\Entity\Asset $asset
*/
public function setAsset($asset)
{
$this->asset = $asset;
return $this;
}
/**
*
* #return the $asset
*
*/
public function getAsset()
{
return $this->asset;
}
AssetService
namespace MyApi\V1\Rest\Asset;
...
class AssetService implements ServiceManagerAwareInterface
{
...
public function saveAssets($data)
{
$entityManager = $this->serviceManager->get('Doctrine\ORM\EntityManager');
$assetRepository = $entityManager->getRepository('My\Model\Entity\Asset');
$hydratorManager = $this->serviceManager->get('hydratormanager');
$hydrator = $hydratorManager->get('My\\Model\\Entity\\Hydrator\\EntityHydrator');
foreach ($data as $assetData) {
$asset = new Asset();
$hydrator->hydrate($assetData, $asset);
$entityManager->persist($asset);
$entityManager->flush();
}
}
...
}
Since #JoinColumn defaults nullable to true according to the Doctrine documentation I don't really understand the error. But I do see that in your Attachment entity #table definition you declare an index:
indexes={#ORM\Index(name="fk_attachment_uuid", columns={"attachment_linkassetuuid"})}
Try once to remove this, rebuild your database and check if it solves your issue. If not then leave a comment and I will have another look.
Check the OneToOne example in the Doctrine documentation. Adding an #index like you do is not mentioned there. Doctrine will add the necessary indexes automatically to your relationship columns.
UPDATE:
I think the problem might be that Asset is not the owning side of the relationship. Check the documentation here. Try to change your setAttachment method like this:
public function setAttachment($attachment)
{
$this->attachment = $attachment;
$attachment->setAsset($this);
return $this;
}
I have recently startet with Zend Framework 2 and came now across Doctrine 2, which I would now like to integrate in my first project.
I have now got the following situation and even after days, I can not find a solution.
I have 3 Tables:
Advert
advert_id
advert_title
etc
Category
category_id
name
label
etc
advert2category
advert2category_category_id
advert2category_advert_id
An Advert can be in different Categories and different Categories have different Adverts, therefore the table Advert2Category (ManytoMany).
After reading through the www, I have decided that it should be a ManytoMany Bidirectional, with the "owning side" at the Advert Entity.
Don't ask me why I decided that, I still don't understand Doctrine fully. Anyway, I created 3 Entities, but guess I only need Advert and Category Entity.
I now want the following to happen.
I click on a Category and want to see a list of Articles within this category., that means I have to read out the Table advert2category. I have created the Entities, here my Advert Entity:
So here is first my Advert Entity:
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Advert
*
* #ORM\Table(name="advert")
* #ORM\Entity
*/
class Advert
{
/**
* #var integer
*
* #ORM\Column(name="advert_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $advertId;
/**
* #var string
*
* #ORM\Column(name="advert_title", type="string", length=255, nullable=true)
*/
private $advertTitle;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="advertCategory", cascade={"persist"})
* #ORM\JoinTable(name="advert2category",
* joinColumns={#ORM\JoinColumn(name="advert2category_category_id", referencedColumnName="category_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="advert2category_advert_id", referencedColumnName="advert_id")}
* )
*/
protected $category;
public function __construct()
{
$this->category = new ArrayCollection();
}
/**
* Get advertId
*
* #return integer
*/
public function getAdvertId()
{
return $this->advertId;
}
/**
* Set advertTitle
*
* #param string $advertTitle
* #return Advert
*/
public function setAdvertTitle($advertTitle)
{
$this->advertTitle = $advertTitle;
return $this;
}
/**
* Get advertTitle
*
* #return string
*/
public function getAdvertTitle()
{
return $this->advertTitle;
}
/**
* Set category
*
* #param \Advert\Entity\User $category
* #return Advert
*/
public function setCategory(\Advert\Entity\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \Advert\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
}
And my Category Entity:
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="category_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $categoryId;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="Advert", mappedBy="category")
**/
private $advertCategory;
public function __construct()
{
$this->advertCategory = new ArrayCollection();
}
/**
* Get categoryId
*
* #return integer
*/
public function getCategoryId()
{
return $this->categoryId;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
Just as a first test, I have now tried the following in my Controller:
//Below Controller now works to echo the categories ArrayCollection
$data = $this->getEntityManager()->getRepository('Advert\Entity\Advert')->findAll();
foreach($data as $key=>$row)
{
echo $row->getAdvertTitle();
echo $row->getUser()->getUsername();
$categories = $row->getCategory();
foreach($categories as $row2) {
echo $row2->getName();
}
What am I doing wrong here? Can anyone give me an advice? Thank you very much in advance !
Honestly, and it's a very honest and fine thing, that this is way overcomplicating what you want to do, but only in specific areas.
If you used Composer to include Doctrine (the recommended way), also include symfony/console and you will get a whole mess of awesome tools to help you on your quest. There is a very specific command that will kick you in your seat for how awesome it is: $ doctrine orm:schema-tool:update --force --dump-sql. This will get Doctrine to run through your Entities (you only need the two) and will generate your tables and even setup the *To* associations for you. Int he case of ManyToOne's it will generate the appropriate Foreign Key schema. In the case of ManyToMany's it will automatically create, AND manage it's own association table, you just need only worry about giving the table a name in the Entity.
I'm not kidding you, Do this. It will make your life worth living.
As for your entity setup, this is all you need:
<?php
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Advert
*
* #ORM\Table(name="advert")
* #ORM\Entity
*/
class Advert
{
/**
* #var integer
*
* #ORM\Column(name="advert_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $advertId;
/**
* #var string
*
* #ORM\Column(name="advert_title", type="string", length=255, nullable=true)
*/
private $advertTitle;
/**
* #ORM\ManyToMany(targetEntity="Category", cascade={"persist"})
* #JoinTable(name="advert_categories")
*/
protected $category;
public function __construct()
{
$this->category = new ArrayCollection();
}
/**
* Get advertId
*
* #return integer
*/
public function getAdvertId()
{
return $this->advertId;
}
/**
* Set advertTitle
*
* #param string $advertTitle
* #return Advert
*/
public function setAdvertTitle($advertTitle)
{
$this->advertTitle = $advertTitle;
return $this;
}
/**
* Get advertTitle
*
* #return string
*/
public function getAdvertTitle()
{
return $this->advertTitle;
}
/**
* Set category
*
* #param ArrayCollection $category
* #return Advert
*/
public function setCategory(ArrayCollection $category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return ArrayCollection
*/
public function getCategory()
{
return $this->category;
}
}
Notice that the getters and setters are Documented to Set and Return ArrayCollection, this is important for IDE's and tools that read PHPDoc and Annotations to understand how in-depth PHP class mapping works.
In addition, notice how much simpler the ManyToMany declaration is? The #JoinTable annotation is there to give a name to the table that doctrine will generate and manage. That's all you need!
But now, you probably should remove the $advertCategory property out of the Category Entity. Doctrine is going to auto-hydrate embedded Entities in properties with the Entity Association Mappings.
This is also potentially dangerous as it can result in infinite recursion. Basically, if all you requested was an Advert with ID of 1, it would go in and find ALL of the Category Entities associated to Advert 1, but inside of those Categories it's re-referencing Advert 1, which Doctrine will sub-query for and inject, which will contain a Category association, which will then Grab those categories, and so on and so fourth until PHP kills itself from lack of memory.
Once everything is good to go, and you got some Categories associated with your Advert, using the Getter for your category in the Advert entity will return an array of Category Entities. Simply iterate through them:
foreach($category as $advert->getCategories()) {
echo $category->getName();
}
or
echo current($advert->getCategories())->getName();
After I successfuly created TaskBundle with One-to-Many relation between category and tasks, now I'm trying to create a new TaskBundle with Many-to-Many relation. I get also problem with checking checkbox in this relation, but now it is not a primary problem (maybe after solving this). I deleted all tables, which is TaskBundle using and trying to create a new, but here is problem (description at the bottom).
My Task object:
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="tasks")
*/
class Task
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=200)
* #Assert\NotBlank(
* message = "Task is empty"
* )
* #Assert\Length(
* min = "3",
* minMessage = "Task is too short"
* )
*/
protected $task;
/**
* #ORM\Column(type="datetime")
* #Assert\NotBlank()
* #Assert\Type("\DateTime")
*/
protected $dueDate;
/**
* #Assert\True(message = "You have to agree.")
*/
protected $accepted;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories")
*/
protected $category;
/**
* Constructor
*/
public function __construct()
{
$this->category = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set task
*
* #param string $task
* #return Task
*/
public function setTask($task)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return string
*/
public function getTask()
{
return $this->task;
}
/**
* Set dueDate
*
* #param \DateTime $dueDate
* #return Task
*/
public function setDueDate($dueDate)
{
$this->dueDate = $dueDate;
return $this;
}
/**
* Get dueDate
*
* #return \DateTime
*/
public function getDueDate()
{
return $this->dueDate;
}
/**
* Add category
*
* #param \Acme\TaskBundle\Entity\Category $category
* #return Task
*/
public function addCategory(\Acme\TaskBundle\Entity\Category $category)
{
$this->category[] = $category;
return $this;
}
/**
* Remove category
*
* #param \Acme\TaskBundle\Entity\Category $category
*/
public function removeCategory(\Acme\TaskBundle\Entity\Category $category)
{
$this->category->removeElement($category);
}
/**
* Get category
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategory()
{
return $this->category;
}
}
and Category object
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="categories")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=200, unique=true)
* #Assert\NotNull(message="Categories cannot be empty", groups = {"adding"})
*/
protected $name;
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="category")
*/
private $tasks;
public function __toString()
{
return strval($this->name);
}
/**
* Constructor
*/
public function __construct()
{
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
* #return Category
*/
public function addTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks[] = $tasks;
return $this;
}
/**
* Remove tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
*/
public function removeTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks->removeElement($tasks);
}
/**
* Get tasks
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTasks()
{
return $this->tasks;
}
}
So, after i put doctrine:schema:update --force i'll get error: Table 'symfony.categories' already exists. I've tried to delete all caches, but same problem. Any idea?
There's only problem, if it is as m2m relation.
PS: I was looking for this problem at the Google, but no one answers at this problem. There were only questions, but not correct answers, where the problem is and how to solve it.
Looks like you already have table named "categories" in that database. Remove this line #ORM\JoinTable(name="categories") and try without it.
P.S. "Categories" is really a strange name for join table. You should probably follow some conventions and let doctrine name it. Common names for join tables are category_task or category2task as they are more self-explanatory. Nothing that important, just trying to suggest what I consider good practice.
The thing is that doctrine doesn't understand how your existing table should be used. But you can give him some help.
You have two options :
You don't care about the existing table : simple, you can remove the #ORM\JoinTable(name="categories") annotation, and doctrine will create an other table etc.
You want to keep your existing table, which sounds pretty logical : you have to be more explicit in your annotation by adding #ORM\JoinColumn annotation.
Here is an example:
class
<?php
...
/**
* #ORM\Entity
* #ORM\Table(name="tasks")
*/
class Task
{
...
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="task_id", referencedColumnName="id")})
*/
protected $category;
...
}
and Category object
<?php
...
/**
* #ORM\Entity
* #ORM\Table(name="categories")
*/
class Category
{
...
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="category")
* #ORM\JoinTable(name="categories",
* joinColumns={#ORM\JoinColumn(name="task_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")})
*/
private $tasks;
...
Doing so, you will be able to keep your table without any doctrine error.
My fix for this, as far as I can tell, was a case-sensitivity issue with table names. Doctrine let me create a Users and a users table but afterwards would die on migrations:diff or migrations:migrate .
I used the -vvv option to get more detail on this error message; it seems that the error happens when Doctrine is loading up its own internal representation of the current database's schema. So if your current database has table names that Doctrine doesn't understand (like two tables that are identical, case-insensitive) then it will blow up in this fashion.
Seems like most of the answers above assume that the error is in your code, but in my case it was in the database.
I got this error with 2 ManyToMany targeting the same entity (User in the exemple below).
To create the table name doctrine use the entity and target entity name.
So in my case it was trying to create two time the table thread_user
To debug this it's easy. Just use the '#ORM\JoinTable' annotation and specify the table name.
Here is a working exemple.
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User")
* #ORM\JoinTable(name="thread_participant")
*/
private $participants;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User")
* #ORM\JoinTable(name="thread_recipient")
*/
private $recipients;
in Symfony4.1 you can force the migration using the migration version
doctrine:migrations:execute <migration version>
ex
for migration version123456.php use
doctrine:migrations:execute 123456
there is another using the table name ,you can search it in your project . Maby be demo,I think it...
sorry for my chinese english !
Try to drop everything inside of your proxy directory.
I fix same issue after check other entities on each bundles, be aware of this.
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.