Skip to content
Snippets Groups Projects
BaseDto.php 3.93 KiB
Newer Older
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
<?php

namespace App\Service\Dto;

use App\Service\Response\ResponseServiceInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
use Symfony\Component\HttpFoundation\Response;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
use Symfony\Component\Serializer\Annotation\Ignore;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
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;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
use Symfony\Contracts\Service\Attribute\Required;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed

abstract class BaseDto implements DtoServiceInterface
{
    private ?Request $request = null;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
    private ?ValidatorInterface $validator = null;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
    #[Required]
    public function initValidator(
        ?ValidatorInterface $validator
    ): void
    {
        $this->validator = $validator;
    }

    #[Required]
    public function initRequest(
        ?RequestStack $requestStack = null
    ): void
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
    {
        if ($requestStack) {
            $this->request = $requestStack->getCurrentRequest();
        }
    }


    /**
     * Получение класса Dto
     *
     * @return DtoServiceInterface|null
     */
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
    #[Ignore]
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
    public function getClass(): ?DtoServiceInterface
    {
        if ($this->request) {
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            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()]
                );
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
                return $serializer->deserialize($data, static::class, 'json');
            } catch (\Exception $exception) {
                return null;
            }
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
        }
        return null;
    }

    public function toArray(): ?array
    {
        try {
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            $normalizer = new ObjectNormalizer(
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
                null,
                new CamelCaseToSnakeCaseNameConverter(),
                null,
                new ReflectionExtractor()
            );
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
            $data = $serializer->serialize($this->getClass(), 'json');
            return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
        } 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) {
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
                    $response->addError($error->getMessage());
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
                    $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
                }
                $bValid = false;
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            }
        } else {
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            $response->addError("Данные не получены");
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
            $bValid = false;
        }
i.vasilenko@iq-adv.ru's avatar
i.vasilenko@iq-adv.ru committed
        return $bValid;
    }
}