Bu örnekte symfony ile API şeklinde olan temel bir proje oluşturmayı göreceğiz. Bu tarz genelde AJAX kullanan projeler için idealdir. Json istek gelir, json sonuç geri verilir. İsteklerin doğrulanma kuralları, model class içinde belirtilmiştir. Form type kullanılmamaktadır. Json serialisation ve deserialisation işlemi, abstract controller içinde, JMS serialiser bundle yardımı ile yapılır. Serialise edilmiş olan classın propertyleri, Doctrine_Inflector ile "tableise" haline getirilir (örnek: $fullName => full_name).


Abstract Controller


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\Validator\ValidatorInterface;

abstract class AbstractController
{
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 $responseData
* @param int $status
*
* @return Response
*/
protected function createJsonResponse($responseData = '', $status = 200)
{
$context = new SerializationContext();
$context->setSerializeNull(false);

$jsonResponse = $this->serializer->serialize($responseData, 'json', $context);

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

/**
* @param $errors
* @param int $status
*
* @return Response
*/
protected function createJsonErrorResponse($errors, $status = 400)
{
$errorData = ['errors' => []];

foreach ($errors as $error) {
if ($error instanceof ConstraintViolationInterface) {
$preparedError = $this->getErrorFromValidation($error, $errorData);
} else {
$preparedError = ['key' => count($errorData['errors']), 'value' => $error];
}
$errorData['errors'][$preparedError['key']] = $preparedError['value'];
}

return $this->createJsonResponse($errorData, $status);
}

/**
* @param string $content
* @param string $class
*
* @return mixed|Response
*/
protected function validate($content, $class)
{
$content = $this->serializer->deserialize(
$content,
$class,
'json'
);

$errors = $this->validator->validate($content);
if (count($errors)) {
return $this->createJsonErrorResponse($errors);
}

return $content;
}

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

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

User Controller


namespace Application\BackendBundle\Controller;

use Application\BackendBundle\Service\UserServiceInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use JMS\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\Common\Inflector\Inflector;

/**
* @Route("user", service="application_backend.controller.user")
*/
class UserController extends AbstractController
{
const ROUTER_PREFIX = 'application_backend_user_';

private $router;
private $userService;

public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
Inflector $inflector,
RouterInterface $router,
UserServiceInterface $userService
) {
parent::__construct($serializer, $validator, $inflector);

$this->router = $router;
$this->userService = $userService;
}

/**
* @param Request $request
*
* @Route("")
* @Method({"GET"})
*
* @return Response
*/
public function listAction(Request $request)
{
$page = $request->query->get('page', 1);
$limit = $request->query->get('limit', 2);

return $this->createJsonResponse("USER list: $page - $limit");
}

/**
* @param Request $request
*
* @Route("")
* @Method({"POST"})
*
* @return Response
*/
public function createAction(Request $request)
{
$user = $this->validate(
$request->getContent(),
'Application\BackendBundle\Model\User\Create'
);
if ($user instanceof Response) {
return $user;
}

return $this->createJsonResponse("USER create");
}
}

Services.yml


services:
doctrine_common_inflector:
class: Doctrine\Common\Inflector\Inflector

Controllers.yml


services:
application_backend.controller.abstract:
class: Application\BackendBundle\Controller\AbstractController
abstract: true # Abstract enabled
arguments:
- @serializer # Enabled by JMS Serializer Bundle
- @validator # Enabled by the application by default
- @doctrine_common_inflector # Enabled by user

application_backend.controller.user:
class: Application\BackendBundle\Controller\UserController
parent: application_backend.controller.abstract # Parent abstract class
arguments:
- @router # Compulsory for urls
- @application_backend.service.user # User service

Install JMS Serialiser Bundle


Install "jms/serializer-bundle": "0.13.0" ve new JMS\SerializerBundle\JMSSerializerBundle() satırını AppKernel.php dosyası içindeki $bundles arrayına ekleyin.


User entity


namespace Application\BackendBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
* @ORM\Entity(repositoryClass="Application\BackendBundle\Repository\UserRepository")
* @ORM\Table(name="user")
* @UniqueEntity(fields="username", message="Username is already in use.")
*/
class User
{
/**
* @var int
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @ORM\Column(name="username", type="string", length=20, unique=true)
*/
protected $username;

/**
* @ORM\Column(name="password", type="string", length=40)
*/
protected $password;
}

User model


namespace Application\BackendBundle\Model\User;

use JMS\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Constraints as Assert;

class Create
{
/**
* @var string
*
* @Assert\NotBlank(message="Username is required")
* @Assert\Length(
* min="6", minMessage="Username cannot be less than {{ limit }} characters.",
* max="20", maxMessage="Username cannot be longer than {{ limit }} characters."
* )
*
* @Serializer\Type("string")
*/
public $username;

/**
* @var string
*
* @Assert\NotBlank(message="Password is required")
*
* @Serializer\Type("string")
*/
public $password;
}

Testler


Postman browser extension kullanarak aynı testleri yapabilirsiniz.


listAction() methodu için GET örnekleri




createAction() methodu için POST örnekleri