Save and get Date format in symfony2 via ORM - php

According to this http://symfony.com/doc/2.8/reference/forms/types/date.html#format I created this form type:
->add('warranty', DateType::class, array(
'widget' => 'single_text',
'format' => 'yyyy-MM-dd')
)
Here what i have in my entity
/**
* #ORM\Column(
* type="date"
* )
*
* #JMS\Groups("list")
* #Assert\NotBlank()
*
* #var \DateTime
*/
protected $warranty;
And I'm trying to save date like this 2012-12-12.
And this works fine, bun when I tried to get back data from DB i got this
2012-12-12T00:00:00+0200
I need work only with date, not datetime, can some one help me?

Doctrine maps date sql fields to an instance of \DateTime class which always has time stored (set to zero).
You can consider using the date twig filter:
http://twig.sensiolabs.org/doc/filters/date.html
Or if you have localised pages, the localised date filter using the intl extension:
http://twig.sensiolabs.org/doc/extensions/intl.html

Related

Symfony validation

I'm working in a bundle where the user creates a "comision" using a form, and I'm trying to check that the user still have "credit". So I created a custom validator that queries past comisions and throws an error if credit is not enough.
My problem is that if the user submits a date with a wrong format in the "date" field (i.e. 32-13-20122 24:05) Symfony still tries to run my custom validation and I get all sort of errors (because $comision->getDate() is null and not a valid DateTime object).
I'm getting this error:
clone method called on non-object
I can also check if value of $comision->getDate() is a valid datetime in my custom validator, but it seems to me that it should be not necessary since I added this rules in the date property.
This is my entity (simplified)
/**
* #MyValidation\TotalHours()
*/
class Comision
{
/**
* #ORM\Column(type="datetime")
* #Assert\DateTime()
* #Assert\NotNull()
*/
protected $date;
/**
* #ORM\Column(type="decimal", nullable=false, scale=1)
* #Assert\NotBlank()
*/
protected $hours;
...
My form class ...
class NewComisionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('date', DateTimeType::class, array(
'widget' => 'single_text',
'label' => 'Starting date and time',
'format' => 'dd/MM/yyyy HH:mm'
))
->add('hours', ChoiceType::class, array(
'label'=> 'How many hours',
'choices' => array(
'1:00' => 1,
'1:30' => 1.5,
'2:00' => 2,
'2:30' => 2.5,
'3:00' => 3
)
))
...
And my cutom validator that checks past comisions to find if user still has "credit"
public function validate($comision, Constraint $constraint)
{
$from = clone $comision->getDate();
$from->modify('first day of this month');
$to = clone $comision->getDate();
$to->modify('last day of this month');
$credit = $this->em->getRepository("ComisionsBundle:Comision")->comisionsByDate($comision,$from, $to);
...
One way would be to group your constraints as described in the docs.
This way your can define two groups of contraints whereas the second group will be validated only if all constraints in the first group are valid.
Regarding your use case, you could put your custom constraint in a different group than the default one to be sure your have a proper $comision DateTime object.
To do this, you can use the GroupSequence feature. In this case, an object defines a group sequence, which determines the order groups should be validated.
https://symfony.com/doc/current/validation/sequence_provider.html
The solution should look like this:
/**
* #MyValidation\TotalHours(groups={"Strict"})
* #Assert\GroupSequence({"Comision", "Strict"})
*/
class Comision
In this way, it will first validate all constraints in the group Comision (which is the same as the Default group). Only if all constraints in that group are valid, the second group, Strict, will be validated, making sure $comision->getDate() will have a DateTime instance.
IIRC data transformers run before validation, you can go with data transformer for your date:
https://symfony.com/doc/current/form/data_transformers.html
and then in data transformer check if the date is valid and if not throw an error.

Symfony Sonata - How to show minutes format for datetime in listMapper?

I'm usinf Symfony 3.2.9 with Sonata-admin bundle.
I've create this field in my Entity component:
/**
* #var \DateTime $verificat
*
* #ORM\Column(type="datetime", nullable=true)
*/
private $verificat;
In his admin class there is this function:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->add('verificat','datetime',array('label' => 'Data verificació','format' => 'd/M/Y H:mm'));
}
My problem is that it transforms the date like 2017/Jun/12 13:0606. Where I want to show minutes it shows the month number in the year.
I'd like to know how to show minuts, and even better, how to build any pattern format.
Try looking what the format literals actually mean and how the date_format function works:
http://php.net/manual/en/function.date.php
m stands for month while i stands for minutes.
Try
'd/m/Y H:i'

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

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();
}
}

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!

How to use birthday field in symfony2 forms

Symfony Docs say that we can use birthday date in forms. but they have not given any example how to use that
Can anyone please tell me where do I need to write birthday in doctrine entity?
The Birthday is the form_widget.
ex. in controller:
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('yearOfBirth', 'birthday')
->getForm();
This widget can be mapped to DateTime field
/**
* #var date $yearOfBirth
*
* #ORM\Column(name="year_of_birth", type="datetime")
* #Assert\DateTime()
*/
private $yearOfBirth;
Here you got reference to docs about this field:
http://symfony.com/doc/current/reference/forms/types/birthday.html
Regards,
Max
$builder->add('dateOfBirth', 'birthday');
You have plenties of example on the internet:
How to display months in full text for Date fields in Symfony2?
http://j-place.developpez.com/tutoriels/php/creer-premiere-application-web-avec-symfony2/#LX-A

Categories