Merge remote-tracking branch 'origin/master' into fix-person-tests

This commit is contained in:
2021-05-26 22:44:45 +02:00
148 changed files with 7220 additions and 1192 deletions

View File

@@ -13,6 +13,9 @@ API
Chill provides a basic framework to build REST api.
Basic configuration
*******************
Configure a route
=================
@@ -34,7 +37,7 @@ You can also:
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
Auto-loading the routes
***********************
=======================
Ensure that those lines are present in your file `app/config/routing.yml`:
@@ -47,7 +50,7 @@ Ensure that those lines are present in your file `app/config/routing.yml`:
Create your model
*****************
=================
Create your model on the usual way:
@@ -87,7 +90,7 @@ Create your model on the usual way:
Configure api
*************
=============
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
@@ -171,7 +174,7 @@ Configure the api using Yaml (see the full configuration: :ref:`api_full_configu
}
The :code:`_index` and :code:`_entity` action
=============================================
*********************************************
The :code:`_index` and :code:`_entity` action are default actions:
@@ -189,7 +192,7 @@ Entity:
Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}`
Role
====
****
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
@@ -216,7 +219,7 @@ You can also define a role for each method. In this case, this role is used for
HEAD: MY ROLE_SEE
Customize the controller
========================
************************
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
@@ -264,7 +267,7 @@ And set your controller in configuration:
HEAD: true
Create your own actions
=======================
***********************
You can add your own actions:
@@ -361,8 +364,297 @@ Then, create the corresponding action into your controller:
}
}
Managing association
********************
ManyToOne association
=====================
In ManyToOne association, you can add associated entities using the :code:`PATCH` request. By default, the serializer deserialize entities only with their id and discriminator type, if any.
Example:
.. code-block:: bash
curl -X 'PATCH' \
'http://localhost:8001/api/1.0/person/accompanying-course/2668.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
# see the data sent to the server: \
-d '{
"type": "accompanying_period",
"id": 2668,
"origin": { "id": 11 }
}'
ManyToMany associations
=======================
In OneToMany association, you can easily create route for adding and removing entities, using :code:`POST` and :code:`DELETE` requests.
Prepare your entity, creating the methods :code:`addYourEntity` and :code:`removeYourEntity`:
.. code-block:: php
namespace Chill\PersonBundle\Entity;
use Chill\MainBundle\Entity\Scope;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/**
* AccompanyingPeriod Class
*
* @ORM\Entity
* @ORM\Table(name="chill_person_accompanying_period")
* @DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period"=AccompanyingPeriod::class
* })
*/
class AccompanyingPeriod
{
/**
* @var Collection
* @ORM\ManyToMany(
* targetEntity=Scope::class,
* cascade={}
* )
* @Groups({"read"})
*/
private $scopes;
public function addScope(Scope $scope): self
{
$this->scopes[] = $scope;
return $this;
}
public function removeScope(Scope $scope): void
{
$this->scopes->removeElement($scope);
}
Create your route into the configuration:
.. code-block:: yaml
chill_main:
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
scope:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
PATCH: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
PATCH: null
controller_action: null
path: null
single-collection: single
This will create a new route, which will accept two methods: DELETE and POST:
.. code-block:: raw
+--------------+---------------------------------------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------------------------------------+
| Route Name | chill_api_single_accompanying_course_scope |
| Path | /api/1.0/person/accompanying-course/{id}/scope.{_format} |
| Path Regex | {^/api/1\.0/person/accompanying\-course/(?P<id>[^/]++)/scope\.(?P<_format>[^/]++)$}sD |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | POST|DELETE |
| Requirements | {id}: \d+ |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: csapi_accompanying_course_controller:scopeApi |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
+--------------+---------------------------------------------------------------------------------------+
Then, create the controller action. Call the method:
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Entity\Scope;
class MyController extends ApiController
{
public function scopeApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, [ 'groups' => [ 'read' ] ]);
}
}
This will allow to add a scope by his id, and delete them.
Curl requests:
.. code-block:: bash
# add a scope with id 5
curl -X 'POST' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"type": "scope",
"id": 5
}'
# remove a scope with id 5
curl -X 'DELETE' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"id": 5,
"type": "scope"
}'
Deserializing an association where multiple types are allowed
=============================================================
Sometimes, multiples types are allowed as association to one entity:
.. code-block:: php
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM;
class Resource
{
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @ORM\JoinColumn(nullable=true)
*/
private $thirdParty;
/**
* @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\JoinColumn(nullable=true)
*/
private $person;
/**
*
* @param $resource Person|ThirdParty
*/
public function setResource($resource): self
{
// ...
}
/**
* @return ThirdParty|Person
* @Groups({"read", "write"})
*/
public function getResource()
{
return $this->person ?? $this->thirdParty;
}
}
This is not well taken into account by the Symfony serializer natively.
You must, then, create your own CustomNormalizer. You can help yourself using this:
.. code-block:: php
namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use Symfony\Component\Serializer\Exception;
use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer;
class AccompanyingPeriodResourceNormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
use DenormalizerAwareTrait;
use ObjectToPopulateTrait;
public function __construct(ResourceRepository $repository)
{
$this->repository = $repository;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
// .. snipped for brevity
if ($resource === NULL) {
$resource = new Resource();
}
if (\array_key_exists('resource', $data)) {
$res = $this->denormalizer->denormalize(
$data['resource'],
// call for a "multiple type"
DiscriminatedObjectDenormalizer::TYPE,
$format,
// into the context, we add the list of allowed types:
[
DiscriminatedObjectDenormalizer::ALLOWED_TYPES =>
[
Person::class, ThirdParty::class
]
]
);
$resource->setResource($res);
}
return $resource;
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $type === Resource::class;
}
}
Serialization for collection
============================
****************************
A specific model has been defined for returning collection:
@@ -381,8 +673,9 @@ A specific model has been defined for returning collection:
}
}
Where this is relevant, this model should be re-used in custom controller actions.
This can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`).
In custom actions, this can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`).
.. code-block:: php
@@ -400,10 +693,11 @@ This can be achieved quickly by assembling results into a :code:`Chill\MainBundl
}
}
.. _api_full_configuration:
Full configuration example
==========================
**************************
.. code-block:: yaml

View File

@@ -82,7 +82,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
.. code-block:: bash
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load --purge-with-truncate
There are several users available: