Reputation: 85328
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?
Upvotes: 17
Views: 38865
Reputation: 986
My approach was to let the database set that datetime field configured as CURRENT_TIMESTAMP()
. The reason to not use Doctrine's PrePersist
or calling the corresponding setter manually in PHP was that our database (and I mean data) was shared with other microservices. These microservices didn't even use Doctrine, actually these were not even PHP projects, so we wanted to move the responsibility of setting datetimes to the database, centralized, in one place.
But as the author pointed out, yes, there was a problem of Doctrine passing a null
value as datetime upon flushing a persisted entity, to the DB, which gave the following error:
Integrity constraint violation: 1048 Column 'createdAt' cannot be null
And the fix for that was to set insertable: false
(which by default is true
), thus preventing Doctrine from passing that null
value inside queries,
#[ORM\Column(
name: "createdAt",
type: "datetime",
nullable: false,
insertable: false,
options: ["default" => "CURRENT_TIMESTAMP"]
)]
private \DateTime $createdAt;
Upvotes: 0
Reputation:
#[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;
this is what I found out and I was able to get the "ON UPDATE CURRENT_TIMESTAMP()" however the column becomes nullable which is a better tradeoff in my opinion.
Upvotes: 3
Reputation: 1342
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;
Upvotes: 1
Reputation: 8111
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');
}
Upvotes: 3
Reputation: 3170
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.
Upvotes: 7
Reputation: 85328
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');
}
Upvotes: 28
Reputation: 2250
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();
}
}
Upvotes: 9
Reputation: 71384
For PostgreSQL, you should just be able to pass string value of now
for the field to get the timestamp to function.
Upvotes: 0