How to map MySQL column "timestamp" to a field with Doctrine2 - php

I created a Doctrine2 Entity and would like to map a field to timestamp column in MySQL.
/**
* #ORM\Table(name="biz_order")
* #ORM\Entity(repositoryClass="Acme\OrderBundle\Repository\OrderRepository")
*/
class Order
{
/**
* #ORM\Column(name="order_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
// Lots of other fields ...
/**
* #ORM\Column(name="order_timestamp", type="datetime")
*/
private $createdOn;
}
With annotated type as "datetime" I get following error:
Doctrine\DBAL\Types\ConversionException: Could not convert database value "1390362851" to Doctrine Type datetime. Expected format: Y-m-d H:i:s
at n/a
in /var/www/packer/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ConversionException.php line 63
at Doctrine\DBAL\Types\ConversionException::conversionFailedFormat('1390362851', 'datetime', 'Y-m-d H:i:s')
in /var/www/packer/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/DateTimeType.php line 67
However in Doctrine 2.4 documentation I found following
datetime: Type that maps a SQL DATETIME/TIMESTAMP to a PHP DateTime object.
How can I map timestamp DB column to a PHP class field in Doctrine2?
EDIT:
So far my workaround is using the type="integer" in ORM mapping and returning it as ValueObject
public function getCreatedOn()
{
$createdOn = new \DateTime();
$createdOn->setTimestamp($this->createdOn);
return $createdOn;
}

You can just create a custom doctrine type defined timestamp, see the documentation

You can look at This post: datetime vs timestamp
Since it is a createdAt property, and represents a point in time, you might want to fetch objects that have been created before $createdAt or after $createdAt.
To do that, your best option is to store the datetime exactly the way you've done it but to associate a \Datetime object to that field: $this->createdAt = new \Datetime();
The best way for you would be to use lifecycle callbacks:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="biz_order")
* #ORM\Entity(repositoryClass="Acme\OrderBundle\Repository\OrderRepository")
* #ORM\HasLifecycleCallbacks
*/
class Order
{
/**
* #ORM\Column(name="order_timestamp", type="datetime")
*/
private $createdAt;
/**
* #ORM\PrePersist
*/
public function doStuffOnPrePersist()
{
$this->createdAt= new \DateTime();
}
}

Related

Symfony – “Object of class DateTime could not be converted to string” persisting entity

I’m trying to persist an entity with doctrine, the entity has a date attribute and this, apparently, is generating the error.
This is how the attribute is declared in the entity:
/**
* #var date
*
* #ORM\Column(name="fecha", type="date")
* #ORM\Id
*/
private $fecha;
And this is how I create the Entity at controller and the code to persist it with doctrine:
$estadistica = new EstadisticaTerceros();
$fecha = date_create_from_format('Y-m-d', '2017-05-04');
$estadistica->setFecha($fecha);
//Set other attributes
$em = $this->getDoctrine()->getManager();
$em->persist($estadistica);
$em = $this->getDoctrine()->getManager();
$em->flush();
In the table the attribute is date type.
And this is the error screen:
Any idea?
I am assuming that your fecha column is not the primary key of the table. So you can drop the #ORM\Id annotation from that column:
/**
* #var \DateTime
*
* #ORM\Column(name="fecha", type="date")
*/
private $fecha;
date_create_from_format is also an alias for DateTime::createFromFormat and I'd recommend using that just so it's a little more explicit that you are creating a \DateTime:
$fecha = \DateTime::createFromFormat('Y-m-d', '2017-05-04');
If $estadistica->setFecha is expecting a string, just pass it the ISO 8601 date string '2017-05-04' directly instead of converting it to a DateTime instance.
Here you have answer for similiar question:
doctrine DateTime could not be converted to string
You should pass the string into Your entity. With DateTime class instance You could do it as follows:
$estadistica->setFecha($fecha->format('Y-m-d'));

date_add gets Boolean instead of DateTime

