Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable timestampable auto-updating on certain update #1722

Closed
Nightbr opened this issue Dec 13, 2016 · 8 comments
Closed

Disable timestampable auto-updating on certain update #1722

Nightbr opened this issue Dec 13, 2016 · 8 comments

Comments

@Nightbr
Copy link

Nightbr commented Dec 13, 2016

Hi,
I'm really stuck with this and I tried a lots of thing but not successfully. First, I would like to disable the timestampable behavior on certain update. (For example, I want to set inactiveAt if updatedAt is 6-months expire from today, but I don't want to reset the updatedAt by setting inactiveAt).

So I have a my trait TimestampableEntity:

<?php

namespace AppBundle\Entity\Traits;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use JMS\Serializer\Annotation as Serializer;

/**
 * Timestampable Trait, usable with PHP >= 5.4
 *
 */
trait TimestampableEntity
{
    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(name="created_at", type="datetime")
     * @Serializer\Groups({"Default", "elastica"})
     * @Serializer\Expose
     */
    private $createdAt;

    /**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(name="updated_at", type="datetime")
     * @Serializer\Expose
     */
    private $updatedAt;

    /**
     * Sets createdAt.
     *
     * @param  \DateTime $createdAt
     * @return $this
     */
    public function setCreatedAt(\DateTime $createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Returns createdAt.
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Sets updatedAt.
     *
     * @param  \DateTime $updatedAt
     * @return $this
     */
    public function setUpdatedAt(\DateTime $updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Returns updatedAt.
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }
}

And I use it in my Entity:
use TimestampableEntity;

It works like a charm and updates the updatedAt field everytime I made change on my entity.

Now, I want to disable this behavior for my scenario with inactiveAt:
So I tried everything I found on the internet:

Here is my last try and I think I am closed to the solution but the updatedAt is still updated...

    /**
     * Set inactiveAt date the all inactive announces
     */
    private function setAnnounceInactiveAt($announces)
    {
        if($announces){
            // This will be usefull with 6-months expiration announce
            $em = $this->getContainer()->get('doctrine.orm.default_entity_manager');
            $this->disableTimestampable($em);
            foreach ($announces as $announce) {
                // if announce has a date and becomes inactive, use the announce.date
                if($announce->getDate()){
                    $announce->setInactiveAt($announce->getDate());
                }else{
                    $announce->setInactiveAt(new \DateTime());
                }
                $em->persist($announce);
            }
            $em->flush();
        }
    }

    // @TODO refactor properly this...
    private function disableTimestampable($em)
    {
        $eventManager = $em->getEventManager();
        foreach ($eventManager->getListeners('onFlush') as $listener) {
            if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
                $eventManager->removeEventSubscriber($listener);
            }
        }
    }

If someone can help on this.
Thanks in advance!

Regards

@l3pp4rd
Copy link
Contributor

l3pp4rd commented Dec 13, 2016

please respect my time and do not open support issues

@Nightbr
Copy link
Author

Nightbr commented Dec 13, 2016

Okay.
If anyone else have the problem here is a working solution:

    private function disableTimestampable()
    {
        $listenerInst = null;
        $evm = $this->em->getEventManager();
        foreach ($evm->getListeners() as $event => $listeners) {
            foreach ($listeners as $hash => $listener) {
                if ($listener instanceof \Gedmo\Timestampable\TimestampableListener) {
                    $listenerInst = $listener;
                    $evm->removeEventListener(array('prePersist','loadClassMetadata','onFlush'), $listenerInst);
                }
            }
        }
    }

It's really an ugly fix. And I would like to ask if it is possible to create in the TimestampableListener (or better the AbstractTrackingListener) a method or flag silent and we can disable it through a service or something else.
I think it's a real feature and it can be useful in many situation.

Can we discuss about this ?

Thank you for your help btw!

@BorbagUskada
Copy link

Would be nice to see an exclude property in the @timestampable annotation, like this:

/**
     * @var \DateTime
     *
     * @Gedmo\Timestampable(on="update", exclude="inactiveAt")
     * @ORM\Column(name="updated_at", type="datetime")
     * @Serializer\Expose
     */
    private $updatedAt;

Exclude could accept single field or array.

@zajca
Copy link

zajca commented Dec 7, 2018

There is also much nicer solution by implementing own listener. Which allow to cancel event by own rules most easily per entity instance. Cancel event listener is really ugly and unpredictable solution.
I post some code here: https://stackoverflow.com/a/53666915/1269774

I also like @LoicProust solution something like disable-when would be perfect.

@borodiliz
Copy link

Solution proposed by @zajca works like a charm. Thanks!

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@ismaellastlevel
Copy link

for those who will always search, the new syntax
#[Gedmo\Timestampable(on: 'change', field: ['title', 'body'])]
allows you to update the update field based on certain fields only.
it will therefore be enough to omit the field that we do not want to take into account

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants