Création d'une API REST sur Symfony

27 06 2017

16 commentaires

Création d'une API REST sur Symfony

Une API est conçue par des développeurs pour des développeurs. Le principe d'une API REST (Representational State Transfer) est de mettre à disposition des ressources à travers des url au format json ou xml. On met ainsi à disposition des url sur lesquelles un client Angular ou Symfony pourra venir effectuer des requêtes HTTP pour consommer cette API. Dans cette article nous allons voir comment créer une API REST avec Symfony.

Tout d'abord, il y a plusieurs niveaux pour définir une API REST. Les niveaux de conformité d'une API REST sont définis dans le modèle de maturité de Richardson.

  • niveau 0 : Le RPC sur HTTP en POX (Plain Old XML)
  • niveau 1 : L’utilisation de ressources différentiées
  • niveau 2 : L’utilisation des verbes HTTP
  • niveau 3 : L’utilisation des contrôles hypermédia

Une API qui répond aux 4 critères est dit pleinement REST ou Restful.

 

Utilité d'une API REST

L'utilité d'une API REST est de pouvoir lire des resources situées sur un serveur et de pouvoir les consommer depuis un autre serveur. L'échange de flux de données est ainsi qualifée de cross-domain. Pour cela nous aurons besoin de spécifier des entêtes spéciales pour autoriser un serveur à dialoguer avec un autre serveur. Car l'échange de flux de données cross-domain n'est pas autorisé par défaut. Pour cela nous aurons besoin de rajouter des entêtes spéciales de type CORS (Cross Origin Resource Sharing) avec notamment le control-access-allow-origin.

 

Configuration de Symfony

Pour créer une API REST avec Symfony, nous aurons besoin de 2 bundle:

  1. JMSSerializerBundle
  2. FOSRestBundle

JMSSerializerBundle va permettre de sérialiser les données au format json ou de les desérialiser en objet.

FOSRestBundle va permettre de simplifier la création de votre API REST grâce à une configuration spéciale de votre framework Symfony

Je n'expliquerai pas comment télécharger ces bundles, ni comment les activer. Pour cela consultez l'article Télécharger un bundle avec la commande require

Maintenant que ces 2 bundles ont été téléchargés et activés dans le appKernel.php, nous avons besoin de préciser dans le fichier config.yml la configuration de Symfony pour le bundle FOSRest:

fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener:
        rules:
            - { path: '^/api', priorities: ['json'], fallback_format: 'json' }
            - { path: '^/', priorities: ['html'], fallback_format: 'html' }
    view:
        view_response_listener: true
        formats:
            xml: true
            json : true
        templating_formats:
            html: true
        force_redirects:
            html: true
        failed_validation: HTTP_BAD_REQUEST
        default_engine: twig
    routing_loader:
        default_format: false
        include_format: false

 

Création d'une API REST

Nous allons maintenant créer notre controller placeController. Son rôle sera de pouvoir effectuer des actions sur des urls aux travers de verbes HTTP. Chaque action aura une méthode HTTP et une url qui lui sera propre. On pourra donc dire que notre API atteint le niveau 2 du modèle de maturité de Richardson.

Notre API va traité une entité Places qui contiendra 2 atrributs name et adress. Voici notre entité i:

<?php

namespace Blog\JournalBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Places
 * @ORM\Table(name="places", uniqueConstraints={@ORM\UniqueConstraint(name="places_name_unique",columns={"name"})})
 * @ORM\Entity(repositoryClass="Blog\JournalBundle\Repository\PlacesRepository")
 */
class Places
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="address", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $address;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Place
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set address
     *
     * @param string $address
     *
     * @return Place
     */
    public function setAddress($address)
    {
        $this->address = $address;

        return $this;
    }

    /**
     * Get address
     *
     * @return string
     */
    public function getAddress()
    {
        return $this->address;
    }
}

 

Et voici notre contrôleur placeController.php:

<?php
namespace Blog\JournalBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Blog\JournalBundle\Entity\Places;
use Blog\JournalBundle\Form\PlacesType;

class PlaceController extends Controller
{

    /**
     * @Rest\View()
     * @Rest\Get("/places")
     */
    public function getPlacesAction(Request $request)
    {
        $places = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->findAll();
        
    return $places;
    }

   /**
     * @Rest\View()
     * @Rest\Get("/places/{id}")
     */
    public function getPlaceAction(Request $request)
    {
        $place = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->find($request->get('id'));
        /* @var $place Place */

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        return $place;
    }

    /**
     * @Rest\View(statusCode=Response::HTTP_CREATED)
     * @Rest\Post("/places")
     */
    public function postPlaceAction(Request $request)
    {
        $place = new Places();
        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all());

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->persist($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }

     /**
     * @Rest\View(statusCode=Response::HTTP_NO_CONTENT)
     * @Rest\Delete("/places/{id}")
     */
    public function removePlaceAction(Request $request)
    {
        $em = $this->get('doctrine.orm.entity_manager');
        $place = $em->getRepository('JournalBundle:Places')
                    ->find($request->get('id'));
        /* @var $place Place */

        if ($place) {
            $em->remove($place);
            $em->flush();
        }
    }

    /**
     * @Rest\View()
     * @Rest\Put("/places/{id}")
     */
    public function updatePlaceAction(Request $request)
    {
        $em = $this->get('doctrine.orm.entity_manager');
        $place = $em->getRepository('JournalBundle:Places')
                    ->find($request->get('id'));

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all());

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->merge($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }

    /**
     * @Rest\View()
     * @Rest\Patch("/places/{id}")
     */
    public function patchPlaceAction(Request $request)
    {
        $place = $this->get('doctrine.orm.entity_manager')
                ->getRepository('JournalBundle:Places')
                ->find($request->get('id'));

        if (empty($place)) {
            return new JsonResponse(['message' => 'Place not found'], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(PlacesType::class, $place);

        $form->submit($request->request->all(), false);

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->merge($place);
            $em->flush();
            return $place;
        } else {
            return $form;
        }
    }
}

 

Notre API REST est à présent fonctionnelle. On va pouvoir tester notre API avec Postman. Puis nous pourrons consommer cette API avec un client comme Angular ou Symfony pour effectuer des requêtes dessus soit depuis le même serveur, soit depuis un autre serveur. Pour savoir comment faire vous pouvez lire notre article Consommer une API REST avec AngularJS.


 catégorie: Symfony


Commentaires

SLhaneitest posté le 06/03/2024 à 16:25

Aviator Spribe казино играть онлайн
I join. All above told the truth. Let's discuss this question.
Добро пожаловать в захватывающий мир авиаторов! Aviator – это увлекательная игра, которая позволит вам окунуться в атмосферу боевых действий на небе. Необычные графика и захватывающий сюжет сделают ваше путешествие по воздуху неповторимым.

Захватывайте крупные выигрыши с автоматом <a href=https://sites.google.com/view/krash-aviator-spribe/>Aviator Spribe играть на турнире</a> уже сегодня!
Aviator игра позволит вам почувствовать себя настоящим пилотом. Вам предстоит совершить невероятные маневры, выполнять сложные задания и сражаться с противниками. Улучшайте свой самолет, чтобы быть готовым к любым ситуациям и становиться настоящим мастером.
Основные особенности Aviator краш игры:
1. Реалистичная графика и физика – благодаря передовой графике и реалистичной физике вы почувствуете себя настоящим пилотом.
2. Разнообразные режимы игры и миссии – в Aviator краш игре вы сможете выбрать различные режимы игры, такие как гонки, симулятор полетов и захватывающие воздушные бои. Кроме того, каждая миссия будет предлагать свои собственные вызовы и задачи.
3. Улучшение и модернизация самолетов – в игре доступны различные модели самолетов, которые можно покупать и улучшать. Вы сможете устанавливать новое оборудование, улучшать двигательность и мощность своего самолета, а также выбирать различные варианты окраски и декорации.
Aviator краш игра – это возможность испытать себя в роли авиатора и преодолеть все сложности и опасности воздушного пространства. Почувствуйте настоящую свободу и адреналин в Aviator краш игре онлайн!
Играйте в «Авиатор» в онлайн-казино Pin-Up
Aviator краш игра онлайн предлагает увлекательную и захватывающую игровую атмосферу, где вы становитесь настоящим авиатором и сражаетесь с самыми опасными искусственными интеллектами.
В этой игре вы должны показать свое мастерство и смекалку, чтобы преодолеть сложности многочисленных локаций и уровней. Вам предстоит собирать бонусы, уклоняться от препятствий и сражаться с врагами, используя свои навыки пилотирования и стрельбы.
Каждый уровень игры Aviator краш имеет свою уникальную атмосферу и задачи. Будьте готовы к неожиданностям, так как вас ждут захватывающие повороты сюжета и сложные испытания. Найдите все пути к победе и станьте настоящим героем авиатором!
Авиатор игра является прекрасным способом провести время и испытать настоящий адреналиновый разряд. Готовы ли вы стать лучшим авиатором? Не упустите свой шанс и начните играть в Aviator краш прямо сейчас!
Aviator – играй, сражайся, побеждай!
Aviator Pin Up (Авиатор Пин Ап ) – игра на деньги онлайн Казахстан
Aviator игра предлагает увлекательное и захватывающее разнообразие врагов и уровней, которые не оставят равнодушными даже самых требовательных геймеров.
Враги в Aviator краш игре онлайн представлены в самых разных формах и размерах. Здесь вы встретите группы из маленьких и быстрых врагов, а также огромных боссов с мощным вооружением. Разнообразие врагов позволяет игрокам использовать разные тактики и стратегии для победы.
Кроме того, Aviator игра предлагает разнообразие уровней сложности. Выберите легкий уровень, чтобы насладиться игровым процессом, или вызовите себе настоящий вызов, выбрав экспертный уровень. Независимо от выбранного уровня сложности, вы получите максимум удовольствия от игры и окунетесь в захватывающий мир авиаторов.
Играйте в Aviator и наслаждайтесь разнообразием врагов и уровней, которые позволят вам почувствовать себя настоящим авиатором.


SLewisVet posté le 06/03/2024 à 16:40

Aviator Spribe играть на турнире
I like it topic
Добро пожаловать в захватывающий мир авиаторов! Aviator – это увлекательная игра, которая позволит вам окунуться в атмосферу боевых действий на небе. Необычные графика и захватывающий сюжет сделают ваше путешествие по воздуху неповторимым.

Получайте крупные денежные призы с игрой <a href=https://sites.google.com/view/krash-aviator-spribe/>Aviator Spribe играть на компьютере</a> прямо сейчас!
Aviator игра позволит вам почувствовать себя настоящим пилотом. Вам предстоит совершить невероятные маневры, выполнять сложные задания и сражаться с противниками. Улучшайте свой самолет, чтобы быть готовым к любым ситуациям и становиться настоящим мастером.
Основные особенности Aviator краш игры:
1. Реалистичная графика и физика – благодаря передовой графике и реалистичной физике вы почувствуете себя настоящим пилотом.
2. Разнообразные режимы игры и миссии – в Aviator краш игре вы сможете выбрать различные режимы игры, такие как гонки, симулятор полетов и захватывающие воздушные бои. Кроме того, каждая миссия будет предлагать свои собственные вызовы и задачи.
3. Улучшение и модернизация самолетов – в игре доступны различные модели самолетов, которые можно покупать и улучшать. Вы сможете устанавливать новое оборудование, улучшать двигательность и мощность своего самолета, а также выбирать различные варианты окраски и декорации.
Aviator краш игра – это возможность испытать себя в роли авиатора и преодолеть все сложности и опасности воздушного пространства. Почувствуйте настоящую свободу и адреналин в Aviator краш игре онлайн!
Играйте в «Авиатор» в онлайн-казино Pin-Up
Aviator краш игра онлайн предлагает увлекательную и захватывающую игровую атмосферу, где вы становитесь настоящим авиатором и сражаетесь с самыми опасными искусственными интеллектами.
В этой игре вы должны показать свое мастерство и смекалку, чтобы преодолеть сложности многочисленных локаций и уровней. Вам предстоит собирать бонусы, уклоняться от препятствий и сражаться с врагами, используя свои навыки пилотирования и стрельбы.
Каждый уровень игры Aviator краш имеет свою уникальную атмосферу и задачи. Будьте готовы к неожиданностям, так как вас ждут захватывающие повороты сюжета и сложные испытания. Найдите все пути к победе и станьте настоящим героем авиатором!
Авиатор игра является прекрасным способом провести время и испытать настоящий адреналиновый разряд. Готовы ли вы стать лучшим авиатором? Не упустите свой шанс и начните играть в Aviator краш прямо сейчас!
Aviator – играй, сражайся, побеждай!
Aviator Pin Up (Авиатор Пин Ап ) – игра на деньги онлайн Казахстан
Aviator игра предлагает увлекательное и захватывающее разнообразие врагов и уровней, которые не оставят равнодушными даже самых требовательных геймеров.
Враги в Aviator краш игре онлайн представлены в самых разных формах и размерах. Здесь вы встретите группы из маленьких и быстрых врагов, а также огромных боссов с мощным вооружением. Разнообразие врагов позволяет игрокам использовать разные тактики и стратегии для победы.
Кроме того, Aviator игра предлагает разнообразие уровней сложности. Выберите легкий уровень, чтобы насладиться игровым процессом, или вызовите себе настоящий вызов, выбрав экспертный уровень. Независимо от выбранного уровня сложности, вы получите максимум удовольствия от игры и окунетесь в захватывающий мир авиаторов.
Играйте в Aviator и наслаждайтесь разнообразием врагов и уровней, которые позволят вам почувствовать себя настоящим авиатором.


Earnestvot posté le 08/03/2024 à 09:16

Наша компания предлогает <a href=https://ilt.kz/in-top-kazakhstan/>Продвижение сайтов Актобе</a> включают SEO-оптимизацию, контент-маркетинг и аналитику для повышения онлайн-видимости вашего бизнеса.


SDichaelCLECE posté le 09/03/2024 à 19:02

Aviator Spribe играть на доллары казино
I am assured, that you on a false way.
Добро пожаловать в захватывающий мир авиаторов! Aviator – это увлекательная игра, которая позволит вам окунуться в атмосферу боевых действий на небе. Необычные графика и захватывающий сюжет сделают ваше путешествие по воздуху неповторимым.

Попробуйте свою удачу в игре <a href=https://sites.google.com/view/krash-aviator-spribe/>Aviator Spribe играть казино</a> и окунитесь в мир азартных приключений!
Aviator игра позволит вам почувствовать себя настоящим пилотом. Вам предстоит совершить невероятные маневры, выполнять сложные задания и сражаться с противниками. Улучшайте свой самолет, чтобы быть готовым к любым ситуациям и становиться настоящим мастером.
Основные особенности Aviator краш игры:
1. Реалистичная графика и физика – благодаря передовой графике и реалистичной физике вы почувствуете себя настоящим пилотом.
2. Разнообразные режимы игры и миссии – в Aviator краш игре вы сможете выбрать различные режимы игры, такие как гонки, симулятор полетов и захватывающие воздушные бои. Кроме того, каждая миссия будет предлагать свои собственные вызовы и задачи.
3. Улучшение и модернизация самолетов – в игре доступны различные модели самолетов, которые можно покупать и улучшать. Вы сможете устанавливать новое оборудование, улучшать двигательность и мощность своего самолета, а также выбирать различные варианты окраски и декорации.
Aviator краш игра – это возможность испытать себя в роли авиатора и преодолеть все сложности и опасности воздушного пространства. Почувствуйте настоящую свободу и адреналин в Aviator краш игре онлайн!
Играйте в «Авиатор» в онлайн-казино Pin-Up
Aviator краш игра онлайн предлагает увлекательную и захватывающую игровую атмосферу, где вы становитесь настоящим авиатором и сражаетесь с самыми опасными искусственными интеллектами.
В этой игре вы должны показать свое мастерство и смекалку, чтобы преодолеть сложности многочисленных локаций и уровней. Вам предстоит собирать бонусы, уклоняться от препятствий и сражаться с врагами, используя свои навыки пилотирования и стрельбы.
Каждый уровень игры Aviator краш имеет свою уникальную атмосферу и задачи. Будьте готовы к неожиданностям, так как вас ждут захватывающие повороты сюжета и сложные испытания. Найдите все пути к победе и станьте настоящим героем авиатором!
Авиатор игра является прекрасным способом провести время и испытать настоящий адреналиновый разряд. Готовы ли вы стать лучшим авиатором? Не упустите свой шанс и начните играть в Aviator краш прямо сейчас!
Aviator – играй, сражайся, побеждай!
Aviator Pin Up (Авиатор Пин Ап ) – игра на деньги онлайн Казахстан
Aviator игра предлагает увлекательное и захватывающее разнообразие врагов и уровней, которые не оставят равнодушными даже самых требовательных геймеров.
Враги в Aviator краш игре онлайн представлены в самых разных формах и размерах. Здесь вы встретите группы из маленьких и быстрых врагов, а также огромных боссов с мощным вооружением. Разнообразие врагов позволяет игрокам использовать разные тактики и стратегии для победы.
Кроме того, Aviator игра предлагает разнообразие уровней сложности. Выберите легкий уровень, чтобы насладиться игровым процессом, или вызовите себе настоящий вызов, выбрав экспертный уровень. Независимо от выбранного уровня сложности, вы получите максимум удовольствия от игры и окунетесь в захватывающий мир авиаторов.
Играйте в Aviator и наслаждайтесь разнообразием врагов и уровней, которые позволят вам почувствовать себя настоящим авиатором.


LewisVet posté le 13/03/2024 à 16:24

What's up i am kavin, its my first time to commenting anywhere, when i read this paragraph i thought i could also create comment due to this brilliant piece of writing.

http://www.google.nl/url?q=https://didvirtualnumbers.com/de/


LewisVet posté le 13/03/2024 à 20:25

Thanks for some other great post. Where else may just anybody get that kind of information in such an ideal method of writing? I have a presentation subsequent week, and I am at the look for such info.


http://images.google.bg/url?q=https://hottelecom.biz/id/


Jseralddix posté le 17/03/2024 à 10:09

True phrase
Подробно расскажем, как Ограничение родительских прав - Оренбургский районный суд г. Оренбурга онлайн или самостоятельно <a href="https://orenburgskij-rajonnyj-sud-orenburga.orenburgskaya-oblast.ru/zajavlenie/ogranichenie-roditelskih-prav/">Ограничение родительских прав - Оренбургский районный суд г. Оренбурга</a> Ограничение родительских прав - Оренбургский районный суд г. Оренбурга онлайн или самостоятельно


Fobertder posté le 17/03/2024 à 10:56

I think, that you are not right. I am assured. Write to me in PM, we will talk.
Подробно расскажем, как Взыскать компенсацию за задержку зарплаты - Саракташский районный суд Оренбургской области онлайн или самостоятельно <a href="https://saraktashskij-rajonnyj-sud.orenburgskaya-oblast.ru/zajavlenie/vzyskat-kompensaciyu-za-zaderzhku-zarplaty/">Взыскать компенсацию за задержку зарплаты - Саракташский районный суд Оренбургской области</a> Взыскать компенсацию за задержку зарплаты - Саракташский районный суд Оренбургской области онлайн или самостоятельно


SShaneitest posté le 17/03/2024 à 18:24

Tadalafilo Sandoz 20 Mg Precio
In my opinion you are mistaken. I can defend the position.
Cialis 5 mg prezzo <a href=https://comprarcialis5mg.com/it/>prezzo cialis 5 mg originale in farmacia</a> cialis 5 mg prezzo


Davdidteabs posté le 17/03/2024 à 18:31

Viagra Cialis
It is an amusing phrase
Cialis 5 mg prezzo <a href=https://comprarcialis5mg.com/it/>cialis prezzo</a> cialis 5 mg prezzo


SOLaneitest posté le 18/03/2024 à 18:10

In my opinion you commit an error. I can prove it. Write to me in PM.

<a href=https://ricardohnom16162.bligblogging.com/26174520/boosting-efficiency-with-digital-figures-the-hottelecom-advantage>аренда виртуального номера</a>


Davdidteabs posté le 19/03/2024 à 17:57

Aviator Spribe играть демо казино
Добро пожаловать в захватывающий мир авиаторов! Aviator – это увлекательная игра, которая позволит вам окунуться в атмосферу боевых действий на небе. Необычные графика и захватывающий сюжет сделают ваше путешествие по воздуху неповторимым.
<a href=https://sites.google.com/view/pin-up-aviator2024/>Aviator Spribe казино играть на гривны</a>


GichardHaicH posté le 22/03/2024 à 11:57

This is my first time pay a visit at here and i am really pleassant to read everthing at single place.

<a href=https://marcowxvq90112.snack-blog.com/25967771/se-puede-recetar-rybelsus-fuera-de-indicacion-para-el-manejo-del-peso>Rybelsus</a><a href=https://tysonyazu01223.life3dblog.com/25669293/rybelsus-assistance-program-accessing-financial-support>Rybelsus</a><a href=https://titusggcy12234.bligblogging.com/26498360/existen-estrategias-o-medicamentos-alternativos-recomendados-para-bajar-de-peso-en-lugar-de-rybelsus>Rybelsus</a><a href=https://jeffreykqss02357.bcbloggers.com/25781008/rybelsus-kidney-function-effects-on-renal-function>Rybelsus</a><a href=https://archervngx00099.blogchaat.com/26035726/cuales-son-las-indicaciones-especificas-que-un-medico-consideraria-para-recetar-rybelsus-con-el-proposito-de-perder-peso>Rybelsus</a>


LewisVet posté le 22/03/2024 à 17:03

Hmm is anyone else having problems with the pictures on this blog loading? I'm trying to find out if its a problem on my end or if it's the blog. Any responses would be greatly appreciated.

<a href=https://marcounfw99887.bligblogging.com/26506921/cual-es-la-eficacia-de-rybelsus-en-diferentes-grupos-de-edad-para-la-perdida-de-peso>Rybelsus</a>


Fobertder posté le 25/03/2024 à 12:28

I'm not sure exactly why but this site is loading very slow for me. Is anyone else having this problem or is it a problem on my end? I'll check back later on and see if the problem still exists.
<a href=https://sites.google.com/view/speedypaper2019/>writing service</a>


LewisVet posté le 28/03/2024 à 17:23

gama casino
<a href=https://dzschkola.ru>gama casino</a>



Laisser un commentaire