Symfony 在某些更新时禁用“updatedAt”字段的时间戳自动更新
在Symfony2项目中,我有一个条令实体,它有一个Symfony 在某些更新时禁用“updatedAt”字段的时间戳自动更新,symfony,doctrine-orm,Symfony,Doctrine Orm,在Symfony2项目中,我有一个条令实体,它有一个datetime字段,名为lastAccessed。此外,实体在updatedAt字段中使用 namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM, Gedmo\Mapping\Annotation as Gedmo ; class MyEntity { /** * @ORM\Column(type="datetime") */
datetime
字段,名为lastAccessed
。此外,实体在updatedAt
字段中使用
namespace AppBundle\Entity;
use
Doctrine\ORM\Mapping as ORM,
Gedmo\Mapping\Annotation as Gedmo
;
class MyEntity {
/**
* @ORM\Column(type="datetime")
*/
private $lastAccessed;
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
}
我需要更新字段
lastAccessed
,而不需要更新updatedAt
字段。我该怎么做呢?时间标记只是一种行为,所以每次使用ORM时都会执行。
在我看来,最简单的方法就是使用DBAL层和原始sql查询
例如:
$sql = "UPDATE my_table set last_accessed = :lastAccess where id = :id";
//set parameters
$params['lastAccess'] = new \DateTime();
$params['id'] = $some_id;
$stmt = $this->entityManager->getConnection()->prepare($sql);
$stmt->execute($params);
当然,您可以将其放入适当的存储库类中我也偶然发现了这一点,并提出了以下解决方案:
public function disableTimestampable()
{
$eventManager = $this->getEntityManager()->getEventManager();
foreach ($eventManager->getListeners('onFlush') as $listener) {
if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
$eventManager->removeEventSubscriber($listener);
break;
}
}
}
当然,也可以使用一些非常类似的方法来禁用可指责的行为。还有一种简单的方法(或更合适的方法)如何做到这一点,只需覆盖侦听器
首先创建将由实体实现的接口
interface TimestampableCancelInterface
{
public function isTimestampableCanceled(): bool;
}
而不是扩展时间表侦听器并覆盖updateField
。
通过这种方式,我们可以禁用所有事件,或者使用canceltimestable
根据实体状态定义用于取消的自定义规则
class TimestampableListener extends \Gedmo\Timestampable\TimestampableListener
{
protected function updateField($object, $eventAdapter, $meta, $field)
{
/** @var \Doctrine\Orm\Mapping\ClassMetadata $meta */
$property = $meta->getReflectionProperty($field);
$newValue = $this->getFieldValue($meta, $field, $eventAdapter);
if (!$this->isTimestampableCanceled($object)) {
$property->setValue($object, $newValue);
}
}
private function isTimestampableCanceled($object): bool
{
if(!$object instanceof TimestampableCancelInterface){
return false;
}
return $object->isTimestampableCanceled();
}
}
实现接口。最简单的方法是只为它设置属性
private $isTimestampableCanceled = false;
public function cancelTimestampable(bool $cancel = true): void
{
$this->isTimestampableCanceled = $cancel;
}
public function isTimestampableCanceled():bool {
return $this->isTimestampableCanceled;
}
或者定义你想要的规则
最后一件事是不设置默认侦听器,而是设置我们的侦听器。
我正在使用symfony,因此:
stof_doctrine_extensions:
orm:
default:
timestampable: true
class:
timestampable: <Namespace>\TimestampableListener
这种方式可以针对单个实体禁用时间戳,而不是针对整个onFlush。此外,基于实体状态的自定义行为也很容易应用。没有更干净的解决方案吗?如果能够轻松禁用自动更新功能,那就太好了。。
class TimestampableListener extends \Gedmo\Timestampable\TimestampableListener
{
protected function updateField($object, $eventAdapter, $meta, $field)
{
/** @var \Doctrine\Orm\Mapping\ClassMetadata $meta */
$property = $meta->getReflectionProperty($field);
$newValue = $this->getFieldValue($meta, $field, $eventAdapter);
if (!$this->isTimestampableCanceled($object)) {
$property->setValue($object, $newValue);
}
}
private function isTimestampableCanceled($object): bool
{
if(!$object instanceof TimestampableCancelInterface){
return false;
}
return $object->isTimestampableCanceled();
}
}