I have a very strange error in my Symfony app and I don't know how to fix it. I want to set a DateTime in one of my entities with a DateTime after adding a special DateInterval. Here is my code:
$dateInterval = new \DateInterval('P1DT6H');
$snoozedTo = date_add($sickNote->getSickTo(), $dateInterval);
$channelUser->setSnoozedTo($snoozedTo);
$this->em->persist($channelUser);
In my UnitTests I get the following error:
date_add() expects parameter 1 to be DateTime, boolean given
So I double check if $sickNote->getSickTo() really returns a DateTime. A dump() returns:
DateTime {#17791
+"date": "2018-01-01 06:00:00.000000"
+"timezone_type": 3
+"timezone": "UTC"
}
get_class() on the object returns DateTime.
Here is additional my getter method for the field:
/**
* Get sickTo
* #return Date
*/
public function getSickTo() {
return $this->sickTo;
}
Why date_add gets a Boolean and not the DateTime object?
Edit: I also tried the objet method DateTime::add(). Same result.
Edit²: Here is my declaration of sickTo:
/**
* #var datetime $sickTo
* #ORM\Column(type="date", nullable=true)
* #Assert\Date()
*/
protected $sickTo;
The declaration of sickTo is wrong. you declare it as a Date but you use a Datetime. Try to change that with something like that :
/**
* #var \DateTime $sickTo
* #ORM\Column(type="datetime", nullable=true)
* #Assert\DateTime()
*/
protected $sickTo;

No default option is configured for constraint Symfony\Component\Validator\Constraints\Time

I am trying to set time property of type Time to Doctrine entity Availability
class Availability{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="start_time", type="time", nullable=true)
* #Assert\Time(message = "wrong time format")
*/
private $startTime;
/**
* #ORM\Column(name="end_time", type="time", nullable=true)
* #Assert\Time(message = "wrong time format")
*/
private $endTime;
}
In controller I am setting time by creating Time object:
use Symfony\Component\Validator\Constraints\Time;
/////
$availability = new Availability();
$availability->setStartTime(new Time('18:00:00'));
$availability->setEndTime(new Time('21:00:00'));
I have this error
No default option is configured for constraint
Symfony\Component\Validator\Constraints\Time (500 Internal Server
Error)
The 'auto-adding' you mentionned in comments is sometimes misleading and put you in bad situations specially when you are just starting to learn something.
startTime and endTime are of type time , Doctrine defines the time field as follows :
time: Type that maps a SQL TIME to a PHP DateTime object.
So you need to pass a DateTime object to your setters and not a Time constraint.
Something like this may work for you :
$availability = new Availability();
$availability->setStartTime(new \DateTime('now'));
$availability->setEndTime(new \DateTime('another date')); // <- change another date

Symfony Doctrine2: How do I work with limited one-to-many relation?

I have an Entity Employee
class Employee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="WorkHour", mappedBy="employee", cascade={"persist", "remove"})
*/
private $workHours;
}
and WorkHour
class WorkHour
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Profile
*
* #ORM\ManyToOne(targetEntity="Employee", inversedBy="workHours")
* #ORM\JoinColumn(name="employee_id", referencedColumnName="id")
*/
protected $profile;
/**
* #var integer
*
* #ORM\Column(name="weekday", type="smallint")
*/
private $weekday;
/**
* #var \DateTime
*
* #ORM\Column(name="hour_from", type="time")
*/
private $hourFrom;
/**
* #var \DateTime
*
* #ORM\Column(name="hour_to", type="time")
*/
private $hourTo;
}
Now I'm confused when I'm going to add addWorkHour(), removeWorkHour() methods.
Usually one-to-many relation you can add as many relations as you want, but in my case, one employee can have only up-to-7 workHours, and for a specified weekday (from 0 to 6) can have only one (or no) record.
So I think what I need is something methods like,
public function setWorkHourByWeekday($hour_from, $hour_to, $weekday);
public function getWorkHourByWeekday($weekday);
And after set workhours for an employee, when you persist that employee,
I want doctrine delete those workhours that are no longer exist, update those workhours that are changed, and create new workhours that not exist before.
How can I implement this? Should I write these logic in class Employee or its Repository, or a WorkHourManager class?
I think WorkDay is a probably better name for your entity, so i'll use that :).
$workdays= $employee->getWorkDays();
$workdays->clear(); // Clear existing workdays
// Add new workdays
foreach(...) {
$workday = new WorkDay();
$workday ->setWeekday(0); // You could use a constant like `WorkDay::MONDAY`
$workday ->setStart('09:00');
$workday ->setEnd('17:00');
$workdays->add($workday);
}
Set orphanRemoval=true on $workHours to remove WorkHours without an Employee.
The setWeekday method in your Workday entity should throw an exception when an invalid weekday is supplied (other than 0-6). You could also use a Weekday value object in combination with Doctrine embeddables.
I'd go for a service or manager class in this case.
My advice is not to drop old workhours, maybe you don't needed now, but this data could be useful in the future. So, will be better just add workHours to the Employee and make a report the get the last workHours for today. About validations, there is a lot of ways of doing that. If you are working with forms and the rules are complex maybe you need read http://symfony.com/doc/current/cookbook/validation/custom_constraint.html , but maybe you can find alternatives in the action controller or the entity class itself.

