<?php
namespace App\Misc;
use App\Exception\BadRequestException;
use App\Annotation\TransformAnnotation;
use AutoMapperPlus\AutoMapperInterface;
use Doctrine\ORM\EntityManagerInterface;
use League\Flysystem\FilesystemOperator;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class TransformDataHelper
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var AutoMapperInterface
*/
private $autoMapper;
public function __construct(
EntityManagerInterface $entityManager,
AutoMapperInterface $autoMapper,
\Psr\Container\ContainerInterface $serviceLocator,
private FilesystemOperator $uploadsStorage
) {
$this->entityManager = $entityManager;
$this->autoMapper = $autoMapper;
$this->serviceLocator = $serviceLocator;
}
public function transform($object, $inputProperties)
{
$reflectionClass = new \ReflectionClass(get_class($object));
$properties = $reflectionClass->getProperties();
$reader = new AnnotationReader();
foreach ($properties as $property) {
// @todo: check property readable
$propertyName = $property->getName();
$propertyValue = $object->{$propertyName};
/*
if(!in_array($propertyName, $inputProperties)) {
unset($object->{$propertyName});
continue;
}
*/
/** @var TransformAnnotation $transformAnnotation */
$transformAnnotation = $reader->getPropertyAnnotation($property, TransformAnnotation::class);
if (!$transformAnnotation) {
continue;
}
$newValue = $this->transformValue(
$propertyValue,
$transformAnnotation,
$object
);
$object->{$propertyName} = $newValue;
}
}
private function transformValue($value, TransformAnnotation $annotation, $object = null)
{
switch ($annotation->type) {
case 'int':
case 'integer':
return (int)$value;
case 'string':
return (string) is_array($value) ? 'yes' : $value;
case 'bool':
case 'boolean':
return filter_var($value, FILTER_VALIDATE_BOOLEAN);
case 'datetime':
if ($annotation->keepTimezone) return new \DateTime($value);
return is_null($value) ? null : $this->castDateTimeToEntity($value);
case 'date':
if ($annotation->format)
return $value == '' ? null : \DateTime::createFromFormat(
'Y-m-d',
date("Y-m-d", strtotime(str_replace('/', '-', $value)))
);
return $value == '' ? null : \DateTime::createFromFormat('Y-m-d', date("Y-m-d", strtotime($value)));
case 'time':
return $value == '' ? null : \DateTime::createFromFormat('H:i:s', $value);
case 'float':
return (float) $value;
case 'strip_tags':
// 9 is directory interview
// 8 is discussion
$isPost = isset($object->type) && ($object->type == 9 || $object->type == 8);
$isRichText = isset($annotation->isRichText) && $annotation->isRichText === 'true';
$containsHTML = $value != strip_tags($value);
if (($isPost || $isRichText) && $containsHTML) {
return $this->strip_tags_secured($value, [
'a', 'p', 'strong', 'u',
'h1', 'h2', 'h3',
'ul', 'li', 'ol',
'wrapquestion',
'question1', 'question2', 'question3',
'question4', 'question5', 'question6',
'question7', 'directorname', 'directorposition',
'img', 'iframe'
]);
} else {
return strip_tags($value);
}
case 'entity':
return $this->castValueToEntity($value, $annotation->class);
case 'entityEditable':
return $this->castValueToEntityEditable($value, $annotation);
case 'collectionEntity':
return $this->castValueToCollectionEntity($value, $annotation);
case 'collectionEntityEditable':
return $this->castValueToCollectionEntityEditable($value, $annotation);
case 'collectionObject':
return $this->castValueToObject($value, $annotation->class);
case 'imageBase64':
return $this->caseValueToImgBase64($value);
case 'slug':
return $this->setSlugToEntity($object, $annotation);
case 'mediaEntity':
return $this->castValueToMediaEntity($value, $annotation->class);
case 'mediaCollectionEntity':
return $this->castValueToMediaCollectionEntity($value, $annotation);
}
return $value;
}
private function castValueToEntity($identifier, $class)
{
if (!isset($identifier)) {
return null;
}
if ($identifier === 'isNull' || $identifier === '') {
return 'isNull';
}
if (is_numeric($identifier)) {
$identifier = (int) $identifier;
} else if (isset($identifier['id'])) {
$identifier = $identifier['id'];
}
$repository = $this->entityManager->getRepository($class);
$entity = $repository->find($identifier);
if (is_null($entity)) {
$parts = explode('\\', $class);
$entityName = $parts[count($parts) - 1];
throw new BadRequestException(
BadRequestException::NO_ENTITY,
null,
$entityName,
$identifier
);
}
return $entity;
}
private function castValueToEntityEditable($value, $annotation)
{
if (!is_array($value) || $value === '') {
return [];
}
$commonService = $this->serviceLocator->get('App\Service\CommonService');
$serviceName = $commonService->getClassName($annotation->class, true);
$requestDTO = 'App\DTO\\' . $serviceName . '\Add' . $serviceName . 'Input';
$service = $this->serviceLocator->get('App\Service\\' . $serviceName . 'Service');
$service->logger->info('value', [$value]);
$entity = null;
if (!empty($value['id'])) {
$entity = $service->get($value['id']);
}
$object = $service->inputResolver($value, $requestDTO, null, $serviceName);
$entity = $service->objectToEntity($object, $serviceName, $entity, true);
return $entity;
}
private function castValueToCollectionEntity($value, $annotation)
{
if (!is_array($value) || $value === '') {
return [];
}
try {
$repository = $this->entityManager->getRepository($annotation->class);
if (isset($annotation->field)) {
$filter = [];
$filter[$annotation->field] = $value;
$entityCollection = $repository->findBy($filter);
} else {
$entityCollection = $repository->findBy([
'id' => $value
]);
}
return $entityCollection;
} catch (\Exception $exception) {
dd($exception->getMessage());
}
return $value;
}
private function castValueToCollectionEntityEditable($value, $annotation)
{
if (!is_array($value) || $value === '') {
return [];
}
$commonService = $this->serviceLocator->get('App\Service\CommonService');
$serviceName = $commonService->getClassName($annotation->class, true);
$requestDTO = 'App\DTO\\' . $serviceName . '\Add' . $serviceName . 'Input';
$service = $this->serviceLocator->get('App\Service\\' . $serviceName . 'Service');
$collection = [];
$service->logger->info('value', [$value]);
foreach ($value as $arrayData) {
$entity = null;
if (!empty($arrayData['id'])) {
$entity = $service->get($arrayData['id']);
}
$object = $service->inputResolver($arrayData, $requestDTO, null, $serviceName);
$entity = $service->objectToEntity($object, $serviceName, $entity, true);
$collection[] = $entity;
}
return $collection;
}
private function castValueToObject($value, $class)
{
if (!class_exists($class)) {
return $value;
}
$newArr = [];
foreach ($value as $key => $attributes) {
$newArr[$key] = $this->autoMapper->map($attributes, $class);
}
return $newArr;
}
private function caseValueToImgBase64($value)
{
if (!$value) {
return null;
}
$pureBase64 = Base64FileExtractor::extractBase64String($value);
if (!$pureBase64) {
return null;
}
return new UploadedBase64File($pureBase64, 'image');
}
private function setSlugToEntity($object, $annotation)
{
$field = isset($annotation->field) ? $annotation->field : 'name';
$commonService = $this->serviceLocator->get('App\Service\CommonService');
return $commonService->slugify($object->{$field});
}
function strip_tags_secured(
$html_str,
$allowed_tags = [],
$allowed_attrs = ['href', 'alt', 'src', 'frameborder', 'allowfullscreen']
) {
$xml = new \DOMDocument();
//Suppress warnings: proper error handling is beyond scope of example
libxml_use_internal_errors(true);
if (!strlen($html_str)) {
return false;
}
$html_str = mb_convert_encoding($html_str, 'HTML-ENTITIES', "UTF-8");
if ($xml->loadHTML($html_str, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) {
foreach ($xml->getElementsByTagName("*") as $tag) {
if (!in_array($tag->tagName, $allowed_tags)) {
$tag->parentNode->removeChild($tag);
} else {
foreach ($tag->attributes as $attr) {
if (!in_array($attr->nodeName, $allowed_attrs)) {
$tag->removeAttribute($attr->nodeName);
}
}
}
}
}
return trim($xml->saveHTML());
}
public function castDateTimeToEntity($value)
{
if ($value === '' || $value === 'isNull') return 'isNull';
$requestService = $this->serviceLocator->get('App\Service\RequestService');
$datetime = new \DateTime(str_replace('Z', '', str_replace('T', ' ', str_replace('/', '-', $value))), new \DateTimeZone($requestService->timezone));
$datetime->setTimezone(new \DateTimeZone('UTC'));
return $datetime;
}
public function castValueToMediaEntity($file, $class)
{
$mediaService = $this->serviceLocator->get('App\Service\MediaService');
if ($file instanceof UploadedFile) {
$newFile = $mediaService->uploadFile($file, 'media');
return $mediaService->add($newFile, null, null, 'ENTITY');
}
return $this->getEntityFromId($file, $class);
}
private function castValueToMediaCollectionEntity($value, $annotation)
{
if (!is_array($value) || $value === '') {
return [];
}
$mediaService = $this->serviceLocator->get('App\Service\MediaService');
$mediaService->logger->info('value', [$value]);
$collection = [];
foreach ($value as $file) {
if ($file instanceof UploadedFile) {
$newFile = $mediaService->uploadFile($file, 'media');
$collection[] = $mediaService->add($newFile, null, null, 'ENTITY');
} else {
$collection[] = $this->getEntityFromId($file, $annotation->class);
}
}
return $collection;
}
public function getEntityFromId($identifier, $class)
{
if (!isset($identifier)) {
return null;
}
if ($identifier === 'isNull' || $identifier === '') {
return 'isNull';
}
if (is_numeric($identifier)) {
$identifier = (int) $identifier;
} else if (isset($identifier['id'])) {
$identifier = $identifier['id'];
}
$repository = $this->entityManager->getRepository($class);
$entity = $repository->find($identifier);
if (is_null($entity)) {
$parts = explode('\\', $class);
$entityName = $parts[count($parts) - 1];
throw new BadRequestException(
BadRequestException::NO_ENTITY,
null,
$entityName,
$identifier
);
}
return $entity;
}
}