<?php
namespace EADPlataforma\Requests;
use EADPlataforma\Enum\ContentTypeEnum;
use EADPlataforma\Error\ActionInvalidException;
use EADPlataforma\Error\FieldException;
use EADPlataforma\Error\EmptyBodyException;
use EADPlataforma\Error\UnsupportedContentTypeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
abstract class BaseRequest
{
protected $validator;
/**
* @var Request
*/
public $request;
/**
* @var array
*/
public $data;
/**
* @var string
*/
private $method;
/**
* @var string|null
*/
private $contentType;
/**
* @var array
*/
private $routeParams;
/**
* @var bool
*/
private $isFormData;
/**
* @throws ActionInvalidException
* @throws EmptyBodyException
* @throws UnsupportedContentTypeException
*/
public function __construct(ValidatorInterface $validator, Request $request)
{
$this->validator = $validator;
$this->request = $request;
$this->method = $request->getMethod();
$this->contentType = $request->headers->get('Content-Type');
$this->routeParams = $request->attributes->get('_route_params');
$this->isFormData = stristr($this->contentType, ContentTypeEnum::MULTPART_FORMDATA);
if(
$this->method !== Request::METHOD_GET &&
$this->contentType !== ContentTypeEnum::APPLICATION_JSON &&
!$this->isFormData
){
throw new UnsupportedContentTypeException;
}
//TO DO -> Change switch to MATCH in php 8
switch ($this->method)
{
case Request::METHOD_GET:
$this->data = $this->request->query->all();
break;
case Request::METHOD_DELETE:
$this->data = $this->request->attributes->get('_route_params');
break;
default:
$this->data = $this->getData();
break;
}
$this->populate();
if ($this->autoValidateRequest()) {
$this->validate();
}
}
public function getData(): ?array
{
if(!$this->isFormData){
return $this->request->toArray();
}
$data = $this->request->request->all();
foreach ($this->request->files as $key => $file) {
$data[$key] = $file;
}
return $data;
}
/**
* @throws ActionInvalidException
* @throws EmptyBodyException
*/
public function validate()
{
if(
(
$this->method !== Request::METHOD_GET &&
$this->method !== Request::METHOD_DELETE
) && empty($this->data)
){
throw new EmptyBodyException("Empty request body");
}
$errors = $this->validator->validate($this);
$messages = ['errors' => []];
/** @var ConstraintViolation $errors */
foreach ($errors as $message) {
$messages['errors'][] = [
'property' => $message->getPropertyPath(),
'value' => $message->getInvalidValue(),
'message' => $message->getMessage(),
];
}
if (count($messages['errors']) > 0) {
throw new FieldException("FieldException", $messages['errors']);
}
}
protected function populate(): void
{
if(isset($this->routeParams)) {
$this->data = array_merge($this->data, $this->routeParams);
}
foreach ($this->data as $property => $value) {
if (property_exists($this, $property)) {
$this->{$property} = $value;
}
}
}
protected function autoValidateRequest(): bool
{
return true;
}
}