Tutoriel APEX: classe de programmation Apex et exemples de codage

Qu’est-ce que Apex dans Salesforce?

Apex est un langage de programmation orienté objet et fortement typé développé par Salesforce pour la création de logiciels en tant que service (SaaS) et de gestion de la Relation Client (CRM). Apex aide les développeurs à créer des applications SaaS tierces et à ajouter une logique métier aux événements système en fournissant un support de base de données back-end et des interfaces client-serveur.,

Apex aide les développeurs à ajouter une logique métier aux événements système tels que les clics sur les boutons, les mises à jour d’enregistrements associées et les pages Visualforce. Apex a une syntaxe similaire à Java.

dans ce tutoriel débutant Salesforce Apex, vous apprendrez les bases D’Apex comme –

  • Qu’est-ce Qu’Apex?,ge
  • quand le développeur doit-il choisir Apex
  • structure de travail D’Apex
  • syntaxe Apex
  • environnement de développement Apex
  • Type de données dans Apex
  • spécificateur D’accès Apex
  • mots-clés dans Apex
  • chaîne Apex
  • limites du Gouverneur Apex
  • Getter Apex et Setter
  • classe Apex
  • déclencheur Apex
  • classe batch dans Apex

Caractéristiques du langage de programmation Apex

Voici les caractéristiques importantes de Salesforce Apex:

  • Apex est un langage insensible à la casse.,
  • Vous pouvez effectuer des opérations DML telles que INSERT, UPDATE, UPSERT, DELETE sur les enregistrements sObject à l’aide d’apex.
  • Vous pouvez interroger les enregistrements sObject en utilisant SOQL(Salesforce object query language) et SOSL(Salesforce object search language) dans apex.
  • Vous permet de créer un test unitaire et de les exécuter pour vérifier la couverture et l’efficacité du code dans apex.
  • Apex s’exécute dans un environnement multi-locataire, et Salesforce a défini des limites de gouverneur qui empêchent un utilisateur de contrôler les ressources partagées., Tout code qui dépasse la limite du gouverneur salesforce échoue, une erreur s’affiche.
  • L’objet Salesforce peut être utilisé comme type de données dans apex. Par exemple –
    Account acc = new Account(); 

    ,ici le compte est un objet salesforce standard.

  • Apex se met automatiquement à niveau avec chaque version Salesforce.

quand le développeur doit-il choisir Apex

le code Apex ne doit être écrit que si un scénario métier est trop complexe et ne peut pas être implémenté à l’aide des fonctionnalités prédéfinies fournies par Salesforce.,

Voici les quelques scénarios où nous devons écrire du code apex:

  • pour créer des services web qui intègrent Salesforce avec d’autres applications.
  • pour implémenter une validation personnalisée sur sobjects.
  • pour exécuter une logique Apex personnalisée lorsqu’une opération DML est effectuée.
  • pour implémenter des fonctionnalités qui ne peuvent pas être implémentées à l’aide des flux de workflows existants et des fonctionnalités des constructeurs de processus.
  • pour configurer les services de messagerie, vous devez inclure le traitement du contenu, des en-têtes et des pièces jointes des e-mails à l’aide du code apex.,

structure de travail D’Apex

maintenant, dans ce tutoriel Apex, nous allons en apprendre davantage sur la structure de travail D’Apex:

Voici le flux d’actions pour un code apex:

  • Action du développeur: tout le code apex écrit par un développeur est compilé dans un ensemble d’instructions qui peuvent être comprises par apex runtime interpreter lorsque le développeur enregistre le code sur la plate-forme et que ces instructions sont ensuite enregistrées en tant que métadonnées sur la plate-forme.,
  • action de L’utilisateur final: lorsque l’événement utilisateur exécute un code apex, le serveur de plate-forme obtient les instructions compilées à partir des métadonnées et les exécute via l’interpréteur apex avant de renvoyer le résultat.

structure de travail D’Apex

syntaxe Apex

déclaration de variable:

comme Apex est un langage fortement typé, il est obligatoire de déclarer une variable avec datatype dans Apex.,

Par exemple

contact con = new contact(); 

ici, la variable con est déclarée avec contact en tant que type de données.

Requête SOQL:

SOQL est synonyme de salesforce objet langage de requête. SOQL est utilisé pour récupérer les enregistrements sObject de la base de données Salesforce. Par exemple –

