<?php
namespace App\EventListener;
use Exception;
use Pimcore\Db;
use Pimcore\Event\Model\ElementEventInterface;
use Pimcore\Model\Asset;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\Krankheitsmeldung;
use Pimcore\Model\DataObject\Unfallmeldung;
use Pimcore\Model\User;
use Pimcore\Tool\Admin;
use Pimcore\Tool\Session;
class LogChangesListener
{
const CHANGES_FOLDER_PATH = 'Änderungen';
const CLASS_ID = 'Krankheitsmeldung';
const CLASS_ID_UNFALLMELDUNG = 'Unfallmeldung';
const ASSET_FIELD_NAME = 'assets'; // many-to-many relation
const CHANGELOG_FIELD_NAME = 'changeLog'; // many-to-many object relation
const CHANGED_ACTION = 'changed';
const REMOVED_ACTION = 'removed';
const ASSIGNED_ACTION = 'assigned';
const UNASSIGNED_ACTION = 'unassigned';
/**
* @param ElementEventInterface $e
* @return void
* @throws Exception
*/
public function onPreUpdate(ElementEventInterface $e)
{
$asset = $e->getAsset();
$this->createLogFileForAsset($asset, self::CHANGED_ACTION);
}
/**
* @param ElementEventInterface $e
* @return void
* @throws Exception
*/
public function onPreDelete(ElementEventInterface $e)
{
$asset = $e->getAsset();
$this->createLogFileForAsset($asset, self::REMOVED_ACTION);
}
/**
* @param $assetId
* @param $assetName
* @param $userName
* @param $action
* @return DataObject
* @throws Exception
*/
private function createLogFile(Asset $asset, $action): DataObject
{
$folderPath = '/'.ltrim(self::CHANGES_FOLDER_PATH, '/');
$folder = DataObject\Service::createFolderByPath($folderPath);
if (!$folder) {
throw new \LogicException('Could not create folder "'.$folderPath.'"');
}
$logFile = new \Pimcore\Model\DataObject\LogFile();
$logFile->setParent($folder);
$logFile->setKey($asset->getId().'_'.$action.'_'.date('Y-m-d-H-i-s'));
$logFile->setLog('Asset '.$asset->getFilename().' '.$action);
$user = Admin::getCurrentUser();
if($user) {
$logFile->setUser($user->getName());
}
$logFile->setPublished(true);
$logFile->save();
return $logFile;
}
/**
* @param Asset asset
* @param string $action
* @return void
* @throws Exception
*/
private function createLogFileForAsset(Asset $asset, $action)
{
$className = $this->getClassId($asset);
if(!$className) {
return false;
}
$relations = Db::get()->fetchAll('SELECT src_id FROM object_relations_'.$className.' WHERE dest_id = ? AND fieldname = ?', [$asset->getId(), self::ASSET_FIELD_NAME]);
try {
$logFile = $this->createLogFile($asset, $action);
} catch (Exception $exception) {
return;
}
$changeLogGetter = 'get'.ucfirst(self::CHANGELOG_FIELD_NAME);
$changeLogSetter = 'set'.ucfirst(self::CHANGELOG_FIELD_NAME);
foreach ($relations as $rel) {
$objectWithCurrentAsset = DataObject::getById($rel['src_id']);
if(!$objectWithCurrentAsset instanceof DataObject) {
continue;
}
$changeLogs = $objectWithCurrentAsset->$changeLogGetter();
$changeLogs[] = $logFile;
$objectWithCurrentAsset->$changeLogSetter($changeLogs);
$objectWithCurrentAsset->save();
}
}
/**
* @param ElementEventInterface $e
* @return void
* @throws Exception
*/
public function objectUpdate(ElementEventInterface $e)
{
if (method_exists($e, 'getArgument')) {
try {
$saveVersionOnly = $e->getArgument('saveVersionOnly');
if ($saveVersionOnly) {
return;
}
} catch (\InvalidArgumentException $exception) {
}
}
$object = $e->getObject();
if (!method_exists($object, 'getClassId')) {
return;
}
if ($object->getClassId() === self::CLASS_ID || $object->getClassId() === self::CLASS_ID_UNFALLMELDUNG) {
$versions = $object->getVersions();
$previousVersion = $versions[count($versions) - 1];
$assetGetter = 'get'.ucfirst(self::ASSET_FIELD_NAME);
$prevAssets = $previousVersion->getData()->$assetGetter();
$curAssets = $object->$assetGetter();
$this->updateChangeLogList((array)$prevAssets, (array)$curAssets, $object, self::UNASSIGNED_ACTION);
$this->updateChangeLogList((array)$curAssets, (array)$prevAssets, $object, self::ASSIGNED_ACTION);
}
}
/**
* @param Asset[] $assetArray1
* @param Asset[] $assetArray2
* @param DataObject\Concrete$object
* @param string $action
* @return void
*/
private function updateChangeLogList(array $assetArray1, array $assetArray2, DataObject\Concrete $object, $action)
{
foreach ($assetArray1 as $asset) {
if(!$asset instanceof Asset) {
continue;
}
$exists = false;
foreach ($assetArray2 as $item) {
if(!$item instanceof Asset) {
continue;
}
if ($item->getId() == $asset->getId()) {
$exists = true;
break;
}
}
if ($exists) {
continue;
}
try {
$changeLogsGetter = 'get'.ucfirst(self::CHANGELOG_FIELD_NAME);
$changeLogs = $object->$changeLogsGetter();
$logFile = $this->createLogFile($asset, $action);
$changeLogs[] = $logFile;
$object->setChangeLog($changeLogs);
//TODO: prakash
if($action === self::UNASSIGNED_ACTION) {
$asset->delete();
}
} catch (Exception $exception) {
continue;
}
}
}
private function getClassId(Asset $asset)
{
$path = $asset->getPath();
$uuid = trim($path, '/');
$sickness = Krankheitsmeldung::getByInterne_Schadennummer($uuid)->current();
if ($sickness instanceof Krankheitsmeldung && $sickness->getId()) {
return self::CLASS_ID;
}
$accident = Unfallmeldung::getByInterne_Schadennummer($uuid)->current();
if ($accident instanceof Unfallmeldung && $accident->getId()) {
return self::CLASS_ID_UNFALLMELDUNG;
}
return false;
}
}