我是Doctrine ORM(v2.5.5)和Silex(v2.0.4)/ Symfony(v3.1.6)的初学者。我需要将日期字段输出为 YYYY-MM-DD 格式。让我们说我在我的实体上有这个注释和getter方法:
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* @ORM\Column(type="date")
*/
protected $expire;
// getter
public function getExpire()
{
return !is_object($this->expire) ? new \DateTime() : $this->expire->format('Y-m-d');
}
这是我的简化控制器,用于调试目的:
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$normalizer = new \Symfony\Component\Serializer\Normalizer\ObjectNormalizer();
$encoder = new \Symfony\Component\Serializer\Encoder\JsonEncoder();
$normalizer->setCircularReferenceHandler(function($obj){
return $obj->getId();
});
$serializer = new \Symfony\Component\Serializer\Serializer(array($normalizer), array($encoder));
$qb = $tnkbRepo->createQueryBuilder('c')
->setMaxResults(1);
//$query = $qb->getQuery(); // [1] <<-- this line produce proper YYYY-MM-DD format
//$query = $qb->select('c.expire')->getQuery(); // [2] <<-- this (manual select) line produce DateTime object.
$results = $query->getResult();
return $serializer->serialize($results, 'json');
});
在第一个 [1] 行取消注释后,我得到了我想要的正确输出:
[more json output here]...,"expire":"1970-10-25",...
但是第二个 [2] 行没有注释(我打算省略其他测试字段),我得到了以下输出,这不是我的预期:
[{"expire":{"timezone":{"name":"UTC","location":{"country_code":"??","latitude":0,"longitude":0,"comments":""}},"offset":0,"timestamp":25660800}}]
我也注意到,使用 [2] 行,Doctrine似乎忽略了我的实体的getter方法(我尝试返回空字符串)。我希望输出与 [1] 情况相同,这让我很好奇。我的问题是:
谢谢。
更简化的 / debug 控制器用于测试(无序列化):
$app->get('/debug', function() use ($app) {
$tnkbRepo = $app['orm.em']->getRepository('\App\Entity\Tnkb');
$qb = $tnkbRepo->createQueryBuilder('c');
// [1a] normal query. doesn't return Entity, getExpire() isn't called.
/*$query = $qb->select('c.expire')
->setMaxResults(1)->getQuery();*/
// [2a] partial query. returns Entity, getExpire() called.
/*$query = $qb->select('partial c.{id,expire}')
->setMaxResults(1)->getQuery();*/
$results = $query->getResult();
var_dump($results);die;
});
更新了实体方法getExpire():
// src/App/Entity/Tnkb.php (simplified)
// 'expire' field
/**
* @ORM\Column(type="date")
*/
protected $expire;
protected $dateAsString = true;
protected $dateFormat = 'Y-m-d';
// getter
public function getExpire()
{
return ($this->expire instanceof \DateTime) ? $this->dateOutput($this->expire)
: $this->dateOutput(new \DateTime());
}
protected function dateOutput(\DateTime $date) {
if ($this->dateAsString) {
return $date->format($this->dateFormat);
}
return $date;
}
控制器转储结果:
[1a]正常查询:
// non-entity
array(1) { [0]=> array(1) { ["expire"]=> object(DateTime)#354 (3) { ["date"]=> string(26) "1970-10-25 00:00:00.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } } }
[2a]部分对象查询:
// array of entity
array(1) { [0]=> object(App\Entity\Tnkb)#353 (23) { /* more properties */...["expire":protected]=> object(DateTime).../* more properties */
我发现这是Doctrine的正常行为,它与部分对象有关。请参阅下面的评论。链接:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html
答案 0 :(得分:0)
我不认为有时候返回一个\ DateTime,但有时会返回一个格式化的字符串。不过,也许你有理由这样做。
我能想到结果差异的唯一原因是Doctrine在加载实体时是否在属性上调用getter。我测试了一个简单的类,它具有相同的expire属性和getter。返回类仍然有序列化(未格式化)\ DateTime对象,这表示在某些时候你的getter被调用,属性设置为新的\ DateTime。
我的建议是查看Symfony在3.1中提供的the DateTimeNormalizer。如果你无法升级到3.1,那么你可以轻松地建立自己的。然后,您可以确保在所有回复中始终具有一致的\ DateTime格式。您可以从getter中删除->format(...)
,然后始终返回\ DateTime对象。我认为这是一种更清洁的方法。