在Symfony2项目中,我有一个具有datetime
字段的Doctrine实体,名为lastAccessed
。此外,该实体在updatedAt
字段上使用Timestampable。
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
字段。我怎么能这样做?
答案 0 :(得分:2)
Timestampable只是主义行为,所以每次使用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);
您当然可以将其放入正确的存储库类
答案 1 :(得分:2)
我也偶然发现了这个问题并提出了这个解决方案:
public function disableTimestampable()
{
$eventManager = $this->getEntityManager()->getEventManager();
foreach ($eventManager->getListeners('onFlush') as $listener) {
if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
$eventManager->removeEventSubscriber($listener);
break;
}
}
}
当然也可以使用非常相似的东西来禁用可燃行为。
答案 2 :(得分:1)
还有一种简单的方法(或更合适的方法),只需覆盖侦听器即可。
将由实体实现的第一个创建接口
interface TimestampableCancelInterface
{
public function isTimestampableCanceled(): bool;
}
比扩展Timestampable侦听器和覆盖updateField
。
这样,我们可以禁用所有事件或使用cancelTimestampable
定义自定义规则以根据实体状态进行取消。
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
比你只能做
$entity = new Entity;
$entity->cancelTimestampable(true)
$em->persist($entity);
$em->flush(); // and you will get constraint violation since createdAt is not null :D
这种方法可以为每个实体禁用时间戳,而不是为整个onFlush禁用。另外,自定义行为很容易根据实体状态应用。