diff --git a/config/services.yaml b/config/services.yaml index dfe3de8f..f0576e53 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -73,6 +73,10 @@ services: tags: - { name: "doctrine.orm.entity_listener" } + App\EventSubscriber\EventLoggerSubscriber: + tags: + - { name: 'doctrine.event_subscriber' } + App\EventSubscriber\MigrationListener: tags: - { name: 'doctrine.event_subscriber' } diff --git a/src/Entity/LogSystem/AbstractLogEntry.php b/src/Entity/LogSystem/AbstractLogEntry.php index b4334902..c4107bae 100644 --- a/src/Entity/LogSystem/AbstractLogEntry.php +++ b/src/Entity/LogSystem/AbstractLogEntry.php @@ -32,9 +32,14 @@ use App\Entity\Devices\DevicePart; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; +use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; use App\Entity\Parts\Storelocation; use App\Entity\Parts\Supplier; +use App\Entity\PriceInformations\Currency; +use App\Entity\PriceInformations\Orderdetail; +use App\Entity\PriceInformations\Pricedetail; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use DateTime; @@ -85,6 +90,11 @@ abstract class AbstractLogEntry extends AbstractDBElement protected const TARGET_TYPE_PART = 10; protected const TARGET_TYPE_STORELOCATION = 11; protected const TARGET_TYPE_SUPPLIER = 12; + protected const TARGET_TYPE_PARTLOT = 13; + protected const TARGET_TYPE_CURRENCY = 14; + protected const TARGET_TYPE_ORDERDETAIL = 15; + protected const TARGET_TYPE_PRICEDETAIL = 16; + protected const TARGET_TYPE_MEASUREMENTUNIT = 17; /** @var array This const is used to convert the numeric level to a PSR-3 compatible log level */ protected const LEVEL_ID_TO_STRING = [ @@ -111,6 +121,11 @@ abstract class AbstractLogEntry extends AbstractDBElement self::TARGET_TYPE_PART => Part::class, self::TARGET_TYPE_STORELOCATION => Storelocation::class, self::TARGET_TYPE_SUPPLIER => Supplier::class, + self::TARGET_TYPE_PARTLOT => PartLot::class, + self::TARGET_TYPE_CURRENCY => Currency::class, + self::TARGET_TYPE_ORDERDETAIL => Orderdetail::class, + self::TARGET_TYPE_PRICEDETAIL => Pricedetail::class, + self::TARGET_TYPE_MEASUREMENTUNIT => MeasurementUnit::class, ]; /** @var User The user which has caused this log entry diff --git a/src/Entity/LogSystem/DBElement.php b/src/Entity/LogSystem/DBElement.php new file mode 100644 index 00000000..a4041585 --- /dev/null +++ b/src/Entity/LogSystem/DBElement.php @@ -0,0 +1,28 @@ +level = self::LEVEL_INFO; + $this->setTargetElement($new_element); + } + /** * Gets the instock when the part was created. * diff --git a/src/Entity/LogSystem/ElementDeletedLogEntry.php b/src/Entity/LogSystem/ElementDeletedLogEntry.php index 2af0aade..53c59c42 100644 --- a/src/Entity/LogSystem/ElementDeletedLogEntry.php +++ b/src/Entity/LogSystem/ElementDeletedLogEntry.php @@ -24,6 +24,8 @@ declare(strict_types=1); namespace App\Entity\LogSystem; +use App\Entity\Base\AbstractDBElement; +use App\Entity\Contracts\NamedElementInterface; use Doctrine\ORM\Mapping as ORM; /** @@ -33,6 +35,32 @@ class ElementDeletedLogEntry extends AbstractLogEntry { protected $typeString = 'element_deleted'; + public function __construct(AbstractDBElement $deleted_element) + { + parent::__construct(); + $this->level = self::LEVEL_INFO; + $this->setTargetElement($deleted_element); + } + + /** + * @inheritDoc + * @return $this + */ + public function setTargetElement(?AbstractDBElement $element): AbstractLogEntry + { + parent::setTargetElement($element); + if ($element instanceof NamedElementInterface) { + $this->setOldName($element->getName()); + } + return $this; + } + + public function setOldName(string $old_name): self + { + $this->extra['n'] = $old_name; + return $this; + } + public function getOldName(): string { return $this->extra['n']; diff --git a/src/Entity/LogSystem/ElementEditedLogEntry.php b/src/Entity/LogSystem/ElementEditedLogEntry.php index 72908504..136490fd 100644 --- a/src/Entity/LogSystem/ElementEditedLogEntry.php +++ b/src/Entity/LogSystem/ElementEditedLogEntry.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace App\Entity\LogSystem; +use App\Entity\Base\AbstractDBElement; use Doctrine\ORM\Mapping as ORM; /** @@ -33,6 +34,14 @@ class ElementEditedLogEntry extends AbstractLogEntry { protected $typeString = 'element_edited'; + public function __construct(AbstractDBElement $changed_element) + { + parent::__construct(); + $this->level = self::LEVEL_INFO; + + $this->setTargetElement($changed_element); + } + /** * Returns the message associated with this edit change. * diff --git a/src/EventSubscriber/EventLoggerSubscriber.php b/src/EventSubscriber/EventLoggerSubscriber.php new file mode 100644 index 00000000..b7d7c768 --- /dev/null +++ b/src/EventSubscriber/EventLoggerSubscriber.php @@ -0,0 +1,121 @@ +logger = $logger; + } + + public function onFlush(OnFlushEventArgs $eventArgs) + { + $em = $eventArgs->getEntityManager(); + $uow = $em->getUnitOfWork(); + + /* + * Log changes and deletions of entites. + * We can not log persist here, because the entities do not have IDs yet... + */ + + foreach ($uow->getScheduledEntityUpdates() as $entity) { + if ($this->validEntity($entity)) { + $log = new ElementEditedLogEntry($entity); + $this->logger->log($log); + } + } + + foreach ($uow->getScheduledEntityDeletions() as $entity) { + if ($this->validEntity($entity)) { + $log = new ElementDeletedLogEntry($entity); + $this->logger->log($log); + } + } + + + $uow->computeChangeSets(); + } + + public function postPersist(LifecycleEventArgs $args) + { + //Create an log entry + + /** @var AbstractDBElement $entity */ + $entity = $args->getObject(); + if ($this->validEntity($entity)) { + $log = new ElementCreatedLogEntry($entity); + $this->logger->log($log); + } + } + + public function postFlush(PostFlushEventArgs $args) + { + $em = $args->getEntityManager(); + $uow = $em->getUnitOfWork(); + // If the we have added any ElementCreatedLogEntries added in postPersist, we flush them here. + if ($uow->hasPendingInsertions()) { + $em->flush(); + } + } + + /** + * Check if the given entity can be logged. + * @param object $entity + * @return bool True, if the given entity can be logged. + */ + protected function validEntity(object $entity): bool + { + //Dont log logentries itself! + if ($entity instanceof AbstractDBElement && !$entity instanceof AbstractLogEntry) { + return true; + } + + return false; + } + + /** + * @inheritDoc + */ + public function getSubscribedEvents() + { + return[ + Events::onFlush, + Events::postPersist, + Events::postFlush + ]; + } +} \ No newline at end of file