Bu abstract controller kullanıcıdan gelen isteklerin içeriklerini ve bu isteklerin content-type özelliklerini kontrol eder. Json veya XML kabul eder ve json olarak cevap verir. Daha fazla bilgi için diğer yazıları kontrol edebilirsiniz.


Composer.json


Composer ile "jms/serializer-bundle": "0.13.0" paketini yükleyin.


Controllers.yml


services:
application_backend.controller.abstract:
class: Application\BackendBundle\Controller\AbstractController
abstract: true
arguments:
- @serializer
- @validator
- @doctrine_common_inflector

application_backend.controller.api:
class: Application\BackendBundle\Controller\ApiController
parent: application_backend.controller.abstract

doctrine_common_inflector:
class: Doctrine\Common\Inflector\Inflector

AbstractController


namespace Application\BackendBundle\Controller;

use Doctrine\Common\Inflector\Inflector;
use JMS\Serializer\SerializationContext;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;

abstract class AbstractController
{
private $validContentTypes = ['application/json' => 'json', 'application/xml' => 'xml'];

protected $serializer;
protected $validator;
protected $inflector;

public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->inflector = $inflector;
}

/**
* @param string $contentType
*
* @return string|Response
*/
protected function validateContentType($contentType)
{
if (!isset($this->validContentTypes[$contentType])) {
return $this->createErrorResponse(
['content_type' => sprintf('Invalid content type %s.', $contentType)],
415
);
}

return $this->validContentTypes[$contentType];
}

/**
* @param string $payload
* @param string $model
* @param string $format
*
* @return object|Response
*/
protected function validatePayload($payload, $model, $format)
{
$payload = $this->serializer->deserialize($payload, $model, $format);

$errors = $this->validator->validate($payload);
if (count($errors)) {
return $this->createErrorResponse($errors, 400);
}

return $payload;
}

/**
* @param array|object $content
* @param int $status
*
* @return Response
*/
protected function createJsonResponse($content, $status = 200)
{
$context = new SerializationContext();
$context->setSerializeNull(false);

$response = $this->serializer->serialize($content, 'json', $context);

return new Response($response, $status, ['Content-Type' => 'application/json']);
}

/**
* @param array|ConstraintViolationListInterface $errors
* @param int $status
*
* @return Response
*/
private function createErrorResponse($errors, $status)
{
$errorList = null;

if ($errors instanceof ConstraintViolationList) {
foreach ($errors as $error) {
$error = $this->getErrorFromValidation($error);
$errorList[$error['key']] = $error['value'];
}
} else {
$errorList = $errors;
}

return $this->createJsonResponse(['errors' => $errorList], $status);
}

/**
* @param ConstraintViolationInterface $error
*
* @return array
*/
private function getErrorFromValidation($error)
{
$properties = $this->inflector->tableize($error->getPropertyPath());

return ['key' => $properties, 'value' => $error->getMessage()];
}
}

ApiController


namespace Application\BackendBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\Common\Inflector\Inflector;

/**
* @Route("api", service="application_backend.controller.api")
*/
class ApiController extends AbstractController
{
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector
) {
parent::__construct($serializer, $validator, $inflector);
}

/**
* @param Request $request
*
* @Method({"POST"})
* @Route("")
*
* @return JsonResponse|Response
*/
public function indexAction(Request $request)
{
$format = $this->validateContentType($request->headers->get('content_type'));
if ($format instanceof Response) {
return $format;
}

$device = $this->validatePayload(
$request->getContent(),
'Application\BackendBundle\Model\Api\Device',
$format
);
if ($device instanceof Response) {
return $device;
}

return $this->createJsonResponse($device);
}
}

Hatalı örnek isteklerin sonucu


415 Invalid content-type


{
"errors": {
"content_type": "Invalid content type application/jsonnnnn."
}
}

400 Bad request


{
"errors": {
"price": "The price field must have a valid format.",
"datetime": "The datetime must be in yyyy-mm-dd H:i:s format."
}
}