17/11/2018 - SYMFONY
API'niz yalnızca JSON istekleri içinse, daha güçlü olan JMS Serializer paketi yerine yerel Symfony serializer paketini kullanabilirsiniz. Kullanım için aşağıdaki örneğe bakın.
$ composer require symfony/serializer
$ composer require symfony/property-info
$ composer require symfony/validator
# services.yaml
services:
...
Symfony\Component\Serializer\Normalizer\PropertyNormalizer:
arguments:
$nameConverter: '@serializer.name_converter.camel_case_to_snake_case'
$propertyTypeExtractor: '@property_info.php_doc_extractor'
tags: [serializer.normalizer]
namespace App\Util;
use Exception;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class RequestUtil
{
private $serializer;
private $validator;
private $violator;
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
ViolationUtil $violator
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->violator = $violator;
}
public function validate(string $data, string $model): object
{
if (!$data) {
throw new BadRequestHttpException('Empty body.');
}
try {
$object = $this->serializer->deserialize($data, $model, 'json');
} catch (Exception $e) {
throw new BadRequestHttpException('Invalid body.');
}
$errors = $this->validator->validate($object);
if ($errors->count()) {
throw new BadRequestHttpException(json_encode($this->violator->build($errors)));
}
return $object;
}
}
declare(strict_types=1);
namespace Inanzzz\RequestResponseHandler\Util;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationListInterface;
class ViolationUtil implements ViolationUtilInterface
{
private $textUtil;
public function __construct(TextUtilInterface $textUtil)
{
$this->textUtil = $textUtil;
}
public function build(ConstraintViolationListInterface $violations): array
{
$errors = [];
/** @var ConstraintViolation $violation */
foreach ($violations as $violation) {
$errors[
$this->textUtil->makeSnakeCase($violation->getPropertyPath())
] = $violation->getMessage();
}
return $this->buildMessages($errors);
}
private function buildMessages(array $errors): array
{
$result = [];
foreach ($errors as $path => $message) {
$temp = &$result;
foreach (explode('.', $path) as $key) {
preg_match('/(.*)(\[.*?\])/', $key, $matches);
if ($matches) {
$index = str_replace(['[', ']'], '', $matches[2]);
$temp = &$temp[$matches[1]][$index];
} else {
$temp = &$temp[$key];
}
}
$temp = $message;
}
return $result;
}
}
declare(strict_types=1);
namespace Inanzzz\RequestResponseHandler\Util;
class TextUtil implements TextUtilInterface
{
public function makeSnakeCase(string $text): string
{
if (!trim($text)) {
return $text;
}
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $text));
}
}
namespace App\Util;
use Symfony\Component\Serializer\SerializerInterface;
class ResponseUtil implements ResponseUtilInterface
{
private $serializer;
public function __construct(
SerializerInterface $serializer
) {
$this->serializer = $serializer;
}
public function serialize(object $model): string
{
return $this->serializer->serialize($model, 'json');
}
}
namespace App\Model\User\Update;
use Symfony\Component\Validator\Constraints as Assert;
class User
{
/**
* @var string
*
* @Assert\Type("string")
* @Assert\NotBlank
*/
public $fullName;
/**
* @var iterable
*
* @Assert\Type("iterable")
*/
public $favouriteTeams;
/**
* @var iterable
*
* @Assert\Type("iterable")
*/
public $randomData;
/**
* @var Address
*
* @Assert\NotBlank
* @Assert\Type("App\Model\User\Update\Address")
* @Assert\Valid
*/
public $address;
}
namespace App\Model\User\Update;
use Symfony\Component\Validator\Constraints as Assert;
class Address
{
/**
* @var int
*
* @Assert\Type("int")
* @Assert\NotBlank
*/
public $houseNumber;
/**
* @var string
*
* @Assert\Type("string")
* @Assert\NotBlank
*/
public $line1;
/**
* @var string
*
* @Assert\Type("string")
*/
public $line2;
/**
* @var iterable
*
* @Assert\Type("iterable")
* @Assert\Count(max=2)
*/
public $flats;
/**
* @var Occupier[]
*
* @Assert\NotBlank
* @Assert\Type("iterable")
* @Assert\Valid
*/
public $occupiers;
}
namespace App\Model\User\Update;
use Symfony\Component\Validator\Constraints as Assert;
class Occupier
{
/**
* @var string
*
* @Assert\Type("string")
* @Assert\NotBlank
*/
public $fullName;
/**
* @var string
*
* @Assert\Type("string")
* @Assert\NotBlank
*/
public $sex;
}
# Deserialize request as User model and validate it
$userModel = $this->requestUtil->validate($request->getContent(), User::class);
# Serilize User object as JSON string
$userJsonString = $this->responseUtil->serialize($userModel);
# Return response
return new Response($result, 200, ['Content-Type' => 'application/json']);
{
"full_name": "John Travolta",
"favourite_teams": [
"Fenerbahce",
"Arsenal"
],
"random_data": {
"hair_style": "Curly",
"eye_colour": "Brown",
"allergies": [
"Nuts",
"Shellfish"
]
},
"address": {
"house_number": 184,
"line1": "House 101",
"line2": "",
"flats": [
"A",
"B"
],
"occupiers": [
{
"full_name": "Robert DeNiro",
"sex": "Male"
},
{
"full_name": "Sharon Stone",
"sex": "Female"
}
]
}
}