Symfony2/Doctrine2 - Issue when getting datetime from database

As I was working on my Symfony2 project a strange bug savagely appeared (again).
I created an entity Check containing a dateCreated attribute and some others attributes so I can link Check to different entities that are extending a ProductBase. Here are samples of Check and a AProduct :
/**
* Check
*
* #ORM\Table(name="check")
* #ORM\Entity
*/
class Check
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="date_created", type="datetime")
*/
private $dateCreated;
[...]
/**
* #ORM\ManyToOne(targetEntity="Acme\BlogBundle\Entity\AProduct", inversedBy="checks")
* #ORM\JoinColumn(name="aproduct_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $aproduct;
[...]
}
/**
* AProduct
*
* #ORM\Table(name="aproduct")
* #ORM\Entity
*/
class AProduct extends ProductBase
{
[...]
/**
* #ORM\OneToMany(targetEntity="Acme\BlogBundle\Entity\Check", mappedBy="product")
* #ORM\OrderBy({"dateCreated" = "DESC"})
*/
protected $checks;
[...]
}
So my problem is that when I am trying to display the dateCreated attribute in one of my controller, see code below, Symfony2 (or Doctrine2) is adding exactly one month to the date stored in the database and I don't know why it's happening :
[...]
$aproduct = $aproducts[0];
$checks = $aproduct->getChecks();
$lastCheck = $checks->toArray()[0]; //I know it's not 'safe' but it's shorter to expose my problem
var_dump($lastCheck->getDateCreated());
Result :
object(DateTime)[854]
public 'date' => string '2014-01-20 16:21:41' (length=19)
public 'timezone_type' => int 3
public 'timezone' => string 'UTC' (length=3)
Value stored in database :
2013-12-20 16:21:41
What I don't understand the most is that in another controller, with the exact same methods but on a different product (BProduct for instance), I get the correct date...
Has anyone already faced to this problem or have any clue of what to do to solve it?
Thank you again. If you need more information just ask and I will try to help as most as I can.
Edit : The others aproduct stored in aproducts are displaying the correct date...
I see you are using:
#ORM\OrderBy({"dateCreated" = "DESC"})
Might be silly but check the id of returned Check instance.
Well I finally found my problem and my post here was really silly and completely unrelated to Symfony or Doctrine, sorry about that.
I was performing some "tests" on the last instance of my aproduct checks before displaying them and those "tests" were affecting the dateCreated value.
Here is what I was doing :
public static function updateAProductStatus(AProduct $product){
if(($check = $product->getChecks()->first()) instanceof Check){
$date = $check->getDateCreated();
$expiracyDate = $date->add(new \DateInterval('P1M')); //this line is the problem
$status = self::getStatus($expiracyDate); //this is only returning 'expired', 'expiring' or 'good' based on the difference between today's date and dateCreated + 1 month
} else {
$status = 'expired';
}
return $status;
}
So, as written in the code, $date->add(new \DateInterval('P1M')); is changing the stored value of Checks's dateCreated attribute. I don't understand exactly why it's affecting it because I'm not working directly on the Check instance.
The quick way to solve it was to explicitly clone the DateTime instance before adding a DateInterval :
$date = clone $date;
But I will add a new field in my Check or AProduct entity to store the expiracy date instead of calculating it on every update.
Update:
I read that PHP passes objects and arrays as reference and not as value. That's why I was having a problem here. I didn't know PHP was acting like that. I will be more careful in the future then!

Categories