【问题标题】:Doctrine - Add default time stamp to entity like NOW()Doctrine - 为 NOW() 等实体添加默认时间戳
【发布时间】:2012-11-30 19:15:42
【问题描述】:

按照 Doctrine 指南,我了解如何为实体设置默认值,但如果我想要日期/时间戳怎么办?

我的问题是我的数据库在字段上有默认的 NOW(),但是当我使用 Doctrine 插入记录时,值是 null 或空白,但插入的其余部分发生了。

此外,由于 Doctrine 说要将默认值声明为 const,这也会产生问题。

建议?

【问题讨论】:

    标签: php postgresql symfony doctrine-orm entities


    【解决方案1】:

    好的,我找到了解决方案:

    prePersist 选项是我正在做的。

    确保在注释中定义

    <?php
    
    /** @Entity 
     *  @HasLifecycleCallbacks 
     */
    class User
    

    这是他们提供的功能示例

    /** 
     *  @PrePersist 
     */
    public function doStuffOnPrePersist()
    {
        $this->createdAt = date('Y-m-d H:i:s');
    }
    

    如果你像我一样使用 ORM

    <?php
    
    /** @ORM\Entity 
     *  @ORM\HasLifecycleCallbacks 
     */
    class User
    

    这是他们提供的功能示例

    /** 
     *  @ORM\PrePersist 
     */
    public function doStuffOnPrePersist()
    {
        $this->createdAt = date('Y-m-d H:i:s');
    }
    

    【讨论】:

    • 有没有办法在不使用 php 注释的可憎性的情况下实现这一点?
    • @Sejanus,是的,Doctrine 有 XML、YAML 和 PHP 注释。请参阅docs.doctrine-project.org/projects/doctrine-orm/en/latest 下的“驱动程序”
    • 来自文档:“应该注意,此事件仅在实体的 initial 持久化时触发(即它不会在未来更新时触发)”
    • 我认为值得注意的是,这个解决方案和我的下面都是很好的解决方案。它的工作方式有一个重要区别。在我的解决方案中,时间戳是在首次实例化实体时创建的。在这个解决方案中,时间戳是在它被持久化到数据库时设置的。
    • 这会起作用,但更新将由 symfony 层中的学说完成。如果您认为更新应该由 db 层完成,那么您需要找到如何设置on update CURRENT_TIMESTAMP。如果你发现也通知我:)
    【解决方案2】:

    根据我的经验,最好将所有内容都放在您的实体中,而不是试图强制您的数据库绕过 ORM。

    <?php
    namespace Phill\PaffordBundle\Entity;
    use Doctrine\ORM\Mapping as ORM;
    /**
     * Stack
     * @ORM\Table()
     */
    class Stack
    {
      /**
       * @var integer
       * @ORM\Column(type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="AUTO")
       */
      private $id;
    
      /**
       * @var \DateTime
       * @ORM\Column(type="datetime")
       */
      private $startDate;
    
      public function __construct()
      {
        $this->startDate = new \DateTime();
      }
    
    }
    

    【讨论】:

    • 我不同意,原因如下:ORM 可以改变,如果我执行原始 SQL 会怎样,还有其他原因,但这至少应该在数据库端处理以保证数据完整性
    • 那么就看你的需要了。通常在使用 Doctrine 时,开发人员的意图是对 ORM 进行编程并仅使用 DB 作为后端。如果不是这种情况,则需要将内容推送到数据库,就像您建议的那样。我认为对于那些只想与 ORM 交互的人来说,这是更好的解决方案。
    • 我认为值得注意的是,这个解决方案和上面的@PhillPafford 都是很好的解决方案。它的工作方式有一个重要区别。在我的解决方案中,时间戳是在第一次实例化实体时创建的。在这个解决方案中,时间戳是在它被持久化到数据库时设置的。
    【解决方案3】:

    为了准确地拥有NOW(),您可以扩展Doctrine\DBAL\Types\DateTimeType

    其他方法:

    class DateTimeNow
    {
        public function format() 
        {
            return 'NOW()';
        }
    }
    

    那么您可以使用$entity-&gt;setFieldDatetime(DateTimeNow()) 而不是$entity-&gt;setFieldDatetime(new Datetime())
    注意:方法format()会被Doctrine自动调用。

    【讨论】:

    • 这段代码要放在哪里(即在哪个文件中)(在 Symfony 中)?谢谢!
    • @ThomasLandauer 我做了它,并直接将它放在我需要使用它的文件中......但最好在供应商文件夹或类似的东西中创建一个包。
    • 这个答案是迄今为止唯一使用数据库服务器时间(而不是 PHP 时间)的解决方案。这就是为什么这是一件好事:stackoverflow.com/a/3705090/1668200
    【解决方案4】:

    试试这个:

    /**
     * @var \DateTime
     *
     * @Column(name="created", type="datetime", nullable=false)
     */
    private $created;
    
    function __construct()
    {
        $this->created = new \DateTime();
    }
    

    您分配给created 字段的$value 必须能够处理此调用:

    $value->format('Y-m-d H:i:s');
    

    relevant Doctrine code line

    经测试可与 Doctrine 2.5.4 一起使用

    注意:以上内容在创建时有效,但默认情况下更新时无效——您必须在进行更新或查看 doStuffOnPrePersist 时手动将 created 属性设置为 new \DateTime()

    /** @PrePersist */
    public function doStuffOnPrePersist()
    {
        $this->created = date('Y-m-d H:i:s');
    }
    

    【讨论】:

    • 这对您有什么作用?我收到错误:错误:调用字符串上的成员函数 format() 是有道理的,因为 'CURRENT_TIMESTAMP' 是字符串:/
    • 哈哈,我得到了同样的错误! (我一直用它来读取数据)
    • 我在 doStuffOnPrePersist() 函数中使用了这个
    • “不要在你的实体中使用魔术钩” Marco Pivetta,该教义的作者
    • 不要使用它,...但是如果您必须将PrePersist 编程到 Doctrine 中?:)
    【解决方案5】:

    您可以使用 TimestampableEntity Trait 在您的实体中自动创建 created_at 和 updated_at 字段;

    首先安装学说扩展;

    composer require gedmo/doctrine-extensions
    

    第二次将 trait 添加到您的实体类中;

    use Gedmo\Timestampable\Traits\TimestampableEntity;
    
        /**
         * @ORM\Entity(repositoryClass="App\Repository\ProjectRepository")
         */
        class Project
        {
            use TimestampableEntity;
    

    【讨论】:

      【解决方案6】:

      对于 PostgreSQL,您应该能够将字符串值 now 传递给字段以获取时间戳以发挥作用。

      【讨论】:

      • 谢谢,使用 PostgreSQL 9.x 并将 DEFAULT 值从 now() 更改为 CURRENT_TIMESTAMP 但它又恢复为 now()。还创建了一个测试表并将日期时间列设置为 CURRENT_TIMESTAMP,但也恢复为 now()。还有其他想法吗?
      • 抱歉,没有意识到它是 Postgres。我正在对 PHP 用户更常见的 MySQL 进行评论。为 PostgreSQL 添加了标签。我也更新了我的答案。
      • 抱歉没用,现在传递字符串时出现日期时间问题
      • 那么当您尝试使用该值时,您会从 Doctrine 收到 PHP 级别的错误吗?如果您仅将它用于数据插入目的并且不打算从中读取,您可能会欺骗 Doctrine 说该字段是一个字符串。我没有在 Postgres 中使用过 Doctrine,所以我真的不知道在这种情况下最好的方法。
      【解决方案7】:
      #[ORM\Column(type: 'datetime_immutable', options: ['default' => 'CURRENT_TIMESTAMP'])]
          private $createdAt;
      
          #[ORM\Column(type: 'datetime_immutable', options: ['default' => 'CURRENT_TIMESTAMP'], columnDefinition: "DATETIME on update CURRENT_TIMESTAMP")]
          private $modifiedAt;
      

      这是我发现的,我能够获得“ON UPDATE CURRENT_TIMESTAMP()”,但是该列变为可为空,在我看来这是一个更好的权衡。

      【讨论】:

        猜你喜欢
        • 2016-12-19
        • 1970-01-01
        • 2016-04-07
        • 2012-06-30
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多