Account acc = ; 

la requête ci-dessus récupère l’enregistrement du compte à partir de la base de données salesforce.

instruction Loop:

l’instruction Loop est utilisée pour parcourir les enregistrements d’une liste. Le nombre d’itérations est égal au nombre d’enregistrements dans la liste., Par exemple:

dans l’extrait de code ci-dessus, listOfAccounts est une variable de type de données list.

instruction de contrôle de flux:

L’instruction de contrôle de flux est bénéfique lorsque vous souhaitez exécuter certaines lignes du code en fonction de certaines conditions.

Par exemple:

l’extrait de code ci-dessus interroge les enregistrements de compte de la base de données et vérifie la taille de la liste.

instruction DML:

DML est synonyme de langage de manipulation de données. Les instructions DML sont utilisées pour manipuler les données de la base de données Salesforce., Par exemple –

Account acc = new Account(Name = ‘ Test Account’);Insert acc; //DML statement to create account record.

environnement de développement Apex

maintenant, dans ce tutoriel de programmation Apex, nous allons en apprendre davantage sur L’environnement de développement Apex:

le code Apex peut être développé dans sandbox et developer edition de Salesforce.

Il est recommandé de développer le code dans l’environnement sandbox, puis de le déployer dans l’environnement de production.

code Apex outils de développement: la Suite sont les trois outils disponibles pour développer l’apex code dans toutes les éditions de Salesforce.,

  • Force.com Console de développement
  • Force.com Editor
  • éditeur de Code dans L’interface utilisateur Salesforce

Type de données dans Apex

Voici les types de données pris en charge par apex:

Primitive:

Integer, Double, Long, Date, Date Time, String, ID et Boolean sont considérés comme des types de données primitifs.Tous les types de données primitifs sont transmis par valeur, pas par référence.,

Collections:

trois types de collections sont disponibles dans Apex

  • List: il s’agit d’une collection ordonnée de primitives, de sObjects, de collections ou d’objets Apex basés sur des index.
  • Set: une collection non ordonnée de primitives uniques.
  • Map: c’est une collection de clés primitives uniques qui correspondent à des valeurs uniques qui peuvent être des primitives, des sObjects, des collections ou des objets Apex.

sObject:

Il s’agit d’un type de données spécial dans Salesforce. Il est similaire à une table en SQL et contient des champs similaires aux colonnes en SQL.,

Enums

Enum est un type de données abstrait qui stocke une valeur d’un ensemble fini d’identifiants spécifiés

Classes

objets:

Il fait référence à tout type de données supporté par Apex.

Interfaces

spécificateur D’accès Apex

Voici le spécificateur d’accès pris en charge par apex:

Public:

Ce spécificateur d’accès donne accès à une classe, une méthode, une variable à utiliser par un apex dans un espace de noms.,

Private:

ce spécificateur d’accès donne accès à une classe, une méthode, une variable à utiliser localement ou dans la section de code, elle est définie. Toute la technique, les variables qui n’ont pas de spécificateur d’accès défini ont le spécificateur d’accès par défaut de privé.

protégé:

ce spécificateur d’accès donne accès à une méthode, variable à utiliser par toutes les classes internes dans la définition de la classe Apex.,

Global:

ce spécificateur d’accès donne accès à une classe, une méthode, une variable à utiliser par un apex dans un espace de noms ainsi qu’en dehors de l’espace de noms. Il est recommandé de ne pas utiliser de mot clé global jusqu’à ce que cela soit nécessaire.

Keywords in Apex

With sharing:

Si une classe est définie avec ce mot-clé, toutes les règles de partage s’appliquent à l’utilisateur actuel sont appliquées et si ce mot-clé est absent, le code s’exécute dans le contexte du système.,

Par exemple:

