0

I have this EventSubscriber:

class ChangeLogListener implements EventSubscriber
{
    private $tokenStorage;
    private $str,$str1;

    public function __construct(TokenStorage $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public function getSubscribedEvents()
    {
        return array(
            'postPersist',
            'postUpdate',
            'onDelete',
        );
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        if (!$args->getEntity() instanceof ChangeLog)

            $this->createLog($args, 'creation');
    }

    public function postUpdate(LifecycleEventArgs $args)
    {

        $this->createLog($args, 'update');
    }

    public function preRemove(LifecycleEventArgs $args)
    {
        $this->createLog($args, 'remove');
    }

    public function createLog(LifecycleEventArgs $args, $action)
    {
        # Entity manager
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();
        $entity = $args->getEntity();

        # Get user
        $user = $this->tokenStorage->getToken()->getUser();

        #Get changes
        $changes = $uow->getEntityChangeSet($entity);

        $cl = new ChangeLog();
        $cl->setDate(new \DateTime());
        $cl->setUser($user);
        $cl->setEntityName(get_class($entity));
        $cl->setEntityId($entity->getId());
        $cl->setAction($action);
        $cl->setDescription($log);
        $cl->setChangeset($changes);

        $em->persist($cl);
        $em->flush();
    }
}

And when I want to POST item, some data must be recorded to db. After all actions I receive this in change_set in my db:

a:3:{s:5:"value";a:2:{i:0;N;i:1;s:3:"120";}s:4:"item";a:2:{i:0;N;i:1;O:21:"AppBundle\Entity\Item":6:{s:25:"AppBundle\Entity\Itemid";i:127;s:27:"AppBundle\Entity\Itemname";s:7:"newitem";s:13:"*categories";O:33:"Doctrine\ORM\PersistentCollection":2:{s:13:"*collection";O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:2:{i:0;O:25:"AppBundle\Entity\Category":7:{s:29:"AppBundle\Entity\Categoryid";i:2;s:31:"AppBundle\Entity\Categoryname";s:10:"child to 1";s:33:"AppBundle\Entity\Categoryparent";O:40:"Proxies__CG__\AppBundle\Entity\Category":8:{s:17:"isInitialized";b:0;s:29:"AppBundle\Entity\Categoryid";i:1;s:31:"AppBundle\Entity\Categoryname";N;s:33:"AppBundle\Entity\Categoryparent";N;s:35:"AppBundle\Entity\Categorychildren";N;s:8:"*items";N;s:36:"AppBundle\Entity\CategorycreatedAt";N;s:36:"AppBundle\Entity\CategoryupdatedAt";N;}s:35:"AppBundle\Entity\Categorychildren";O:33:"Doctrine\ORM\PersistentCollection":2:{s:13:"*collection";O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:0:{}}s:14:"*initialized";b:0;}s:8:"*items";O:33:"Doctrine\ORM\PersistentCollection":2:{s:13:"*collection";O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:0:{}}s:14:"*initialized";b:0;}s:36:"AppBundle\Entity\CategorycreatedAt";N;s:36:"AppBundle\Entity\CategoryupdatedAt";N;}i:1;O:25:"AppBundle\Entity\Category":7:{s:29:"AppBundle\Entity\Categoryid";i:4;s:31:"AppBundle\Entity\Categoryname";s:8:"child1.1";s:33:"AppBundle\Entity\Categoryparent";r:13;s:35:"AppBundle\Entity\Categorychildren";O:33:"Doctrine\ORM\PersistentCollection":2:{s:13:"*collection";O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:0:{}}s:14:"*initialized";b:0;}s:8:"*items";O:33:"Doctrine\ORM\PersistentCollection":2:{s:13:"*collection";O:43:"Doctrine\Common\Collections\ArrayCollection":1:{s:53:"Doctrine\Common\Collections\ArrayCollectionelements";a:0:{}}s:14:"*initialized";b:0;}s:36:"AppBundle\Entity\CategorycreatedAt";N;s:36:"AppBundle\Entity\CategoryupdatedAt";N;}}}s:14:"*initialized";b:1;}s:13:"*attributes";N;s:32:"AppBundle\Entity\ItemcreatedAt";O:8:"DateTime":3:{s:4:"date";s:26:"2018-03-19 10:22:47.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}s:32:"AppBundle\Entity\ItemupdatedAt";N;}}s:9:"attribute";a:2:{i:0;N;i:1;O:26:"AppBundle\Entity\Attribute":3:{s:30:"AppBundle\Entity\Attributeid";i:96;s:33:"AppBundle\Entity\Attributealias";s:5:"price";s:32:"AppBundle\Entity\Attributename";s:5:"price";}}}

But I think this data is not readable.I think I need to parse received data before writing it into db, but I don't understand how to parse this into readable format, something like this:

name: Old Value: 12 => New Value: 121, updatedAt: Old Value: 2018-03-20 05:51:44 => New Value: 2018-03-20 08:36:12 and other

Any idea how to parse this?

Ashutosh Rai
  • 458
  • 1
  • 7
  • 14
Dialkord
  • 111
  • 1
  • 3
  • 12
  • Just iterate over the change set and generate required array format by yourself. It's not that hard. – Mike Doe Mar 20 '18 at 09:56
  • @MichaelZukowski if I knew how to do it, then I would not ask ... Can you tell me where you can find examples or articles to learn more about this? – Dialkord Mar 20 '18 at 10:17
  • @Dialkord I had given you links in answer, they are similar to your requirement, if you face any more complexity mark me. – Ashutosh Rai Mar 20 '18 at 10:32
  • @Dialkord you want an article how to traverse an array? Just use a `foreach` and see what you get, it isn't that hard, have you tried anything at all? – Mike Doe Mar 20 '18 at 11:05
  • @MichaelZukowski The problem is that I have objects in the resulting array and I just can not use foreach, since there will be an error when the value is an object (the object can not be converted to a string) – Dialkord Mar 20 '18 at 11:38

1 Answers1

0

You are directly inserting all work done on entities with whole object, that's why you are saving all the meta-data into db. Better to doctrine customized extension to handle this (doctrine-extensions and see Loggable behavioral extension for Doctrine2) or if you want to create self customized ChangeLogListner then use methods to compute or get exact change-Set using doctrine methods. to methods see here.

you can change your EventListner code something like this:

$em = $this->getDoctrine()->getManager();
$entity = $em->find('My\Entity', 1);
$entity->setTitle('Changed Title!');
$uow = $em->getUnitOfWork();
$uow->computeChangeSets(); // do not compute changes if inside a listener
$changeset = $uow->getEntityChangeSet($entity);

or check Is there a built-in way to get all of the changed/updated fields in a Doctrine 2 entity

if you are trying inside EventListner then try inside particular events like:

public function preUpdate(Event\LifecycleEventArgs $eventArgs)
{   
    $changeArray = $eventArgs->getEntityChangeSet();

    //do stuff with the change array

}
Ashutosh Rai
  • 458
  • 1
  • 7
  • 14
  • The bottom line is that I need to make my own log without resorting to using bandles, but the sample code that you gave me, namely using computeChangeSet () did not lead to any results, everything was as before, and I need to write down in the base of the change in a readable form. – Dialkord Mar 20 '18 at 10:40
  • I have tested this and working proper. Try to `print_r($changeset);`, it's better to first check this on your any controller, that will result you and easy to understand, it will return a array and as required you can convert this into json – Ashutosh Rai Mar 20 '18 at 11:22
  • You can use also similar methods like `Doctrine\ORM\UnitOfWork#recomputeSingleEntityChangeSet(Doctrine\ORM\ClassMetadata $meta, $entity)` if you know exactly what you want to check without iterating over the entire object graph. – Ashutosh Rai Mar 20 '18 at 11:26
  • if I do not parse data, result is: [sample](https://docs.google.com/document/d/1N8hBJ-UFZHMHc5n3i3MPf0tcGhWe6B5lxvrKT1T2uOw/edit?usp=sharing) But I want to explicitly record the changes, something like the one in question – Dialkord Mar 20 '18 at 11:44
  • If you could try this once better, and still face any problem then share result `$em = $eventArgs->getEntityManager(); $cm = $em->getClassMetadata(get_class($entity)); $em->getUnitOfWork()->recomputeSingleEntityChangeSet($cm, $entity);` – Ashutosh Rai Mar 20 '18 at 11:58
  • On call of $uow->getEntityChangeSet($entity) which returns an array where keys are $entity's properties and values are [$oldValue, $newValue] – Ashutosh Rai Mar 20 '18 at 12:04
  • Thanks for your support, I will try – Dialkord Mar 20 '18 at 15:16