xiidea / EasyAuditBundle

A Symfony Bundle To Log Selective Events
http://xiidea.github.io/EasyAuditBundle/
MIT License
89 stars 22 forks source link

Support ODM #35

Closed ronisaha closed 5 years ago

ronisaha commented 5 years ago

To support ODM, we have to do

ronisaha commented 5 years ago

Planning to rename following config values:

Old value New value
entity_class audit_log_class
entity_event_resolver doctrine_event_resolver
doctrine_entities doctrine_objects

Any suggestion/thought from any one? @wh1pp3rz, @braianj

Thanks.

braianj commented 5 years ago

Hi @ronisaha i'm still working with v1.4.7 but I can share with you my entity resolver in case it help you

<?php
namespace LoginBundle\Resolver;
use Symfony\Component\EventDispatcher\Event;
use Xiidea\EasyAuditBundle\Events\DoctrineEntityEvent;
use Xiidea\EasyAuditBundle\Resolver\EntityEventResolver as BaseResolver;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Psr\Log\LoggerInterface;

class EntityEventResolver extends BaseResolver
{

    private $logger;
    private $serializer;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    /**
     * @param Event|DoctrineEntityEvent $event
     * @param $eventName
     *
     * @return array
     */
    public function getEventLogInfo(Event $event, $eventName)
    {
        if (!$event instanceof DoctrineEntityEvent) {
            return null;
        }
        $this->initialize($event, $eventName);
        $changesMetaData = $this->getChangeSets($this->entity);

        if ($this->isUpdateEvent() && $changesMetaData == NULL) {
            return NULL;
        }
        $reflectionClass = $this->getReflectionClassFromObject($this->entity);
        $typeName = $reflectionClass->getShortName();
        //$eventType = $this->getEventType($typeName);
        $eventDescription = $this->getDescriptionString($reflectionClass, $typeName);

        $data = [];
        $ignorar = array('tu', 'ts', 'updated', 'created', 'transitions', '__initializer__', '__cloner__', '__isInitialized__', 'timezone', 'salt', 'password', 'newPassword');

        if (empty($changesMetaData)) {
            $encoder = new JsonEncoder();
            $normalizer = new ObjectNormalizer();

            $this->serializer = new Serializer(array($normalizer), array($encoder));

            $reflClass = new \ReflectionClass($this->entity);

            $arrayDatos = [];
            foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {
                if (
                    0 !== $reflMethod->getNumberOfRequiredParameters() ||
                    $reflMethod->isStatic() ||
                    $reflMethod->isConstructor() ||
                    $reflMethod->isDestructor()
                ) {
                    continue;
                }

                $name = $reflMethod->name;
                $attributeName = null;

                if (0 === strpos($name, 'get') || 0 === strpos($name, 'has')) {
                    // getters and hassers
                    $attributeName = substr($name, 3);

                    if (!$reflClass->hasProperty($attributeName)) {
                        $attributeName = lcfirst($attributeName);
                    }
                } elseif (0 === strpos($name, 'is')) {
                    // issers
                    $attributeName = substr($name, 2);

                    if (!$reflClass->hasProperty($attributeName)) {
                        $attributeName = lcfirst($attributeName);
                    }
                }

                if (!is_null($attributeName) && !in_array($attributeName, $ignorar))
                {
                    $val = $this->entity->$name();

                    $es_colecion = (is_array($val) || ($val instanceof \ArrayAccess && $val instanceof \Traversable));

                    if(!$es_colecion) {
                        $arrayDatos[$attributeName] = $this->extraerValor($val);
                    } else {
                        $arrayDatos[$attributeName] = [];
                        foreach ($val as $item) {
                            $arrayDatos[$attributeName][] = $this->extraerValor($item);
                        }
                    }
                }
            }

            $data = $this->serializer->serialize($arrayDatos,'json');

        } elseif (is_string($changesMetaData)) {
            $data = $changesMetaData;
        } else {
            foreach ($changesMetaData as $key => $value) {
                if($value[0]!=$value[1] && !in_array($key, $ignorar)) {
                    if(gettype($value[0])== 'object') {

                        $entity = null;
                        foreach (explode('\\',get_class($value[0])) as $v) {
                            $entity = $v;
                        }

                        if((method_exists($value[0], 'getId'))) {

                            $value1 = $value[0]->getId();
                            $value2 = is_null($value[1]) ? null : $value[1]->getId();
                            $data[$key] = array('entity' => $entity, 'id' => array($value1, $value2));

                        } else {
                            $value1 = $this->isDateOrNot($value[0]);
                            $value2 = $this->isDateOrNot($value[1]);
                            $data[$key] = array($value1, $value2);
                        }
                    } else {
                        $data[$key] = $value;
                    }
                }
            }
            if (!empty($data)) {
                $data = json_encode($data);
            }
        }

        $infoFinal = array(
            'table'         => $typeName,
            'type'          => $this->translateToSpanishType(),
            'description'   => $eventDescription,
        );

        if ($typeName!='Agentes') {
            $infoFinal['tableId'] = $this->getProperty('id');
        }

        if (!empty($data)) {
            $infoFinal['data'] = $data;
        }
        return $infoFinal;
    }

