4
votes

I have an Entity, where I want to use trait "TimestampableEntity" for mapping some properties:

namespace Wbudowie\PortalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Wbudowie\PortalBundle\Traits\TimestampableEntity;

/**
 * Category
 * 
 * @Gedmo\Tree(type="materializedPath")
 * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
 * @ORM\Table(name="categories")
 * @ORM\Entity(repositoryClass="CategoryRepository")
 */
class Category {

    use TimestampableEntity;

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

This is my TimestampableEntity trait:

namespace Wbudowie\PortalBundle\Traits;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

trait TimestampableEntity {

    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(name="created_at", type="datetime")
     */
    private $createdAt;

    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(name="edited_at", type="datetime", nullable=true)
     */
    private $editedAt;

    /**
     * @var \DateTime
     * @ORM\Column(name="deleted_at",type="datetime", nullable=true)
     */
    private $deletedAt;

    /**
     * @var boolean
     *
     * @ORM\Column(name="is_active", type="boolean")
     */
    private $isActive;

    /**
     * Sets createdAt.
     *
     * @param  \DateTime $createdAt
     * @return $this
     */
    public function setCreatedAt(\DateTime $createdAt) {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Returns createdAt.
     *
     * @return \DateTime
     */
    public function getCreatedAt() {
        return $this->createdAt;
    }

    /**
     * Sets updatedAt.
     *
     * @param  \DateTime $updatedAt
     * @return $this
     */
    public function setUpdatedAt(\DateTime $updatedAt) {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Returns updatedAt.
     *
     * @return \DateTime
     */
    public function getUpdatedAt() {
        return $this->updatedAt;
    }

    /**
     * Sets deletedAt.
     *
     * @param \Datetime|null $deletedAt
     * 
     * @return $this
     */
    public function setDeletedAt(\DateTime $deletedAt = null) {
        $this->deletedAt = $deletedAt;

        return $this;
    }

    /**
     * Returns deletedAt.
     *
     * @return \DateTime
     */
    public function getDeletedAt() {
        return $this->deletedAt;
    }

    /**
     * Is deleted?
     * 
     * @return bool
     */
    public function isDeleted() {
        return null !== $this->deletedAt;
    }

    /**
     * Set isActive
     *
     * @param boolean $isActive
     * @return $this
     */
    public function setIsActive($isActive) {
        $this->isActive = $isActive;

        return $this;
    }

    /**
     * Get isActive
     *
     * @return boolean 
     */
    public function getIsActive() {
        return $this->isActive;
    }

}

When I run php bin/console doctrine:generate:entities Wbudowie\PortalBundle on my entity has been added this code:

/**
 * @var \DateTime
 */
private $createdAt;

/**
 * @var \DateTime
 */
private $editedAt;

/**
 * @var \DateTime
 */
private $deletedAt;

/**
 * @var boolean
 */
private $isActive;


/**
 * Set createdAt
 *
 * @param \DateTime $createdAt
 * @return Category
 */
public function setCreatedAt($createdAt)
{
    $this->createdAt = $createdAt;

    return $this;
}

/**
 * Get createdAt
 *
 * @return \DateTime 
 */
public function getCreatedAt()
{
    return $this->createdAt;
}

/**
 * Set editedAt
 *
 * @param \DateTime $editedAt
 * @return Category
 */
public function setEditedAt($editedAt)
{
    $this->editedAt = $editedAt;

    return $this;
}

/**
 * Get editedAt
 *
 * @return \DateTime 
 */
public function getEditedAt()
{
    return $this->editedAt;
}

/**
 * Set deletedAt
 *
 * @param \DateTime $deletedAt
 * @return Category
 */
public function setDeletedAt($deletedAt)
{
    $this->deletedAt = $deletedAt;

    return $this;
}

/**
 * Get deletedAt
 *
 * @return \DateTime 
 */
public function getDeletedAt()
{
    return $this->deletedAt;
}

/**
 * Set isActive
 *
 * @param boolean $isActive
 * @return Category
 */
public function setIsActive($isActive)
{
    $this->isActive = $isActive;

    return $this;
}

/**
 * Get isActive
 *
 * @return boolean 
 */
public function getIsActive()
{
    return $this->isActive;
}

After that when I try do do anything I'm getting this error, so I have to remove generated code:

Runtime Notice: Wbudowie\PortalBundle\Entity\Category and Wbudowie\PortalBundle\Traits\TimestampableEntity define the same property ($createdAt) in the composition of Wbudowie\PortalBundle\Entity\Category. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed in /mnt/DANE/projekty/wbudowie/src/Wbudowie/PortalBundle/Entity/Category.php line 607

What is wrong? I'm using PHP 5.5.9, Doctrine 2.4.* and Symfony 2.5.*


Edit: It,s doctrine bug. It is fixed, but not in 2.4.x version.

https://github.com/doctrine/doctrine2/pull/632

https://github.com/doctrine/doctrine2/pull/763

2
Please write what you are trying to achieve - Rishi Dua
I don't want to have copied everything from trait to my entity, because I want to have everything in my trait. - cyklista
This patch fix generating entities when you use traits: pastebin.com/bQppqbg5 - cyklista

2 Answers

1
votes

Here

That's all what you would possibly need to achieve your goal.

And according to this, it's something you can't do anything about. Just don't use generate entities :)

0
votes

I have had success with this. Try these steps:

First add the entity annotation to your trait:

/**
* @ORM\Entity 
*/
trait TimestampableEntity

Temporarily change it to a class

/**
* @ORM\Entity 
*/
class TimestampableEntity

Run generate:entities on your trait:

app/console doctrine:generate:entities WbudowiePortalBundle:Traits/TimestampableEntity

Change TimestampableEntity back to a trait:

/**
* @ORM\Entity 
*/
trait TimestampableEntity

Add the trait to Category

class Category {

    use TimestampableEntity;

If you now use:

app/console doctrine:generate:entities WbudowiePortalBundle:Category

You shouldn't see the duplicates. I'm not sure, but I believe this works because your trait's getters and setters will now be identical to those that might have been created in Category so they aren't replaced. Hand coding the getters and settings might cause discrepancies that cause Doctrine to think new code is required in Category.