Doctrine - Add default time stamp to entity like NOW()

34,971

Solution 1

Ok I found the solution:

The prePersist option is what I'm doing.

Make sure you define in the annotations

<?php

/** @Entity 
 *  @HasLifecycleCallbacks 
 */
class User

and here is the function example they offer

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

And if you're using ORM like I am

<?php

/** @ORM\Entity 
 *  @ORM\HasLifecycleCallbacks 
 */
class User

and here is the function example they offer

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

Solution 2

In my experience it is best to put everything in your Entities and not try to force your database to bypass the 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();
  }

}

Solution 3

In order to have exactly NOW() you could extend Doctrine\DBAL\Types\DateTimeType.

Other method:

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

Then you can use $entity->setFieldDatetime(DateTimeNow()) instead of $entity->setFieldDatetime(new Datetime()).
Note: The method format() is automatically called by Doctrine.

Solution 4

Try this:

/**
 * @var \DateTime
 *
 * @Column(name="created", type="datetime", nullable=false)
 */
private $created;

function __construct()
{
    $this->created = new \DateTime();
}

The whatever $value you assign to created field, has to be able to handle this call:

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

See relevant Doctrine code line

Tested to work with Doctrine 2.5.4

Note: above works at creation time but not on update by default -- you have to manually set created property to new \DateTime()when you do an update or look into doStuffOnPrePersist

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

Solution 5

You can use TimestampableEntity Trait for automatically create created_at and updated_at fields in you Entity;

First install doctrine-extensions;

composer require gedmo/doctrine-extensions

Secondly add trait into your Entity Class;

use Gedmo\Timestampable\Traits\TimestampableEntity;

    /**
     * @ORM\Entity(repositoryClass="App\Repository\ProjectRepository")
     */
    class Project
    {
        use TimestampableEntity;
Share:
34,971
Phill Pafford
Author by

Phill Pafford

Love development with PHP/Symfony/PHPStorm, iOS, PostgreSQL, Linux flavor Ubuntu, jQuery/Mobile, Foundation CSS, GitFlow AVH and HTML5 Personal Projects are Crypto Currencies, Home Automation, Mobile development, SMS/MMS and DIY electronics via Make and Hack A Day https://keybase.io/phillpafford https://onename.com/phillpafford #bitcoin: https://www.coinbase.com/phillpafford #DogeCoin: D67fwUKwKQQeL9pdbZmbWcevuAYW8XPqyz

Updated on December 27, 2021

Comments

  • Phill Pafford
    Phill Pafford over 2 years

    Following the Doctrine guidelines I understand how to set a default value for an Entity, but what if I wanted a date/time stamp?

    My problem is my database has a default of NOW() on a field but when I use Doctrine to insert a record the values are null or blank but the rest of the insert happened.

    Also since Doctrine says to declare the default as a const, this also creates a problem.

    Suggestions?

  • Phill Pafford
    Phill Pafford over 11 years
    Thanks, Using PostgreSQL 9.x and when changing the DEFAULT value from now() to CURRENT_TIMESTAMP but it reverts back to now(). Also created a test table and set the datetime column to CURRENT_TIMESTAMP but also reverted to now(). Any other thoughts?
  • Mike Brant
    Mike Brant over 11 years
    Sorry, didn't realize it was Postgres. I was giving commentary for MySQL which is more typically encountered by PHP users. Have added tag for PostgreSQL. I have updated my answer as well.
  • Phill Pafford
    Phill Pafford over 11 years
    sorry that didn;'t work either, DateTime issue when passing string NOW
  • Mike Brant
    Mike Brant over 11 years
    So you are getting a PHP-level error from Doctrine when trying to use that value? If you are only using it for data insert purposes and aren't going to be reading from it, you might trick Doctrine be saying the field is a string. I haven't used Doctrine with Postgres, so I don't really know best approach in this case.
  • Phill Pafford
    Phill Pafford almost 10 years
    I disagree, here is why: ORM can change, what if I do raw SQL, there are other reasons as well but this should be handled on the database side for at least data integrity
  • David Baucum
    David Baucum almost 10 years
    Then it just depends on your needs. Often when using Doctrine it is the developer's intention to program to the ORM and just use the DB as the backend. If that is not the case then stuff will need to be pusehd to the DB, like you are suggesting. I think that for those who are looking to only interface with the ORM then this is the better solution.
  • Sejanus
    Sejanus over 9 years
    Is there a way to achieve this without using the abomination that is php annotations?
  • Dennis
    Dennis over 8 years
    @Sejanus, yes, Doctrine has XML, YAML, and PHP annotations. See "Drivers" under docs.doctrine-project.org/projects/doctrine-orm/en/latest
  • Dennis
    Dennis over 8 years
    From the docs: "It should be noted that this event is only triggered on initial persist of an entity (i.e. it does not trigger on future updates)"
  • Thomas Landauer
    Thomas Landauer over 8 years
    Where (i.e. in which file) is this code to be placed (in Symfony)? Thanks!
  • Alexandre
    Alexandre over 8 years
    @ThomasLandauer I did it durty and had it directely in the file where I need to use it... But would be better to create a bundle in the vendor folder or something like this.
  • Thomas Landauer
    Thomas Landauer about 8 years
    This answer is the only solution so far which uses the database server's time (rather than PHP's time). Here's why this is a good thing: stackoverflow.com/a/3705090/1668200
  • David Baucum
    David Baucum about 8 years
    I think it is worth noting that both this solution and mine below are good solutions. There is an important distinction in how that work. In my solution the timestamp is created when the entity is first instantiated. In this solution the timestamp is set at the time it is persisted to the database.
  • David Baucum
    David Baucum about 8 years
    I think it is worth noting that both this solution and @PhillPafford's above are good solutions. There is an important distinction in how that work. In my solution the timestamp is created when the entity is first instantiated. In this solution the timestamp is set at the time it is persisted to the database.
  • Dariux
    Dariux almost 8 years
    How is this working for you? I get error: Error: Call to a member function format() on string which makes sense, because 'CURRENT_TIMESTAMP' is string :/
  • Dennis
    Dennis almost 8 years
    hah, I get the same error! (I've been using this to read data only)
  • Dariux
    Dariux almost 8 years
    I used this in doStuffOnPrePersist() function
  • emix
    emix over 7 years
    "Don`t use magic hooks inside your entities" Marco Pivetta, author of the Doctrine
  • Dennis
    Dennis over 7 years
    Don't use it,... but if you must we program the PrePersist into Doctrine?:)
  • Erce
    Erce almost 5 years
    This will work but the update will be done by doctrine in symfony layer. If you think that update should be done by db layer, than you need to find how to set on update CURRENT_TIMESTAMP. If you find also inform me as well :)