mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
748 lines
24 KiB
ReStructuredText
748 lines
24 KiB
ReStructuredText
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
|
Permission is granted to copy, distribute and/or modify this document
|
|
under the terms of the GNU Free Documentation License, Version 1.3
|
|
or any later version published by the Free Software Foundation;
|
|
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
|
A copy of the license is included in the section entitled "GNU
|
|
Free Documentation License".
|
|
|
|
.. _api:
|
|
|
|
API
|
|
###
|
|
|
|
Chill provides a basic framework to build REST api.
|
|
|
|
Basic configuration
|
|
*******************
|
|
|
|
Configure a route
|
|
=================
|
|
|
|
Follow those steps to build a REST api:
|
|
|
|
1. Create your model;
|
|
2. Configure the API;
|
|
|
|
You can also:
|
|
|
|
* hook into the controller to customize some steps;
|
|
* add more route and steps
|
|
|
|
.. note::
|
|
|
|
Useful links:
|
|
|
|
* `How to use annotation to configure serialization <https://symfony.com/doc/current/serializer.html>`_
|
|
* `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`:
|
|
|
|
|
|
.. code-block:: yaml
|
|
|
|
chill_cruds:
|
|
resource: 'chill_main_crud_route_loader:load'
|
|
type: service
|
|
|
|
|
|
Create your model
|
|
=================
|
|
|
|
Create your model on the usual way:
|
|
|
|
.. code-block:: php
|
|
|
|
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
|
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
|
|
/**
|
|
* @ORM\Entity(repositoryClass=OriginRepository::class)
|
|
* @ORM\Table(name="chill_person_accompanying_period_origin")
|
|
*/
|
|
class Origin
|
|
{
|
|
/**
|
|
* @ORM\Id
|
|
* @ORM\GeneratedValue
|
|
* @ORM\Column(type="integer")
|
|
*/
|
|
private $id;
|
|
|
|
/**
|
|
* @ORM\Column(type="json")
|
|
*/
|
|
private $label;
|
|
|
|
/**
|
|
* @ORM\Column(type="date_immutable", nullable=true)
|
|
*/
|
|
private $noActiveAfter;
|
|
|
|
// .. getters and setters
|
|
|
|
}
|
|
|
|
|
|
Configure api
|
|
=============
|
|
|
|
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/packages/chill_main.yaml
|
|
chill_main:
|
|
apis:
|
|
accompanying_period_origin:
|
|
base_path: '/api/1.0/person/accompanying-period/origin'
|
|
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
|
name: accompanying_period_origin
|
|
base_role: 'ROLE_USER'
|
|
actions:
|
|
_index:
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
_entity:
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
|
|
.. note::
|
|
|
|
If you are working on a shared bundle (aka "The chill bundles"), you should define your configuration inside the class :code:`ChillXXXXBundleExtension`, using the "prependConfig" feature:
|
|
|
|
.. code-block:: php
|
|
|
|
namespace Chill\PersonBundle\DependencyInjection;
|
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
/**
|
|
* Class ChillPersonExtension
|
|
* Loads and manages your bundle configuration
|
|
*
|
|
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
|
|
* @package Chill\PersonBundle\DependencyInjection
|
|
*/
|
|
class ChillPersonExtension extends Extension implements PrependExtensionInterface
|
|
{
|
|
public function prepend(ContainerBuilder $container)
|
|
{
|
|
$this->prependCruds($container);
|
|
}
|
|
|
|
/**
|
|
* @param ContainerBuilder $container
|
|
*/
|
|
protected function prependCruds(ContainerBuilder $container)
|
|
{
|
|
$container->prependExtensionConfig('chill_main', [
|
|
'apis' => [
|
|
[
|
|
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class,
|
|
'name' => 'accompanying_period_origin',
|
|
'base_path' => '/api/1.0/person/accompanying-period/origin',
|
|
'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
|
|
'base_role' => 'ROLE_USER',
|
|
'actions' => [
|
|
'_index' => [
|
|
'methods' => [
|
|
Request::METHOD_GET => true,
|
|
Request::METHOD_HEAD => true
|
|
],
|
|
],
|
|
'_entity' => [
|
|
'methods' => [
|
|
Request::METHOD_GET => true,
|
|
Request::METHOD_HEAD => true
|
|
]
|
|
],
|
|
]
|
|
]
|
|
]
|
|
]);
|
|
}
|
|
}
|
|
|
|
The :code:`_index` and :code:`_entity` action
|
|
*********************************************
|
|
|
|
The :code:`_index` and :code:`_entity` action are default actions:
|
|
|
|
* they will call a specific method in the default controller;
|
|
* they will generate defined routes:
|
|
|
|
Index:
|
|
Name: :code:`chill_api_single_accompanying_period_origin__index`
|
|
|
|
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
|
|
|
|
Entity:
|
|
Name: :code:`chill_api_single_accompanying_period_origin__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.
|
|
|
|
For index action, the role will be called with :code:`NULL` as :code:`$subject`. The retrieved entity will be the subject for single queries.
|
|
|
|
You can also define a role for each method. In this case, this role is used for the given method, and, if any, the base role is taken into account.
|
|
|
|
.. code-block:: yaml
|
|
|
|
# config/packages/chill_main.yaml
|
|
chill_main:
|
|
apis:
|
|
accompanying_period_origin:
|
|
base_path: '/api/1.0/person/bla/bla'
|
|
class: 'Chill\PersonBundle\Entity\Blah'
|
|
name: bla
|
|
actions:
|
|
_entity:
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
roles:
|
|
GET: MY_ROLE_SEE
|
|
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`.
|
|
|
|
|
|
.. code-block:: php
|
|
|
|
|
|
namespace Chill\PersonBundle\Controller;
|
|
|
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class OpeningApiController extends ApiController
|
|
{
|
|
protected function customizeQuery(string $action, Request $request, $qb): void
|
|
{
|
|
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
|
|
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
|
|
$qb->setParameter('now', new \DateTime('now'));
|
|
}
|
|
}
|
|
|
|
And set your controller in configuration:
|
|
|
|
.. code-block:: yaml
|
|
|
|
chill_main:
|
|
apis:
|
|
accompanying_period_origin:
|
|
base_path: '/api/1.0/person/accompanying-period/origin'
|
|
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
|
name: accompanying_period_origin
|
|
# add a controller
|
|
controller: 'Chill\PersonBundle\Controller\OpeningApiController'
|
|
base_role: 'ROLE_USER'
|
|
actions:
|
|
_index:
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
_entity:
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
|
|
Create your own actions
|
|
***********************
|
|
|
|
You can add your own actions:
|
|
|
|
.. 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:
|
|
# add a custom participation:
|
|
participation:
|
|
methods:
|
|
POST: true
|
|
DELETE: true
|
|
GET: false
|
|
HEAD: false
|
|
PUT: false
|
|
roles:
|
|
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
|
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
|
GET: null
|
|
HEAD: null
|
|
PUT: null
|
|
single-collection: single
|
|
|
|
The key :code:`single-collection` with value :code:`single` will add a :code:`/{id}/ + "action name"` (in this example, :code:`/{id}/participation`) into the path, after the base path. If the value is :code:`collection`, no id will be set, but the action name will be append to the path.
|
|
|
|
Then, create the corresponding action into your controller:
|
|
|
|
.. 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\PersonBundle\Entity\AccompanyingPeriod;
|
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
|
|
class AccompanyingCourseApiController extends ApiController
|
|
{
|
|
protected EventDispatcherInterface $eventDispatcher;
|
|
|
|
protected ValidatorInterface $validator;
|
|
|
|
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
|
|
{
|
|
$this->eventDispatcher = $eventDispatcher;
|
|
$this->validator = $validator;
|
|
}
|
|
|
|
public function participationApi($id, Request $request, $_format)
|
|
{
|
|
/** @var AccompanyingPeriod $accompanyingPeriod */
|
|
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
|
|
$person = $this->getSerializer()
|
|
->deserialize($request->getContent(), Person::class, $_format, []);
|
|
|
|
if (NULL === $person) {
|
|
throw new BadRequestException('person id not found');
|
|
}
|
|
|
|
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
|
|
|
|
switch ($request->getMethod()) {
|
|
case Request::METHOD_POST:
|
|
$participation = $accompanyingPeriod->addPerson($person);
|
|
break;
|
|
case Request::METHOD_DELETE:
|
|
$participation = $accompanyingPeriod->removePerson($person);
|
|
break;
|
|
default:
|
|
throw new BadRequestException("This method is not supported");
|
|
}
|
|
|
|
$errors = $this->validator->validate($accompanyingPeriod);
|
|
|
|
if ($errors->count() > 0) {
|
|
// only format accepted
|
|
return $this->json($errors);
|
|
}
|
|
|
|
$this->getDoctrine()->getManager()->flush();
|
|
|
|
return $this->json($participation);
|
|
}
|
|
}
|
|
|
|
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:
|
|
|
|
.. code-block:: json
|
|
|
|
{
|
|
"count": 49,
|
|
"results": [
|
|
],
|
|
"pagination": {
|
|
"more": true,
|
|
"next": "/api/1.0/search.json&q=xxxx......&page=2",
|
|
"previous": null,
|
|
"first": 0,
|
|
"items_per_page": 1
|
|
}
|
|
}
|
|
|
|
Where this is relevant, this model should be re-used in custom controller actions.
|
|
|
|
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
|
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Chill\MainBundle\Pagination\PaginatorInterface;
|
|
|
|
class MyController extends AbstractController
|
|
{
|
|
|
|
protected function serializeCollection(PaginatorInterface $paginator, $entities): Response
|
|
{
|
|
$model = new Collection($entities, $paginator);
|
|
|
|
return $this->json($model, Response::HTTP_OK, [], $context);
|
|
}
|
|
}
|
|
|
|
|
|
.. _api_full_configuration:
|
|
|
|
Full configuration example
|
|
**************************
|
|
|
|
.. code-block:: yaml
|
|
|
|
apis:
|
|
-
|
|
class: Chill\PersonBundle\Entity\AccompanyingPeriod
|
|
name: accompanying_course
|
|
base_path: /api/1.0/person/accompanying-course
|
|
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
|
|
actions:
|
|
_entity:
|
|
roles:
|
|
GET: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
|
HEAD: null
|
|
POST: null
|
|
DELETE: null
|
|
PUT: null
|
|
controller_action: null
|
|
path: null
|
|
single-collection: single
|
|
methods:
|
|
GET: true
|
|
HEAD: true
|
|
POST: false
|
|
DELETE: false
|
|
PUT: false
|
|
participation:
|
|
methods:
|
|
POST: true
|
|
DELETE: true
|
|
GET: false
|
|
HEAD: false
|
|
PUT: false
|
|
roles:
|
|
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
|
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
|
GET: null
|
|
HEAD: null
|
|
PUT: null
|
|
controller_action: null
|
|
# the requirements for the route. Will be set to `[ 'id' => '\d+' ]` if left empty.
|
|
requirements: []
|
|
path: null
|
|
single-collection: single
|
|
base_role: null
|
|
|
|
|