С выходом PHP версии 5.3 язык ожил и заиграл новыми красками. Пафосно звучит конечно, но это факт. Следущие две версии, 5.4 и 5.5, соответственно, принесли тоже не мало вкусных плюшек, использование которых реально доставляет немалое удовольствие. Сегодня не столько делюсь опытом, сколько делюсь впечатлениями, так как впервые нашлось и время и возможность попробовать и применить эти самые плюшки.
Вот вам пример простенькой модельки, с использованием Doctrine:
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:
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:
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:
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;
}
Ну и теперь, посмотрим, как будет выглядеть модель, которую я привел в самом начале:
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.