Php traits

С выходом PHP версии 5.3 язык ожил и заиграл новыми красками. Пафосно звучит конечно, но это факт. Следущие две версии, 5.4 и 5.5, соответственно, принесли тоже не мало вкусных плюшек, использование которых реально доставляет немалое удовольствие. Сегодня не столько делюсь опытом, сколько делюсь впечатлениями, так как впервые нашлось и время и возможность попробовать и применить эти самые плюшки.

Вот вам пример простенькой модельки, с использованием Doctrine:

<?php

namespace Application\AcmeBundle\Entity;

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

/**
 * Model
 *
 * @ORM\Table()
 * @ORM\Entity
 */

class Model
{

    /**
     * @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)
     */

    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="code", type="string", length=255)
     */

    private $code;

    /**
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
     */

    protected $createdAt;

    /**
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */

    protected $updatedAt;

    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="created_by_id", referencedColumnName="id")
     */

    protected $createdBy;

    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="updated_by_id", referencedColumnName="id")
     */

    protected $updatedBy;

    /**
     * Get id
     *
     * @return integer
     */

    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Menu
     */

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */

    public function getName()
    {
        return $this->name;
    }

    /**
     * Set code
     *
     * @param string $code
     * @return Menu
     */

    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

    /**
     * Get code
     *
     * @return string
     */

    public function getCode()
    {
        return $this->code;
    }

    /**
     * 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;
    }

    /**
     * Set createdBy
     *
     * @param \Application\AcmeBundle\Entity\User $createdBy
     * @return \Application\AcmeBundle\Entity\User
     */

    public function setCreatedBy(\Application\AcmeBundle\User $createdBy = null)
    {
        $this->createdBy = $createdBy;

        return $this;
    }

    /**
     * Get createdBy
     *
     * @return \Application\AcmeBundle\Entity\User
     */

    public function getCreatedBy()
    {
        return $this->createdBy;
    }

    /**
     * Set updatedBy
     *
     * @param \Application\AcmeBundle\Entity\User $updatedBy
     * @return \Application\AcmeBundle\Entity\User
     */

    public function setUpdatedBy(\Application\AcmeBundle\Entity\User $updatedBy = null)
    {
        $this->updatedBy = $updatedBy;

        return $this;
    }

    /**
     * Get updatedBy
     *
     * @return \Application\AcmeBundle\Entity\User
     */

    public function getUpdatedBy()
    {
        return $this->updatedBy;
    }
}

Дофига, правда? И это всего лишь для того, что бы описать простую таблицу из 7 полей. Обратите внимание на последние четыре свойства: createdAt, updatedAt, createdBy, createdBy. Служебные поля, которые могут понадобиться в нескольких моделях, писать их в каждой ну просто лениво. Варианты?

Traits

Traits появились в php версии 5.4. Вкратце, для тех, кто не в курсе, traits — это механизм обеспечения повторного использования, предназначены для уменьшения некоторых ограничений единого наследования, позволяя разработчику повторно использовать наборы методов свободно, в нескольких независимых классах и реализованных с использованием разных архитектур построения классов © php.net

Как нам могут помочь эти самые traits?

Используем trait, который отвечает за поля createdAt и updatedAt:

<?php

namespace Gedmo\Timestampable\Traits;

trait TimestampableEntity
{
    /**
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
     */

    protected $createdAt;

    /**
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */

    protected $updatedAt;

    /**
     * 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;
    }
}

Используем trait, который отвечает за поля createdBy и updatedBy:

<?php

namespace Application\AcmeBundle\Traits;

trait UserableEntity
{
    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="created_by_id", referencedColumnName="id")
     */

    protected $createdBy;

    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="updated_by_id", referencedColumnName="id")
     */

    protected $updatedBy;

    /**
     * Set createdBy
     *
     * @param \Application\AcmeBundle\Entity\User $createdBy
     * @return User
     */

    public function setCreatedBy(\Application\AcmeBundle\Entity\User $createdBy = null)
    {
        $this->createdBy = $createdBy;

        return $this;
    }

    /**
     * Get createdBy
     *
     * @return \Application\AcmeBundle\Entity\User
     */

    public function getCreatedBy()
    {
        return $this->createdBy;
    }

    /**
     * Set updatedBy
     *
     * @param \Application\AcmeBundle\Entity\User $updatedBy
     * @return User
     */

    public function setUpdatedBy(\Application\AcmeBundle\Entity\User $updatedBy = null)
    {
        $this->updatedBy = $updatedBy;

        return $this;
    }

    /**
     * Get updatedBy
     *
     * @return \Application\AcmeBundle\Entity\User
     */

    public function getUpdatedBy()
    {
        return $this->updatedBy;
    }

}

Создадим, для дальнейшего использования несколькими моделями абстрактный класс, которы подключит traits:

<?php

namespace Application\AcmeBundle\Entity;

use Gedmo\Timestampable\Traits\TimestampableEntity;
use Application\AcmeBundle\Traits\UserableEntity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;

abstract class AbstractEntity
{
    use TimestampableEntity;
    use UserableEntity;
}

Ну и теперь, посмотрим, как будет выглядеть модель, которую я привел в самом начале:

<?php

namespace Application\AcmeBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Application\AcmeBundle\Entity\AbstractEntity;

/**
 * Model
 *
 * @ORM\Table()
 * @ORM\Entity
 */

class Model extends AbstractEntity
{

    /**
     * @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)
     */

    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="code", type="string", length=255)
     */

    private $code;

    /**
     * Get id
     *
     * @return integer
     */

    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Menu
     */

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */

    public function getName()
    {
        return $this->name;
    }

    /**
     * Set code
     *
     * @param string $code
     * @return Menu
     */

    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

    /**
     * Get code
     *
     * @return string
     */

    public function getCode()
    {
        return $this->code;
    }
}

96 строк кода против 215 изначальных, неплохо, правда? Бонусом — возможность использовать эти поля в других моделях без оглядки на структуру таблиц в целом. Trait Timestampable можно найти в бандле DoctrineExtensions на Github.

Php traits

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *