Symfony2 Datetime TransformationFailed Exception - php

i'm stuck in error when try to generate CRUD in symfony2 I always get the following exception:
"Unable to transform value for property path "xxx": Expected a \DateTime or \DateTimeInterface."
it always happened with the any datetime field here is excerpt of my entity field:
/**
* #var \DateTime
*
* #ORM\Column(name="date_added", type="datetime", nullable=false)
*/
private $dateAdded = '0000-00-00 00:00:00';
/**
* Set dateAdded
*
* #param \DateTime $dateAdded
*
* #return User
*/
public function setDateAdded()
{
$this->dateAdded = new \DateTime();
return $this;
}
/**
* Get dateAdded
*
* #return \DateTime
*/
public function getDateAdded()
{
return $this->dateAdded;
}
-Also i tried to use easyadmin bundle which generate backend from entities using symfony2 CRUD on the fly but also get the same error so is there something wrong with my entity ?

Maybe removing the annotation #param \DateTime $dateAdded as your function setDateAdded() has no parameter ?

The $dateAdded field cannot contain a string. It needs to have a DateTime object, because that's whats expected. In other words you need to have a constructor which sets the date:
/**
* #var \DateTime
*
* #ORM\Column(name="date_added", type="datetime", nullable=false)
*/
private $dateAdded;
public function __construct() {
$this->dateAdded = new \DateTime();
}
Also, you need to accept a parameter on your setDate method:
public function setDate($date) {
$this->dateAdded = $date;
}
As a side note, keep in mind you will need to use a date filter if you'll be displaying the date in a twig template:
{{ entity.dateAdded|date('d.m.Y') }}

Related

Symfony - set entity field as timestamp

In my Symofny project I want for my entity to have timestamp field.
/**
* #ORM\Column(type="datetime", nullable=false)
*/
private $timestamp;
/**
* #ORM\PreUpdate
* #throws \Exception
*/
public function setTimestamp()
{
$this->timestamp = new DateTime("now");
return $this;
}
I want to be saved in timestamp format? How can I accomplish that?
Like // => 1387909800
I am on Symfony 4.3 version.
Try getTimestamp();
/**
* #ORM\Column(type="datetime", nullable=false)
*/
private $timestamp;
/**
* #ORM\PreUpdate
* #throws \Exception
*/
public function setTimestamp()
{
$date = new \DateTime();
$this->timestamp = $date->getTimestamp();
return $this;
}

Phpunit partial mock + proxy Entity

I tried find solution to my issue but didn't find anything.
I use: Symfony, Doctrine, PhpUnit
I have one entity class InvoiceNumerator:
/**
* InvoiceNumerator
*
* #ORM\Table(name="invoice_numerator")
* #ORM\Entity(repositoryClass="AppBundle\Repository\InvoiceNumeratorRepository")
*/
class InvoiceNumerator
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="translatedFormat", type="string", length=64)
*/
private $translatedFormat;
/**
* #var int
*
* #ORM\Column(name="currentValue", type="integer", options={"default": 0})
*/
private $currentValue = 0;
/**
* #var string
*
* #ORM\Column(name="current_number", type="string", length=64)
*/
private $currentNumber = '';
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set translatedFormat
*
* #param string $translatedFormat
*
* #return InvoiceNumerator
*/
public function setTranslatedFormat($translatedFormat)
{
$this->translatedFormat = $translatedFormat;
return $this;
}
/**
* Get translatedFormat
*
* #return string
*/
public function getTranslatedFormat()
{
return $this->translatedFormat;
}
/**
* Set currentValue
*
* #param integer $currentValue
*
* #return InvoiceNumerator
*/
public function setCurrentValue($currentValue)
{
$this->currentValue = $currentValue;
return $this;
}
/**
* Get currentValue
*
* #return int
*/
public function getCurrentValue()
{
return $this->currentValue;
}
/**
* #return string
*/
public function getCurrentNumber(): string
{
return $this->currentNumber;
}
/**
* #param string $currentNumber
* #return InvoiceNumerator
*/
public function setCurrentNumber(string $currentNumber): InvoiceNumerator
{
$this->currentNumber = $currentNumber;
return $this;
}
}
and I need in my tests to mock this class, but my setters should be left the same - no stubs - working code.
To mock this class, I made simple mock method:
public function getInvoiceNumerator()
{
$invoiceNumerator = $this->createMock(InvoiceNumerator::class);
$invoiceNumerator->method('getTranslatedFormat')
->willReturn('FS-CM/{n}/2018/01');
$invoiceNumerator->method('getCurrentValue')
->willReturn('1');
$invoiceNumerator->method('getCurrentNumber')
->willReturn('FS-CM/1/2018/01');
return $invoiceNumerator;
}
but in this case my setters are not working.
I can also set values on new Entity object:
public function getInvoiceNumerator()
{
$invoiceNumerator = new InvoiceNumerator();
$invoiceNumerator->setTranslatedFormat('FS-CM/{n}/2018/01');
$invoiceNumerator->setCurrentValue(1);
$invoiceNumerator->setCurrentNumber('FS-CM/1/2018/01');
return $invoiceNumerator;
}
In this case my setters working properly.
Question:
Is there any better way to do this? What is the best practice?
You almost have the answer in your question “Phpunit partial mock + proxy Entity”: there is a createPartialMock() method which you can use like this:
$invoiceNumerator = $this-> createPartialMock(
InvoiceNumerator::class,
['nameOfMockedMethod1', 'nameOfMockedMethod2']
);
This method has been available in PHPUnit 5.5 and newer. If you are using an older version, you can use setMethods(), but have to call it on the result returned by getMockBuilder(), not on the object returned by createMock() (which is the reason of the error you got after trying the approach from the 1st answer):
$subject = $this->getMockBuilder(MyClass::class)
->setMethods(['method1', 'method2'])
->getMock();
However, please note that createPartialMock() does slightly more. For instance, it will automatically disable the original constructor – which is almost always what you want in your tests (and what you have to do explicitly when using setMethods()). See documentation for exact information.
Basically you can set your mock to only mock specific methods:
$invoiceNumerator = $this->getMockBuilder(InvoiceNumerator::class)
->setMethods(["getTranslatedFormat","getCurrentValue", "getCurrentNumber"])
->getMock();
according to the documentation
setMethods(array $methods) can be called on the Mock Builder object to specify the methods that are to be replaced with a configurable test double. The behavior of the other methods is not changed. If you call setMethods(null), then no methods will be replaced.
Update:
Since PHPUnit 8 the setMethods function has been deprecated and replaced with onlyMethods for methods that exist on the mocked class and addMethods for methods that don't yet exist on the mock class (e.g. they will be implemented in the future but you want to text their dependencies assuming they already exist).

Cannot Change String To Date Formate in Symfony 2.7

OK, tried to debug this problem for a few days and now i give up.
I have the followig form builder
Builder
->add('passDate', 'hidden', array('data'=>null, 'empty_data'=> date('Y-m-d',strtotime('1950-10-10'))))
->add('TDVLFirstIssue', 'hidden', array('data'=>null, 'empty_data'=> date('Y-m-d',strtotime('1950-10-10'))))
->add('TDVLExpiryDate', 'hidden', array('data'=>null, 'empty_data'=> date('Y-m-d',strtotime('2017-10-10'))));
and this is my entity
/**
* #var \DateTime
*
* #ORM\Column(name="passDate", type="date")
* #Assert\NotBlank()
*/
private $passDate;
/**
* #var \DateTime
*
* #ORM\Column(name="tdvlIssue", type="date")
* #Assert\NotBlank()
*/
private $TDVLFirstIssue;
/**
* #var \DateTime
*
* #Assert\GreaterThan(value = "+1 day midnight", message="Your TDVL require at least 1 month validity.")
* #ORM\Column(name="tdvlExpiry", type="date")
* #Assert\NotBlank()
*/
private $TDVLExpiryDate;
public function setPassDate($passDate)
{
$this->passDate = $passDate;
return $this;
}
/**
* Get passDate
*
* #return \DateTime
*/
public function getPassDate()
{
return $this->passDate;
}
public function setTDVLFirstIssue($tDVLFirstIssue)
{
$this->TDVLFirstIssue = $tDVLFirstIssue;
return $this;
}
/**
* Get tDVLFirstIssue
*
* #return \DateTime
*/
public function getTDVLFirstIssue()
{
return $this->TDVLFirstIssue;
}
**
* Set tDVLExpiryDate
*
* #param \DateTime $tDVLExpiryDate
*
* #return User
*/
public function setTDVLExpiryDate($tDVLExpiryDate)
{
$this->TDVLExpiryDate = $tDVLExpiryDate;
return $this;
}
/**
* Get tDVLExpiryDate
*
* #return \DateTime
*/
public function getTDVLExpiryDate()
{
return $this->TDVLExpiryDate;
}
And here is my controller
$entity = new User();
$form = $this->createSystemUserForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity->setTDVLFirstIssue(date('Y-m-d',strtotime('1950-10-10')));
$entity->setTDVLExpiryDate(date('Y-m-d',strtotime('2018-10-10')));
$entity->setPassDate(date('Y-m-d',strtotime('1950-10-10')));
}
What i am trying to do is i want to pass default date to the database. so i tried with vanilla php format converting function data and format . But when i submit the form, it throw me this error which is
Error: Call to a member function format() on string
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return ($value !== null)
? $value->format($platform->getDateFormatString()) : null;
}
. I understood that $passDate, $TDVLFirstIssue and $TDVLExpiryDate cannot be blank , which defined in entity as NotBlank(). I suspect that it is because of unsuccessful string to date conversion. So can help me about this problem? thanks in advance.
Note: Please take note that i am using symfony 2.7.
I change my builder date as follow and it works.
builder
->add('passDate', 'hidden', array('data'=>null, 'empty_data'=> date_create('1950-10-10')))
->add('TDVLFirstIssue', 'hidden', array('data'=>null, 'empty_data'=> date_create('1950-10-10')))
->add('TDVLExpiryDate', 'hidden', array('data'=>null, 'empty_data'=> date_create('2017-10-10')));
Hope it helps.

Doctrine get full entity after a partial query

I am working on a system that is build using Zend Framework 2 and Doctrine 2.
In this system I am working on the contracts part where I want a list with some data (a partial query) from all contracts and I need to fill in a form with all data (entity find) from a specific contract.
However, since the contract to be filled in the form is also a result of the partial query, the properties that had not been loaded in the PARTIAL query will not be loaded for the queried entity either.
I have simplified the data to show only the current issue, the real entity has more fields:
Entity:
use Doctrine\ORM\Mapping as ORM;
/**
* ContractSub
*
* #ORM\Table(name="contract_sub", indexes={#ORM\Index(name="contract_id", columns={"contract_id"}), #ORM\Index(name="list_pension_start", columns={"list_pension_start_id"}), #ORM\Index(name="list_lease_car_category", columns={"list_lease_car_category_id"}), #ORM\Index(name="created_by_id", columns={"created_by_id"})})
* #ORM\Entity(repositoryClass="Application\Repository\ContractSubRepository")
* #ORM\HasLifecycleCallbacks
*/
class ContractSub
{
/**
*
* #var integer #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
*
* #var \DateTime #ORM\Column(name="start_date", type="date", nullable=false)
*/
private $startDate;
/**
*
* #var \DateTime #ORM\Column(name="end_date", type="date", nullable=true)
*/
private $endDate;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set startDate
*
* #param \DateTime $startDate
*
* #return ContractSub
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate
*
* #return \DateTime
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Set endDate
*
* #param \DateTime $endDate
*
* #return ContractSub
*/
public function setEndDate($endDate)
{
$this->endDate = $endDate;
return $this;
}
/**
* Get endDate
*
* #return \DateTime
*/
public function getEndDate()
{
return $this->endDate;
}
}
Repository:
use Doctrine\ORM\EntityRepository;
class ContractSubRepository extends EntityRepository
{
public function getPartialStuffForTest()
{
$oQuery = $this->_em->createQuery('SELECT PARTIAL ContractSub.{id, startDate}
FROM Application\Entity\ContractSub ContractSub');
return $oQuery->getResult();
}
}
Controller:
use Zend\Mvc\Controller\AbstractActionController;
class ContractController extends AbstractActionController
{
public function testAction()
{
$oEntityManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$aContracts = $oEntityManager->getRepository('Application\Entity\ContractSub')->getPartialStuffForTest();
$oContractSub = $oEntityManager->getRepository('Application\Entity\ContractSub')->find(38);
var_dump($oContractSub->getStartDate());
var_dump($oContractSub->getEndDate());
die();
}
}
This outputs:
object(DateTime)[479]
public 'date' => string '2015-06-01 00:00:00.000000' (length=26)
public 'timezone_type' => int 3
public 'timezone' => string 'Europe/Amsterdam' (length=16)
null
Indicating that the endDate is not loaded, even though I do a find to retrieve the complete entity.
When I comment the line that executes the getPartialStuffForTest(), I do get the endDate as well.
So I was wondering if there is any way to force Doctrine to retrieve the full entity after it already has a cached version of the partial entity?
To fully load a partial you have to use $entityManager->refresh($object).
Your answer is in the first paragraph in the Doctrine2 documentation chapter 18. Partial objects.
Use of partial objects is tricky. Fields that are not retrieved from the database will not be updated by the UnitOfWork even if they get changed in your objects. You can only promote a partial object to a fully-loaded object by calling EntityManager#refresh() or a DQL query with the refresh flag.

Symfony + Doctrine 2.2 DateTime column error

I'm having a hard time sorting this issue out. I'm getting the following error while trying to persist an entity (see source below):
Fatal error: Call to a member function format() on a non-object
in *****\vendor\doctrine-dbal\lib\Doctrine\DBAL\Types\DateTimeTzType.php
on line 64
Here's a snippet of the entity's code:
namespace ****\Bundle\****Bundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* ****\Bundle\****Bundle\Entity\MyEntity
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="****\Bundle\****Bundle\Entity\****Repository")
* #ORM\HasLifecycleCallbacks()
*/
class MyEntity
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime $created_at
*
* #ORM\Column(name="created_at", type="datetime")
*/
private $created_at;
/**
* #var \DateTime $updated_at
*
* #ORM\Column(name="updated_at", type="datetime", nullable="true")
*/
private $updated_at;
/**
* Set created_at
*
* #param datetime $createdAt
*/
public function setCreatedAt($createdAt)
{
$this->created_at = $createdAt;
}
/**
* Get created_at
*
* #return datetime
*/
public function getCreatedAt()
{
return $this->created_at;
}
/**
* Set updated_at
*
* #param datetime $updatedAt
*/
public function setUpdatedAt($updatedAt)
{
$this->updated_at = $updatedAt;
}
/**
* Get updated_at
*
* #return datetime
*/
public function getUpdatedAt()
{
return $this->updated_at;
}
/**
* #ORM\PrePersist()
*/
public function executePrePersist()
{
$this->created_at = new \DateTime();
}
/**
* #ORM\PreUpdate()
*/
public function executePreUpdate()
{
$this->updated_at = new \DateTime();
}
}
Before posting here, I've added:
print_r(get_class($value))
to DateTimeTzType.php at the offending place to know which kind of data it received, and I got the following error:
Warning: get_class() expects parameter 1 to be object, string given
So it seems that it is receiving a string instead of a DateTime object, and then fails because string doesn't have a format() method.
I'm using Symfony 2.0.9. Am I missing something?
Seems like your setCreatedAt() and getCreatedAt() do not specify they require DateTime as a type, which Doctrine expects.
You can either make sure you create a DateTime object when calling those functions or modify the methods to check if a string was provided as the input and create the object when needed. Just sending the string representation of the date as the first argument to the DateTime constructor usually works.
It was my error. I had another field with DateTime type elsewhere in my entitiy and I was passing a string to it before persisting. I was convinced it was the createdAt field. Thanks xdebug and sorry for the post.

Categories