VMC*_*VMC 7 symfony doctrine-orm
在Symfony2项目中,我有一个Doctrine实体,它有一个datetime叫做的字段lastAccessed.此外,实体在字段上使用TimestampableupdatedAt.
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;
}
Run Code Online (Sandbox Code Playgroud)
我需要在不更新字段的lastAccessed情况下更新updatedAt字段.我怎样才能做到这一点?
我也偶然发现了这个问题并提出了这个解决方案:
public function disableTimestampable()
{
$eventManager = $this->getEntityManager()->getEventManager();
foreach ($eventManager->getListeners('onFlush') as $listener) {
if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
$eventManager->removeEventSubscriber($listener);
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当然,非常类似的东西也可以用来禁止可指责的行为。
还有一种简单的方法(或更正确的方法)如何做到这一点,只需覆盖侦听器即可。
首先创建将由实体实现的接口
interface TimestampableCancelInterface
{
public function isTimestampableCanceled(): bool;
}
Run Code Online (Sandbox Code Playgroud)
比扩展 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();
}
}
Run Code Online (Sandbox Code Playgroud)
实现接口。最简单的方法就是为此设置属性
private $isTimestampableCanceled = false;
public function cancelTimestampable(bool $cancel = true): void
{
$this->isTimestampableCanceled = $cancel;
}
public function isTimestampableCanceled():bool {
return $this->isTimestampableCanceled;
}
Run Code Online (Sandbox Code Playgroud)
或者定义你想要的规则
最后一件事是不要设置默认侦听器,而是设置我们的侦听器。我正在使用 symfony 所以:
stof_doctrine_extensions:
orm:
default:
timestampable: true
class:
timestampable: <Namespace>\TimestampableListener
Run Code Online (Sandbox Code Playgroud)
比你能做的
$entity = new Entity;
$entity->cancelTimestampable(true)
$em->persist($entity);
$em->flush(); // and you will get constraint violation since createdAt is not null :D
Run Code Online (Sandbox Code Playgroud)
这种方式可以禁用每个实体的时间戳,而不是整个 onFlush。此外,根据实体状态可以轻松应用自定义行为。
小智 3
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);
Run Code Online (Sandbox Code Playgroud)
您当然可以将其放入适当的存储库类中
| 归档时间: |
|
| 查看次数: |
1534 次 |
| 最近记录: |