Skip to content

Instantly share code, notes, and snippets.

@cierzniak
Last active June 22, 2023 11:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cierzniak/b1d8524cbbbf5ae37b44ee6866a35353 to your computer and use it in GitHub Desktop.
Save cierzniak/b1d8524cbbbf5ae37b44ee6866a35353 to your computer and use it in GitHub Desktop.
Json Response Builder
<?php
declare(strict_types=1);
namespace App\Http\Response;
use App\Http\Request\ListPageRequest;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Webmozart\Assert\Assert;
final class JsonResponseBuilder
{
public function __construct(
private readonly SerializerInterface $serializer,
private array $errors = [],
private array $data = [],
private array $metadata = [],
private int $status = Response::HTTP_OK,
) {}
/** @param list<mixed>|mixed $data */
public function setData($data, array $skipFields = []): self
{
if (is_array($data)) {
/** @var object $x */
$this->data = array_map(fn (object $x): array => $this->serializeObject($x, $skipFields), $data);
return $this;
}
$this->data = $this->serializeObject($data, $skipFields);
return $this;
}
public function addPageMetadata(ListPageRequest $listPage, int $totalRecords): self
{
return $this
->addMetadata('page', $listPage->getPage())
->addMetadata('recordsPerPage', $listPage->getTake())
->addMetadata('numberOfPages', (int) ceil($totalRecords / $listPage->getTake()))
->addMetadata('totalRecords', $totalRecords)
;
}
public function addMetadata(string $key, string|int|bool $value): self
{
$this->metadata[$key] = $value;
return $this;
}
public function setStatus(int $status): self
{
Assert::inArray($status, array_keys(Response::$statusTexts));
$this->status = $status;
return $this;
}
public function build(): JsonResponse
{
$result = ['data' => $this->data];
if ($this->metadata) {
$result['meta'] = $this->metadata;
}
if ($this->errors) {
$result = ['errors' => $this->errors];
}
return new JsonResponse($result, $this->status, json: true);
}
private function serializeObject($object, array $skipFields): string
{
return $this->serializer->serialize(
$object,
JsonEncoder::FORMAT,
[
DateTimeNormalizer::FORMAT_KEY => DATE_ATOM,
AbstractNormalizer::IGNORED_ATTRIBUTES => $skipFields,
]
);
}
}
<?php
declare(strict_types=1);
namespace App\Http\Request;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints as Assert;
final class ListPageRequest
{
private const RECORDS_PER_PAGE = 20;
public int $recordsPerPage = self::RECORDS_PER_PAGE;
public function __construct(
#[Assert\Positive]
private readonly int $page,
) {}
public function getPage(): int
{
return $this->page;
}
public function getSkip(): int
{
return ($this->page - 1) * $this->recordsPerPage;
}
public function getTake(): int
{
return $this->recordsPerPage;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment