<?php namespace App\Service\Dto; use App\Service\Response\ResponseServiceInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Annotation\Ignore; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\Service\Attribute\Required; abstract class BaseDto implements DtoServiceInterface { private ?Request $request = null; private ?ValidatorInterface $validator = null; #[Required] public function initValidator( ?ValidatorInterface $validator ): void { $this->validator = $validator; } #[Required] public function initRequest( ?RequestStack $requestStack = null ): void { if ($requestStack) { $this->request = $requestStack->getCurrentRequest(); } } /** * Получение класса Dto * * @return DtoServiceInterface|null */ #[Ignore] public function getClass(): ?DtoServiceInterface { if ($this->request) { return self::getClassByData($this->request->getContent()); } return null; } public static function getClassByArray(?array $data = null): ?DtoServiceInterface { if (empty($data)) { return null; } return self::getClassByData(json_encode($data, JSON_THROW_ON_ERROR) ?: ''); } private static function getClassByData(string $data): ?DtoServiceInterface { if (!empty($data)) { try { $normalizer = new ObjectNormalizer( null, new CamelCaseToSnakeCaseNameConverter(), null, new ReflectionExtractor() ); $serializer = new Serializer( [$normalizer, new DateTimeNormalizer()], [new JsonEncoder()] ); return $serializer->deserialize($data, static::class, 'json'); } catch (\Exception $exception) { return null; } } return null; } public function toArray(): ?array { try { $normalizer = new ObjectNormalizer( null, new CamelCaseToSnakeCaseNameConverter(), null, new ReflectionExtractor() ); $serializer = new Serializer([$normalizer], [new JsonEncoder()]); $data = $serializer->serialize($this->getClass(), 'json'); return json_decode($data, true, 512, JSON_THROW_ON_ERROR); } catch (\Exception $oException) { return null; } } /** * Валидация Dto * * @param ResponseServiceInterface $response * * @return bool */ public function validate(ResponseServiceInterface $response): bool { $bValid = true; if ($classObj = $this->getClass()) { $aErrors = $this->validator->validate($classObj); if (count($aErrors) > 0) { foreach ($aErrors as $error) { $response->addError($error->getMessage()); $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); } $bValid = false; } } else { $response->addError("Данные не получены"); $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); $bValid = false; } return $bValid; } }