public with sharing class MyApexClass{// sharing rules enforced when code in this class execute}

sans partage:

Si une classe est définie avec ce mot-clé, toutes les règles de partage applicables à l’utilisateur actuel ne sont pas appliquées.

Par Exemple:

public without sharing class MyApexClass{// sharing rules is not enforced when code in this class execute}

Statique:

Une variable, la Méthode est définie avec le mot-clé static est initialisée une fois et associé à la classe. Les variables statiques, les méthodes peuvent être appelées directement par nom de classe sans créer l’instance d’une classe.

Fin:

Une constante, la Méthode est définie avec le mot-clé final ne peut pas être remplacée., Par exemple:

public class myCls {static final Integer INT_CONST = 10;}

Si vous essayez de remplacer la valeur de cette variable INT_CONST, vous obtiendrez un système d’exception.FinalException: la variable finale a déjà été initialisée.

Return:

Ce mot-clé renvoie une valeur à partir d’une méthode. Par exemple:

public String getName() {return 'Test' ;}

Null:

Il définit une constante null et peut être affectée à une variable. Par exemple

 Boolean b = null; 

Virtual:

Si une classe est définie avec un mot-clé virtuel, elle peut être étendue et remplacée.,

Résumé:

Si une classe est définie avec le mot clé abstract, il doit contenir au moins une méthode avec le mot clé abstract, et que la méthode ne devrait avoir qu’une signature.

Par exemple:

public abstract class MyAbstrtactClass {abstract Integer myAbstractMethod1();}

l’Apex de la Chaîne

Une chaîne de caractères est un ensemble de caractères, sans limite de caractères. Par exemple:

String name = 'Test';

Il existe plusieurs méthodes intégrées fournies par classe String dans salesforce., Voici les quelques fonctions fréquemment et principalement utilisées:

abbreviate(maxWidth):

Cette méthode tronque une chaîne à la longueur spécifiée et la renvoie si la longueur de la chaîne donnée est plus longue que la longueur spécifiée; sinon, elle renvoie la chaîne d’origine. Si la valeur de la variable maxWidth est inférieure à 4, cette méthode renvoie un système d’exception d’exécution.StringException: la largeur minimale de l’abréviation est 4

Par exemple:

String s = 'Hello World';String s2 = s.abbreviate(8);System.debug('s2'+s2); //Hello...

capitalize ():

Cette méthode convertit la première lettre d’une chaîne en casse de titre et la renvoie.,

Par exemple:

String s = 'hello;String s2 = s.capitalize();System.assertEquals('Hello', s2);

contient(chaîne):

Cette méthode renvoie true si la Chaîne de l’appel de la méthode contient la sous-chaîne spécifiée.

String name1 = 'test1';String name2 = 'test2';Boolean flag = name.contains(name2);System.debug('flag::',+flag); //true

equals(stringOrId):

Cette méthode renvoie true si le paramètre passé n’est pas null et indique la même séquence binaire de caractères que la chaîne qui appelle la méthode.

lors de la comparaison des valeurs D’Id, la longueur des ID peut ne pas être égale., Par exemple: si une chaîne qui représente 15 caractères id est comparée à un objet qui représente 18 caractères ID, cette méthode renvoie true. Par exemple:

dans l’exemple ci-dessus, la méthode equals compare 15 caractères object Id à 18 caractères object Id et si ces deux id représentent la même séquence binaire, il retournera true.

utilisez cette méthode pour effectuer des comparaisons sensibles à la casse.

escapeSingleQuotes(stringToEscape):

Cette méthode ajoute un caractère d’échappement (\) avant toute citation unique dans une chaîne et le renvoie., Cette méthode empêche L’injection SOQL lors de la création d’une requête SOQL dynamique. Cette méthode garantit que tous les guillemets simples sont considérés comme des chaînes englobantes, au lieu des commandes de base de données.

Par exemple:

String s = 'Hello Tom';system.debug(s); // Outputs 'Hello Tom'String escapedStr = String.escapeSingleQuotes(s);// Outputs \'Hello Tom\'

supprimer(chaîne):

Cette méthode supprime toutes les occurrence de la sous-chaîne de la Chaîne qui appelle la méthode et renvoie la chaîne obtenue.,

Par exemple:

String s1 = 'Salesforce and force.com';String s2 = s1.remove('force');System.debug( 's2'+ s2);// 'Sales and .com'

substring(startIndex):

Cette méthode renvoie une sous-chaîne commence par le caractère à startIndex s’étend jusqu’à la dernière de la chaîne.

Par Exemple:

String s1 = 'hamburger';String s2 = s1.substring(3);System.debug('s2'+s2); //burger

reverse():

Cette Méthode annule tous les caractères d’une chaîne de caractères et retourne. Par exemple:

String s = 'Hello';String s2 = s.reverse();System.debug('s2::::'+s2);// olleH // Hello

trim (): cette méthode supprime tous les espaces blancs d’une chaîne et la renvoie.

valueOf(toconvert):

Cette méthode renvoie la représentation en chaîne de l’objet passé.,

limites Apex Governor

les limites Apex governor sont les limites imposées par apex runtime engine pour s’assurer que tout code et processus Apex runway ne contrôlent pas les ressources partagées et ne violent pas le traitement pour les autres utilisateurs de l’environnement multitenant. Ces limites sont vérifiées par rapport à chaque transaction apex., Sont les suivantes gouverneur limites définies par salesforce sur chaque apex de la transaction:

Description Limit
requêtes SOQL qui peut être fait en mode synchrone transaction 100
requêtes SOQL qui peut être fait dans une transaction Asynchrone 200
Enregistrements qui peuvent être récupérées par une requête SOQL 50000
Enregistrements qui peuvent être récupérés par la Base de données.,getQueryLocator 10000
SOSL requêtes qui peuvent être faites dans un apex transaction 20
Enregistrements qui peuvent être récupérés par un SOSL requête 2000
DML qui peut être fait dans un apex transaction 150
Enregistrements qui peuvent être traitées comme un résultat d’une instruction DML, de l’Approbation.processus ou base de données.emptyRecycleBin 10000
Légendes qui peut être fait dans un apex de la transaction., 100
Cumulatif délai limite sur tous les textes sont en cours d’exécution dans un apex transaction 120 secondes
la Limite de l’apex des emplois qui peuvent être ajoutés à la file d’attente du Système.,enqueueJob 50
Execution time limit for each Apex transaction 10 minutes
Limit on characters that can be used in an apex class and trigger 1 million
CPU time limit for synchronous transaction 10,000 milliseconds
CPU time limit for asynchronous transaction 60,000 milliseconds

Apex Getter and Setter

Apex property is similar to apex variable. Getter and setter are necessary to an apex property., Getter et setter peuvent être utilisés pour exécuter du code avant que la valeur de la propriété ne soit accédée ou modifiée. Le code de l’accesseur get s’exécute lorsqu’une valeur de propriété est lue. Le code de l’accesseur set s’exécute lorsqu’une valeur de propriété est modifiée. Toute propriété ayant un accesseur get est considérée en lecture seule, toute propriété ayant un accesseur set est considérée comme écrivant uniquement toute propriété ayant à la fois un accesseur get et un accesseur set est considérée comme en lecture-écriture. Syntaxe d’une propriété apex:

public class myApexClass {// Property declarationaccess_modifierreturn_typeproperty_name {get {//code }set{//code}}

ici, access_modifier est le modificateur d’accès de la propriété. return_type est le type de données de la propriété., property_name est le nom de la propriété.

ci-dessous est un exemple d’une propriété apex ayant à la fois get et set accessor.

public class myApex{public String name{get{ return name;}set{ name = 'Test';}}}

ici, le nom de la propriété est name, et c’est une propriété publique, et il renvoie un type de données string.

Il n’est pas obligatoire d’avoir du code dans le bloc get et set. Ces blocs peuvent être laissés vides pour définir une propriété automatique. Par exemple:

public double MyReadWriteProp{ get; set; } 

accesseur Get et set peut également être défini avec leur modificateur d’accès., Si un accesseur est défini avec un modificateur, il remplace le modificateur d’accès pour la propriété. Par exemple:

public String name{private get; set;}// name is private for read and public to write.

classe Apex

Une classe apex est un modèle ou un modèle à partir duquel des objets sont créés. Un objet est l’instance d’une classe.

Il existe trois façons de créer des classes apex dans Salesforce:

Developer Console

Force.com class

page de détail de la classe Apex.

dans apex, vous pouvez définir une classe externe également appelée classe de niveau supérieur, et vous pouvez également définir des classes dans une classe externe appelée classes internes.,

Il est obligatoire d’utiliser modificateur d’accès comme global ou public dans la déclaration de l’extérieur de la classe.

Il n’est pas nécessaire d’utiliser le modificateur d’accès dans la déclaration des classes internes.

Une classe apex est définie à l’aide du mot-clé class suivi du nom de la classe.

Le mot-clé Extends est utilisé pour étendre une classe existante par une classe apex, et le mot-clé implements est utilisé pour implémenter une interface par une classe apex.

Salesforce Apex ne prend pas en charge plusieurs héritages, une classe apex ne peut étendre qu’une classe apex existante mais peut implémenter plusieurs interfaces.,

Un apex classe peut contenir de l’utilisateur défini par le constructeur, et si un constructeur n’est pas disponible, un constructeur par défaut est utilisé. Le code dans le constructeur s’exécute lorsqu’une instance d’une classe est créée.

syntaxe de la classe Apex exemple:

public class myApexClass{// variable declaration//constructorpublic myApexClass{}//methods declaration}

le nouveau mot-clé est utilisé pour créer une instance d’une classe apex. Voici la syntaxe pour créer une instance d’une classe apex.

myApexClass obj = new myApexClass();

déclencheur Apex

Les déclencheurs Apex vous permettent d’exécuter Apex personnalisé avant et après l’exécution d’une opération DML.,

Apex prend en charge deux types de déclencheurs:

avant les déclencheurs: ces déclencheurs sont utilisés pour valider et mettre à jour la valeur du champ avant que l’enregistrement ne soit enregistré dans la base de données.

après les déclencheurs: ces déclencheurs sont utilisés pour accéder aux champs(id d’enregistrement, champ LastModifiedDate) définis par le système après un enregistrement validé dans la base de données. La valeur de ces champs peut être utilisée pour modifier d’autres enregistrements. Les enregistrements qui se déclenchent après les déclencheurs sont en lecture seule.

il est recommandé d’écrire des déclencheurs volumineux. Un déclencheur volumineux peut traiter un seul enregistrement ainsi que plusieurs enregistrements à la fois.,

syntaxe d’un déclencheur apex:

trigger TriggerName on ObjectName (trigger_events) {//Code_block }

ici, TriggerName est le nom du déclencheur, ObjectName est le nom de l’objet sur lequel le déclencheur doit être écrit, trigger_events est la liste des événements séparés par des virgules.

ce qui Suit sont les événements pris en charge par l’apex déclencheurs: avant d’insérer, avant la mise à jour, avant de le supprimer, après l’insertion, après une mise à jour, après la suppression, après undelete.

Les mots-clés statiques ne peuvent pas être utilisés dans un déclencheur Apex. Tous les mots-clés applicables aux classes internes peuvent être utilisés dans un déclencheur Apex.,

Il existe une variable implicite définie par chaque déclencheur qui renvoie le contexte d’exécution. Ces variables sont définies dans le système. Classe de déclenchement. Ces variables sont appelées variables de contexte. La capture d’écran ci-dessous montre la variable de contexte prise en charge par Apex trigger.

ce qui Suit sont la prise en considération de la variable de contexte dans l’apex de déclenchement:

  • Ne pas utiliser le déclencheur.nouveau et déclencheur.ancien dans les opérations DML.
  • Détente.les nouveaux ne peuvent pas être supprimés.,
  • Détente.nouveau est en lecture seule.
  • Détente.nouvelle peut être utilisé pour modifier les valeurs des champs sur le même objet avant de déclencher uniquement.

Les captures d’écran ci-dessous répertorient les considérations relatives aux actions spécifiques dans différents événements de déclenchement.

Lot de la Classe dans l’Apex

Lot de la classe dans salesforce est utilisé pour traiter un grand nombre de dossiers qui dépasse le sommet du gouverneur de limites si elles sont traitées normalement. La classe Batch exécute le code de manière asynchrone.,

Voici les avantages de la classe batch:

  • La classe Batch traite les données en morceaux et si un morceau ne parvient pas à traiter avec succès, tous les morceaux traités avec succès ne sont pas annulés.
  • chaque bloc de données d’une classe batch traité avec un nouvel ensemble de limites de gouverneur qui garantissent que le code s’exécute dans les limites d’exécution du gouverneur.
  • Base de données. L’interface Batchable doit être implémentée par une classe apex pour être utilisée comme classe batch. Il fournit trois méthodes qui doivent être implémentées par la classe batch.,

Voici les trois méthodes fournies par Database. Batchable interface:

1.start ():

Cette méthode génère la portée des enregistrements ou des objets à traiter par la méthode d’interface execute. Lors de l’exécution de batch, il est appelé une seule fois. Cette méthode renvoie une base de données.Objet QueryLocator ou un itérable. Nombre d’enregistrements récupérés par requête SQL à l’aide de la base de données.L’objet QueryLocator est de 50 millions d’enregistrements, mais en utilisant un itérable, le nombre total d’enregistrements pouvant être récupérés par la requête SQL est de 50000 uniquement., Iterable est utilisé pour générer une portée complexe pour la classe batch.

la Syntaxe de la méthode de démarrage:

global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContextbc) {}

2.execute():

Cette méthode est utilisée pour le traitement de chaque bloc de données. Pour chaque bloc d’enregistrements exécuter la méthode est appelée. La taille de lot par défaut pour l’exécution est de 200 enregistrements. La méthode Execute prend deux arguments:

une référence à la base de données.BatchableContext objet,

Une liste de nessobjects, tel que le<sObject>, ou une liste de type paramétré., La syntaxe de la méthode d’exécution:

global void execute(Database.BatchableContext BC, list<P>){}

3.finish ():

la méthode finish est appelée une fois lors de l’exécution de la classe batch. Les opérations de Post-traitement peuvent être effectuées dans la méthode de finition. Par exemple: envoi de l’e-mail de confirmation. Cette méthode est appelée lorsque tout le lot est traité. Syntaxe de la méthode Finish:

global void finish(Database.BatchableContext BC){}

base de données.Objet BatchableContext:

chaque méthode de la base de données. L’interface Batchable a une référence à la base de données.Objet BatchableContext.

Cet objet est utilisé pour suivre la progression de la tâche.,

Voici les méthodes d’instance fournies par BatchableContext:

  • getChildJobId(): cette méthode renvoie l’ID d’un travail batch actuellement traité.
  • getJobId(): cette méthode renvoie L’ID du travail par lots.

Voici la syntaxe d’une classe batch:

Database.méthode executeBatch:

base de données.la méthode executeBatch est utilisée pour exécuter une classe batch.

Cette méthode prend deux paramètres: Instance de la classe batch à traiter, paramètre Options pour spécifier la taille du lot si elle n’est pas spécifiée, elle prend la taille par défaut de 200.,

syntaxe de la base de données.executeBatch :

Database.executeBatch(myBatchObject,scope)

l’Exécution d’un lot nom de la classe MyBatchClass :

MyBatchClassmyBatchObject = new MyBatchClass(); Id batchId = Database.executeBatch(myBatchObject,100);

Base de données.stateful:

La classe Batch est sans état par défaut. Chaque fois que la méthode execute est appelé une nouvelle copie d’un objet est reçue, toutes les variables de la classe est initialisée.

la Base de données.stateful est implémenté pour rendre une classe batch stateful.

Si votre classe batch implémente la base de données, toutes les variables d’instance conservent leurs valeurs, mais les variables statiques sont réinitialisées entre la transaction.,

résumé:

  • Apex est un langage de programmation orienté objet fortement typé qui compile et s’exécute sur force.com plate-forme
  • Le langage de programmation Apex est un langage insensible à la casse
  • deux types de flux d’actions dans Apex sont 1) Action du développeur 2) action de l’utilisateur final
  • Apex vous aide à créer des services web qui intègrent Salesforce avec d’autres applications.
  • Les types de données pris en charge par apex sont: 1).,ublic, Private, Protected et Global sont spécifiés par Apex
  • Les mots-clés utilisés dans Apex sont : 1) avec Partage, 2) sans partage, 3) statique, 4) Final 5)Return, 6)Null, 7) virtuel, 8) abstrait
  • une chaîne est un ensemble de caractères sans limite de caractères
  • Les limites du gouverneur Apex sont les limites imposées par le moteur d’exécution apex pour s’assurer que tout code est accessible ou modifié
  • Il existe trois façons de créer des classes Apex dans Salesforce: 1)console développeur 2)Force.,com com et, 3) page de détail de la classe Apex.
  • Les déclencheurs Apex vous permettent d’exécuter Apex personnalisé avant et après l’exécution d’une opération DML.
  • La classe Batch dans salesforce est utilisée pour traiter un grand nombre d’enregistrements qui dépasseraient les limites du gouverneur apex s’ils étaient traités normalement.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *