在 Doctrine 中为 updated_at、created_at 自动取值

Posted

技术标签:

【中文标题】在 Doctrine 中为 updated_at、created_at 自动取值【英文标题】:Automatic values for updated_at, created_at in Doctrine 【发布时间】:2013-06-23 16:47:42 【问题描述】:

我想让我的Doctrine 实体中的字段updated_atcreated_at 自动更新。

在 Ruby on Rails 模型中有 2 个字段:updated_atcreated_at

描述可以在这里找到:http://guides.rubyonrails.org/migrations.html#migration-overview:

timestamps 宏添加了两列,created_at 和 updated_at。如果存在这些特殊列,则它们会由 Active Record 自动管理。

我可以在 Doctrine 2 中启用类似的功能吗?

【问题讨论】:

【参考方案1】:
    您可以在__construct方法中调用$this->setCreatedAt(new \DateTime())。 您可以使用Life Cycle Callbacks
/**
 * @ORM\PrePersist
 * @ORM\PreUpdate
*/
public function updatedTimestamps(): void

    $this->setUpdatedAt(new \DateTime('now'));    
    if ($this->getCreatedAt() === null) 
        $this->setCreatedAt(new \DateTime('now'));
    

并且不要忘记添加到实体类符号中: @ORM\HasLifecycleCallbacks

【讨论】:

在此处获取 OOP 示例-gist.github.com/lelledaniele/be67e03b51e04ab9f9b04b985ccd94e2 3.在构造函数中使用:$this->publishedAt = new \DateTime();$this->updatedAt = new \DateTime(); @VladimirCh 即使实体中没有任何其他内容被更新,也会设置 updatedAt。 @marcguyer 不正确,因为构造函数只会在第一次创建时被教义调用。 'now' 不需要 new \DateTime('now'),因为它是默认值【参考方案2】:

如果您想单独处理它们,这是另一种选择。

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="person")
 * @ORM\HasLifecycleCallbacks
 */
class Person

    ..........

    /**
     * @var datetime $created
     *
     * @ORM\Column(type="datetime")
     */
    protected $created;

    /**
     * @var datetime $updated
     * 
     * @ORM\Column(type="datetime", nullable = true)
     */
    protected $updated;


    /**
     * Gets triggered only on insert

     * @ORM\PrePersist
     */
    public function onPrePersist()
    
        $this->created = new \DateTime("now");
    

    /**
     * Gets triggered every time on update

     * @ORM\PreUpdate
     */
    public function onPreUpdate()
    
        $this->updated = new \DateTime("now");
    

    ..........

【讨论】:

很好的答案,但如果您想按此字段排序,updated_at 在第一次更新之前获得空值这一事实可能会很痛苦。 @El_Matella 您只需更改onPrePersist() 函数,使其同时设置createdupdated。如果您之前在生产环境中没有这样做,也可以轻松地在数据库中修复。 是的,我就是这么做的 :) 如何使用 Yml 文件在 createdAt 字段中插入当前日期时间? 非常好。对于未来的用户,不要忘记在类注释中添加@ORM\HasLifecyleCallbacks(这会节省我一些时间)。【参考方案3】:

对我来说最方便的解决方案是StofDoctrineExtensionsBundle 的Timestampable 功能。

简单的配置,之后您可以通过添加两个简单的annotations 来自动填写EntitycreatedAtupdatedAt 字段,例如:

@Gedmo\Mapping\Annotation\Timestampable(on="create")

和/或

@Gedmo\Mapping\Annotation\Timestampable(on="update")

例如

/**
 * @var \DateTime
 * @Gedmo\Mapping\Annotation\Timestampable(on="create")
 * @Doctrine\ORM\Mapping\Column(type="datetime")
 */
protected $createdAt;

/**
 * @var \DateTime
 * @Gedmo\Mapping\Annotation\Timestampable(on="update")
 * @Doctrine\ORM\Mapping\Column(type="datetime")
 */
protected $updatedAt;

php 中没有任何冗余代码。

【讨论】:

如果您已经使用 StofDoctrineExtensions(可能是我们大多数人),这是最好的解决方案。应该注意的是,您需要启用时间戳:symfony.com/doc/master/bundles/StofDoctrineExtensionsBundle/… 使用 Symfony 4.0+ composer require stof/doctrine-extensions-bundle 安装(使用 Flex) 我在 symfony Flex 中使用这种方法,对我来说唯一缺少的部分是我必须更新 ./config/bundles.php 以包含 Stof 包:Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],【参考方案4】:

您也可以将其实现为 trait - 像这样:

<?php

namespace App\Entity\Traits;

use DateTime;
use DateTimeInterface;
use Exception;

/**
 * Trait TimeStampableTrait
 * @package App\Entity\Trait
 */
trait TimeStampableTrait

    /**
     * @ORM\Column(type="datetime")
     */
    private $createdAt;

    /**
     * @ORM\Column(type="datetime")
     */
    private $updatedAt;

    /**
     * @return DateTimeInterface|null
     * @throws Exception
     */
    public function getCreatedAt(): ?DateTimeInterface
    
        return $this->createdAt ?? new DateTime();
    

    /**
     * @param DateTimeInterface $createdAt
     * @return $this
     */
    public function setCreatedAt(DateTimeInterface $createdAt): self
    
        $this->createdAt = $createdAt;

        return $this;
    

    /**
     * @return DateTimeInterface|null
     */
    public function getUpdatedAt(): ?DateTimeInterface
    
        return $this->updatedAt ?? new DateTime();
    

    /**
     * @param DateTimeInterface $updatedAt
     * @return $this
     */
    public function setUpdatedAt(DateTimeInterface $updatedAt): self
    
        $this->updatedAt = $updatedAt;

        return $this;
    

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function updateTimestamps(): void
    
        $now = new DateTime();
        $this->setUpdatedAt($now);
        if ($this->getId() === null) 
            $this->setCreatedAt($now);
        
    

将此特征添加到您的实体(不要忘记@ORM\HasLifecycleCallbacks() 符号):

<?php

namespace App\Entity;

use App\Entity\Traits\TimeStampableTrait;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\MyEntityRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class MyEntity

    use TimeStampableTrait;

【讨论】:

【参考方案5】:

我建议使用可时间戳特征

https://symfonycasts.com/screencast/symfony4-doctrine/timestampable

use Gedmo\Timestampable\Traits\TimestampableEntity;

class Article

    use TimestampableEntity;

将自动添加所有适当的功能

【讨论】:

以上是关于在 Doctrine 中为 updated_at、created_at 自动取值的主要内容,如果未能解决你的问题,请参考以下文章

Symfony Doctrine 关系在 PhpUnit 测试中为空

如何在Doctrine2中为单个实体使用多个存储库?

如何在 Symfony 中添加 Doctrine 过滤器?

Doctrine 2 和带有额外字段的多对多链接表

如何在Symfony 4中为测试环境设置数据库

如何在 Symfony 2 中为数据库视图设置实体(原则)