    protected function extraerValor ($value) {
        $es_entidad = method_exists($value, 'getId');

        if($es_entidad) {
            return $value->getId();
        } elseif ($value instanceof \Date) {
            return $value->format("Y-m-d");
        } elseif ($value instanceof \DateTime) {
            return $value->format("Y-m-d H:i:s");
        } elseif (gettype($value)== 'object') {
            $value = json_encode($value, JSON_PRETTY_PRINT|JSON_ERROR_UNSUPPORTED_TYPE|JSON_PARTIAL_OUTPUT_ON_ERROR);
        }
        return $value;
    }

    /**
     * @param DoctrineEntityEvent $event
     * @param string $eventName
     */
    private function initialize(DoctrineEntityEvent $event, $eventName)
    {
        $this->eventShortName = null;
        $this->propertiesFound = array();
        $this->eventName = $eventName;
        $this->event = $event;
        $this->entity = $event->getLifecycleEventArgs()->getEntity();
    }

    protected function isDateOrNot($var) {
        if(is_a($var, 'DateTime')){
            return print_r(($var->format('H:i:s')!='00:00:00') ? $var->format('c') : $var->format('Y-m-d'), true);
        } else {
            return print_r($var, true);
        }
    }

    protected function getDescriptionString(\ReflectionClass $reflectionClass, $typeName)
    {
        $property = $this->getBestCandidatePropertyForIdentify($reflectionClass);
        $descriptionTemplate = '%s %s';//'%s ha sido %s ';
        if ($property) {
            $descriptionTemplate .= sprintf('.%s = %s', $property, $this->getProperty($property));
        }

        return sprintf($descriptionTemplate,
            $this->translateToSpanishType(),
            $typeName);
    }
    /**
     * @param $changesMetaData
     *
     * @return null|string
     */
    protected function getAsSerializedString($changesMetaData)
    {
        if (empty($changesMetaData)) {
            return NULL;
        } elseif (is_string($changesMetaData)) {
            return $changesMetaData;
        }
        return serialize($changesMetaData);
    }

    protected function translateToSpanishType() {
        $accion = null;
        switch ($this->getEventShortName()) {
            case 'created':
                $accion = 'Crear';
                break;

            case 'updated':
                $accion = 'Actualizar';
                break;

            case 'deleted':
                $accion = 'Eliminar';
                break;

            default:
                $accion = 'Acción';
                break;
        }
        return $accion;
    }
}
wh1pp3rz commented 5 years ago

Hey Roni,

The new names are exactly what I had in mind.

On Tue, Dec 4, 2018 at 10:23 AM braianj notifications@github.com wrote:

Hi @ronisaha https://github.com/ronisaha i'm still working with v1.4.7 but I can share with you my entity resolver in case it help you

<?php

namespace LoginBundle\Resolver;

use Symfony\Component\EventDispatcher\Event;

use Xiidea\EasyAuditBundle\Events\DoctrineEntityEvent;

use Xiidea\EasyAuditBundle\Resolver\EntityEventResolver as BaseResolver;

use Symfony\Component\Serializer\Encoder\JsonEncoder;

use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

use Symfony\Component\Serializer\Serializer;

use Psr\Log\LoggerInterface;

class EntityEventResolver extends BaseResolver

{

private $logger;

private $serializer;

public function __construct(LoggerInterface $logger)

{

    $this->logger = $logger;

}

/**

 * @param Event|DoctrineEntityEvent $event

 * @param $eventName

 *

 * @return array

 */

public function getEventLogInfo(Event $event, $eventName)

{

    if (!$event instanceof DoctrineEntityEvent) {

        return null;

    }

    $this->initialize($event, $eventName);

    $changesMetaData = $this->getChangeSets($this->entity);

    if ($this->isUpdateEvent() && $changesMetaData == NULL) {

        return NULL;

    }

    $reflectionClass = $this->getReflectionClassFromObject($this->entity);

    $typeName = $reflectionClass->getShortName();

    //$eventType = $this->getEventType($typeName);

    $eventDescription = $this->getDescriptionString($reflectionClass, $typeName);

    $data = [];

    $ignorar = array('tu', 'ts', 'updated', 'created', 'transitions', '__initializer__', '__cloner__', '__isInitialized__', 'timezone', 'salt', 'password', 'newPassword');

    if (empty($changesMetaData)) {

        $encoder = new JsonEncoder();

        $normalizer = new ObjectNormalizer();

        $this->serializer = new Serializer(array($normalizer), array($encoder));

        $reflClass = new \ReflectionClass($this->entity);

        $arrayDatos = [];

        foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflMethod) {

            if (

                0 !== $reflMethod->getNumberOfRequiredParameters() ||

                $reflMethod->isStatic() ||

                $reflMethod->isConstructor() ||

                $reflMethod->isDestructor()

            ) {

                continue;

            }

            $name = $reflMethod->name;

            $attributeName = null;

            if (0 === strpos($name, 'get') || 0 === strpos($name, 'has')) {

                // getters and hassers

                $attributeName = substr($name, 3);

                if (!$reflClass->hasProperty($attributeName)) {

                    $attributeName = lcfirst($attributeName);

                }

            } elseif (0 === strpos($name, 'is')) {

                // issers

                $attributeName = substr($name, 2);

                if (!$reflClass->hasProperty($attributeName)) {

                    $attributeName = lcfirst($attributeName);

                }

            }

            if (!is_null($attributeName) && !in_array($attributeName, $ignorar))

            {

                $val = $this->entity->$name();

                $es_colecion = (is_array($val) || ($val instanceof \ArrayAccess && $val instanceof \Traversable));

                if(!$es_colecion) {

                    $arrayDatos[$attributeName] = $this->extraerValor($val);

                } else {

                    $arrayDatos[$attributeName] = [];

                    foreach ($val as $item) {

                        $arrayDatos[$attributeName][] = $this->extraerValor($item);

                    }

                }

            }

        }

        $data = $this->serializer->serialize($arrayDatos,'json');

    } elseif (is_string($changesMetaData)) {

        $data = $changesMetaData;

    } else {

        foreach ($changesMetaData as $key => $value) {

            if($value[0]!=$value[1] && !in_array($key, $ignorar)) {

                if(gettype($value[0])== 'object') {

                    $entity = null;

                    foreach (explode('\\',get_class($value[0])) as $v) {

                        $entity = $v;

                    }

                    if((method_exists($value[0], 'getId'))) {

                        $value1 = $value[0]->getId();

                        $value2 = is_null($value[1]) ? null : $value[1]->getId();

                        $data[$key] = array('entity' => $entity, 'id' => array($value1, $value2));

                    } else {

                        $value1 = $this->isDateOrNot($value[0]);

                        $value2 = $this->isDateOrNot($value[1]);

                        $data[$key] = array($value1, $value2);

                    }

                } else {

                    $data[$key] = $value;

                }

            }

        }

        if (!empty($data)) {

            $data = json_encode($data);

        }

    }

    $infoFinal = array(

        'table'         => $typeName,

        'type'          => $this->translateToSpanishType(),

        'description'   => $eventDescription,

    );

    if ($typeName!='Agentes') {

        $infoFinal['tableId'] = $this->getProperty('id');

    }

    if (!empty($data)) {

        $infoFinal['data'] = $data;

    }

    return $infoFinal;

}

protected function extraerValor ($value) {

    $es_entidad = method_exists($value, 'getId');

    if($es_entidad) {

        return $value->getId();

    } elseif ($value instanceof \Date) {

        return $value->format("Y-m-d");

    } elseif ($value instanceof \DateTime) {

        return $value->format("Y-m-d H:i:s");

    } elseif (gettype($value)== 'object') {

        $value = json_encode($value, JSON_PRETTY_PRINT|JSON_ERROR_UNSUPPORTED_TYPE|JSON_PARTIAL_OUTPUT_ON_ERROR);

    }

    return $value;

}

/**

 * @param DoctrineEntityEvent $event

 * @param string $eventName

 */

private function initialize(DoctrineEntityEvent $event, $eventName)

{

    $this->eventShortName = null;

    $this->propertiesFound = array();

    $this->eventName = $eventName;

    $this->event = $event;

    $this->entity = $event->getLifecycleEventArgs()->getEntity();

}

protected function isDateOrNot($var) {

    if(is_a($var, 'DateTime')){

        return print_r(($var->format('H:i:s')!='00:00:00') ? $var->format('c') : $var->format('Y-m-d'), true);

    } else {

        return print_r($var, true);

    }

}

protected function getDescriptionString(\ReflectionClass $reflectionClass, $typeName)

{

    $property = $this->getBestCandidatePropertyForIdentify($reflectionClass);

    $descriptionTemplate = '%s %s';//'%s ha sido %s ';

    if ($property) {

        $descriptionTemplate .= sprintf('.%s = %s', $property, $this->getProperty($property));

    }

    return sprintf($descriptionTemplate,

        $this->translateToSpanishType(),

        $typeName);

}

/**

 * @param $changesMetaData

 *

 * @return null|string

 */

protected function getAsSerializedString($changesMetaData)

{

    if (empty($changesMetaData)) {

        return NULL;

    } elseif (is_string($changesMetaData)) {

        return $changesMetaData;

    }

    return serialize($changesMetaData);

}

protected function translateToSpanishType() {

    $accion = null;

    switch ($this->getEventShortName()) {

        case 'created':

            $accion = 'Crear';

            break;

        case 'updated':

            $accion = 'Actualizar';

            break;

        case 'deleted':

            $accion = 'Eliminar';

            break;

        default:

            $accion = 'Acción';

            break;

    }

    return $accion;

}

}

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/xiidea/EasyAuditBundle/issues/35#issuecomment-444138668, or mute the thread https://github.com/notifications/unsubscribe-auth/ALGbRQxdNRVt8oybX--XNwvAlullMn1_ks5u1pNagaJpZM4Y9zW3 .

-- Not everything that counts can be counted, and not everything that can be counted counts - Albert Einstein

ronisaha commented 5 years ago

@wh1pp3rz Could you please confirm the latest odm branch is working for both ORM and Document ? After your confirmation i'll merge it to master branch.

wh1pp3rz commented 5 years ago

@ronisaha I can confirm the latest branch does work for both ODM and ORM

pribeirojtm commented 5 years ago

Hi @ronisaha. Since this feature has lot of changes, is it still in master branch to get more matured, and to be better tested? It is kind of experimental feature? I don't have rush in having this feature since I'm currently only using ORM, I'm just asking if is it planned to release a new tag regarding this. Thanks.

ronisaha commented 5 years ago

Yes you are right, I was waiting for some time to get a feedback from users, as I'm not using ODM in any of my projects. Also I was waiting for SF4.3 release to test it. But could not make time for it. Hopefully I'll release a new tag with SF4.3 support checking soon.