Disable Doctrine Timestampable by automatically updating the `updatedAt` field with a specific update

In a Symfony2 project, I have a Doctrine object that has a field datetimecalled lastAccessed. In addition, the Timestampable object uses 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;

}

I need to update a field lastAccessedwithout updating the field updatedAt. How can i do this?

+4
source share
3 answers

Timestampable is just a doctrine behavior that is executed every time you use ORM. In my opinion, the easiest way is to simply use the DBAL level and the raw SQL query.

For instance:

$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

:

public function disableTimestampable()
{
    $eventManager = $this->getEntityManager()->getEventManager();
    foreach ($eventManager->getListeners('onFlush') as $listener) {
        if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
            $eventManager->removeEventSubscriber($listener);
            break;
        }
    }
}

- , , , , .

+1

( ), , .

,

interface TimestampableCancelInterface
{

   public function isTimestampableCanceled(): bool;

}

Timestampable updateField 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;
}

,

The latter is not to set the default receiver, but ours. I use symfony like this:

stof_doctrine_extensions:
    orm:
        default:
            timestampable: true
    class:
      timestampable:  <Namespace>\TimestampableListener

Than you can just do

$entity = new Entity;
$entity->cancelTimestampable(true)
$em->persist($entity);
$em->flush(); // and you will get constraint violation since createdAt is not null :D

This method can be disabled in time for one object not for the whole onFlush. User behavior is also easy to apply based on the state of the object.

0
source

All Articles