<?php
/**
* @author Antony Tkachenko <at@canaryknight.ru>
*/
namespace App\Form;
use App\Exception\ValidationException;
use App\Form\Contracts\FormDtoInterface;
use App\Utm\Utm;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class FormHandler
{
/** @var DenormalizerInterface */
private $serializer;
/** @var ValidatorInterface */
private $validator;
/** @var EventDispatcherInterface */
private $eventDispatcher;
/** @var PropertyInfoExtractorInterface */
private $propertyInfoExtractor;
public function __construct(
DenormalizerInterface $serializer,
ValidatorInterface $validator,
EventDispatcherInterface $eventDispatcher,
PropertyInfoExtractorInterface $propertyInfoExtractor
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->eventDispatcher = $eventDispatcher;
$this->propertyInfoExtractor = $propertyInfoExtractor;
}
public function handle(string $dtoClass, array $data, ?Utm $utm)
{
$utm = $utm ?? Utm::fromArray([]);
if (isset($data['type'])) {
unset($data['type']);
}
if (isset($data['ym_client_id'])) {
$utm->setYmClientId($data['ym_client_id']);
unset($data['ym_client_id']);
}
$dto = $this->serializer->denormalize(
$data,
$dtoClass
);
$violations = $this->validator->validate($dto);
if (0 !== count($violations)) {
throw new ValidationException($violations);
}
$c = new CamelCaseToSnakeCaseNameConverter();
$path = explode('\\', $dtoClass);
$formName = $c->normalize(array_pop($path));
/** @var FormDtoInterface $dto */
$data = $this->extractData($dto);
$event = new FormHandledEvent($dto, $data, $formName, $utm);
$this->eventDispatcher->dispatch($event, FormHandledEvent::NAME);
//$this->mailer->send($email);
return $dto;
}
public function extractData(object $dto): array
{
$properties = (new \ReflectionObject($dto))
->getProperties(\ReflectionProperty::IS_PUBLIC);
$map = [];
$class = get_class($dto);
foreach ($properties as $property) {
$name = $property->getName();
if (empty($dto->{$name})) {
continue;
}
$label = $this->propertyInfoExtractor->getShortDescription($class, $name);
$map[$label] = $dto->{$name};
}
return $map;
}
}