📜 ⬆️ ⬇️

Symfony: processing requests in the API

image

I think it’s not a secret for many that the Form component is not suitable for working in an API,
Everyone invents his own bike for replacement, I decided to share one of these bikes. I do not pretend to the title of “better solution”, but if my decision turns out to be useful to someone, or I receive new knowledge, it will be very cool.

In our API, each request is processed using a model, whether it is the essence of the doctrine or just the class. Therefore, the solution is built around annotations inside these models.

A model might look something like this:
')
Model listing
<?php namespace Common\Model; use Common\Constraint as AppAssert; use Symfony\Component\Validator\Constraints as Assert; use Troytft\DataMapperBundle\Annotation\DataMapper; class PostsFilter { /** * @DataMapper(type="string") */ protected $query; /** * @DataMapper(type="entity", options={"class": "CommonBundle:City"}) * @Assert\NotBlank */ protected $city; /** * @return mixed */ public function getCity() { return $this->city; } /** * @param mixed $value */ public function setCity($value) { $this->city = $value; return $this; } /** * @return string */ public function getQuery() { return $this->query; } /** * @param string $value */ public function setQuery($value) { $this->query = $value; return $this; } } 


The annotation takes the following parameters:
- name (optional parameter, name of the field in the request)
- type (optional parameter, field type, possible values: string, integer, float, boolean, timestamp, array, entity, array_of_entity)
- groups (optional parameter, scope of request, needed, if the same model is used in different places, but with a different set of fields)

And now what it looks like in the controller:

 /** @var Request $request */ $request = $this->get('request'); $data = $request->getRealMethod() == 'GET' ? $request->query->all() : $request->request->all(); /** @var DataMapperManager $manager */ $manager = $this->get('data_mapper.manager'); $model = $manager ->setGroups($groups) ->setValidationGroups($validationGroups) ->setIsClearMissing($clearMissing) ->setIsValidate(true) ->handle($model, $data); 


The manager himself will smudge all the data on the model, start validation, and if it fails, throw an exception.

If we talk about real use, then all the controller code is put into the base controller, and inside the real actions, the code becomes extremely small:

 public function createAction() { $user = $this->getUser(); $entity = $this->save($this->handleRequest(new Common\Entity\Blog\Post($this->getUser()))); $this->getNotificationManager()->notifyModerators($entity); return $entity; } 


Project Code:
- github: github.com/Troytft/data-mapper
- packagist: packagist.org/packages/troytft/data-mapper-bundle

Source: https://habr.com/ru/post/281875/


All Articles