Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony 在某些更新时禁用“updatedAt”字段的时间戳自动更新_Symfony_Doctrine Orm - Fatal编程技术网

Symfony 在某些更新时禁用“updatedAt”字段的时间戳自动更新

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") */

在Symfony2项目中,我有一个条令实体,它有一个
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();
    }

}