Développement Apex et Visualforce

5 925 vues

Publié le

PARTIE 1 - INSTALLER L'IDE SALESFORCE DANS ECLIPSE
PARTIE 2 - STRUCTURE D'UN PROJET
PARTIE 3 - DEPLOIEMENT D'UN PROJET A PARTIR D'ECLIPSE
PARTIE 4 - DEPLOYER UN PROJET DANS L'ENVIRONNEMENT DE PRODUCTION
PARTIE 5 - LES TRIGGERS
PARTIE 6 - LES CLASSES
PARTIE 7 - PROGRAMMATION APEX
PARTIE 8 - LE LANGAGE SOQL
PARTIE 9 - TEST METHODE
PARTIE 10 - VISUALFORCE

Publié dans : Technologie
1 commentaire
3 j’aime
Statistiques
Remarques
Aucun téléchargement
Vues
Nombre de vues
5 925
Sur SlideShare
0
Issues des intégrations
0
Intégrations
215
Actions
Partages
0
Téléchargements
264
Commentaires
1
J’aime
3
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Développement Apex et Visualforce

  1. 1. PROGRAMMATION APEX Auteur : Axel KAMALAK 18/06/2015 http://www.developpeurapex.eu 1
  2. 2. http://www.developpeurapex.eu 2
  3. 3. PROGRAMMATION APEX SOMMAIRE PARTIE 1 - INSTALLER L'IDE SALESFORCE DANS ECLIPSE PARTIE 2 - STRUCTURE D'UN PROJET PARTIE 3 - DEPLOIEMENT D'UN PROJET A PARTIR D'ECLIPSE PARTIE 4 - DEPLOYER UN PROJET DANS L'ENVIRONNEMENT DE PRODUCTION PARTIE 5 - LES TRIGGERS PARTIE 6 - LES CLASSES PARTIE 7 - PROGRAMMATION APEX PARTIE 8 - LE LANGAGE SOQL PARTIE 9 - TEST METHODE PARTIE 10 - VISUALFORCE PARTIE 11 - FAIRE UN APPEL WEBSERVICE PARTIE 1 - INSTALLER L'IDE SALESFORCE DANS ECLIPSE - Aller dans Eclipse Cliquer sur Help Cliquer sur Eclipse Marketplace Dans le champ "Find" ,Entrer " force.com " et cliquer sur le bouton " GO " Pour installer l'Ide, il faudra cliquer sur "Installer" 1.1-Créer un nouveau projet Sous Eclipse •Dans la zone de gauche, cliquer droit avec la souris •Cliquer sur New •Cliquer sur Force.com project Il faudra remplir le formulaire de la manière suivante: •Project name : le nom du projet (par exemple RBX_project_ABC ) •Username : votre nom utilisateur •Password : votre mot de passe •Security token : votre jeton de sécurité http://www.developpeurapex.eu 3
  4. 4. 1.2-Les environnements Il existe différents types d’environnement : •Sandbox : c'est un environnement de test réservé aux développeurs. Son adresse url est https://test.salesforce.com •Production : c’est un environnement de production réservé aux utilisateurs finaux. Son adresse url est https://login.salesforce.com 1.3-Le nom d’utilisateur Pour chaque environnement, le nom d'utilisateur est unique. •Pour l’environnement de test: il est préconisé de suffixer par le nom de la sandbox: julie.durand@abc.com.dev •Pour l’environnement de production: il est préconisé de ne pas suffixer le nom d'utilisateur: julie.durand@abc.com 1.4-Le jeton de sécurité Pour obtenir un jeton de sécurité, il faut aller sur l'environnement Salesforce. •Cliquer sur « Mes informations personnelles » •Cliquer sur « Réinitialiser mon jeton de sécurité » Un email contenant le jeton de sécurité arrive dans quelques secondes. Le jeton de sécurité est nécessaire pour un utilisateur qui se trouve en dehors de l'espace sécurisé Pour cette action, l'administrateur renseigne une plage d'IP sécurisé. 1.5-Plages de connexion IP Sur la fiche d'un profil, un administrateur peut saisir une plage d’IP sécurisée. Un utilisateur rattaché au profil peut se connecter à Salesforce sans avoir de jeton de sécurité. PARTIE 2 - STRUCTURE D'UN PROJET - Les principaux composants d'un projet sont : •Classes : ce sont toutes les classes du projet •Pages : ce sont les pages Visualforce •Triggers : ce sont les déclencheurs •Static ressources : ce sont les fichiers de Ressources ( js , css , image) que l'on charge sous Salesforce •Salesforce.schéma : on accède à la base de données via une application graphique. http://www.developpeurapex.eu 4
  5. 5. Eclipse propose un module pour créer les composants •Cliquer droit sur le nom du projet •Cliquer sur New •Cliquer sur le composant de votre choix PARTIE 3 - DEPLOIEMENT D'UN PROJET A PARTIR D'ECLIPSE - 3.1- Déployer Il est possible de déployer sous Salesforce à partir d’Eclipse. •Sélectionner les fichiers à déployer •Cliquer droit sur le fichier •Cliquer sur force.com •Cliquer sur Save to Server Le bouton enregistrer permet aussi de faire la même action. 3.2- Conflit de version Salesforce informe l'utilisateur qu'il a un conflit avec le code sur le serveur. •Sauvegarder votre code dans un autre fichier •Effectuer un rafraîchissement à partir du serveur pour récupérer la dernière version du document (Refresh from Server) •Insérer vos modifications dans le fichier Vous pouvez maintenant enregistrer. 3.3- Ecraser la version du serveur Le développeur peut écraser le fichier sur le serveur •Cliquer droit sur le nom du fichier •Cliquer sur force.com •Cliquer sur « Save to Server » http://www.developpeurapex.eu 5
  6. 6. PARTIE 4 - DEPLOYER UN PROJET DANS L'ENVIRONNEMENT DE PRODUCTION - Il est possible de faire une livraison sur l’environnement de production •Cliquer droit sur le nom du projet •Cliquer sur « Force.com » •Cliquer sur « Deploy to Server » •Entrer vos informations •Choisir « Production/ Developer Edition » 4.1-Vérifier la validité du paquet Pour vérifier que vos modifications sont valides et peuvent être déployés sous Salesforce : Cliquer sur « Validate Deployment » 4.2-Validation du paquet Salesforce valide le déploiement du paquet. Pour déployer le paquet, il faut cliquer sur le bouton "next". PARTIE 5 - LES TRIGGERS - Un objet peut avoir des triggers.Ce sont des déclencheurs qui vont générer une ou plusieurs actions. Le trigger se déclenche avant ou après une action spécifique d’un utilisateur sur un objet particulier. le trigger peut avoir plusieurs modes : •After update : après la mise à jour d’un objet •After insert : après insertion d’un nouvel objet •Before insert : avant l’insertion d’un nouvel objet •Before update : avant la mise à jour d’un objet •Before delete : avant la suppression d’un objet http://www.developpeurapex.eu 6
  7. 7. •After delete : après la suppression d’un objet 5.1- mode before ou mode after •mode before : un trigger en mode before s'utilise pour faire une action sur le même objet. Par exemple,pour la modification de la date de naissance du salarié. Le trigger calcule l'âge du salarié. •mode after : un trigger en mode after s'utilise pour faire une action sur un autre objet. Par exemple, à la modification du salaire , il faudra créer un nouvel enregistrement de type "HistoriqueSalaire__c" 5.2-Nomenclature conseillée trigger ABC_Account_BeforeInsert on Account__c (before insert) La nomenclature suivante est conseillée pour le nom du trigger •ABC : sigle de la société •Account : nom de l'objet •BeforeInsert : mode du trigger le mot clé "trigger" indique qu'il s'agit d'un trigger. le mot clé "before insert" indique le mode du trigger 5.3-Un exemple de trigger trigger ABC_Account_BeforeInsert on Account__c (before insert) { list<Account__c> listCompteUtilisateurs = new list<Account__c>(); for(Account__c eachCompte : trigger.new){ listCompteUtilisateurs.add(eachCompte); } if(!ABC_Utils.empty(listCompteUtilisateurs)){ ABC_Account.traiterCompte(listCompteUtilisateurs); } } 5.4-Filtrer les enregistrements Dans l'exemple précédente, nous appelons la méthode "traiterCompte" de la classe ABC_Account. La méthode "traiterCompte" va calculer les comptes dont le Montant__c est positif. Pour répondre à ce besoin,il faut rajouter un filtre dans le trigger. trigger ABC_Account_BeforeInsert on Account__c (before insert) { list<Account__c> listCompteUtilisateurs = new list<Account__c>(); for(Account__c eachCompte : trigger.new){ if(eachCompte.Montant__c >0) { listCompteUtilisateurs.add(eachCompte); } } if(!ABC_Utils.empty(listCompteUtilisateurs)){ ABC_Account.traiterCompte(listCompteUtilisateurs); } } PARTIE 6 - LES CLASSES - Une classe contient toutes les méthodes et les variables. 6.1-Type de classe •Privée : la classe ne peut pas être accessible par les autres classes et les déclencheurs. Salesforce refuse l’enregistrement. •Public : accessible à toutes les classes et déclencheurs du projet courant. http://www.developpeurapex.eu 7
  8. 8. •Global : accessible par toutes les classes apex de tous les projets ( partout ) •Virtual : la classe autorise l’héritage et la surcharge. •Abstract : la classe définit des méthodes abstraites. •Without sharing : indique que la classe ne respecte pas les règles de partage et les profiles de salesforce. •With sharing : indique que la classe respecte les règles de partage de Salesforce. 6.2-Les méthodes et les attributs : Les attributs se déclarent de la manière suivante : public String NomDuResponsable {get;set;} private Integer TotalChiffreAffaire {get;set;} •get;set l'accessibilité de la variable •String le type de la variable •public visibilité de la variable •NomDuResponsable nom de la variable 6.3-Les méthodes Les méthodes sont déclarées de la manière suivante : Accès type de retour nom (paramétre1, paramétre n){ return x ; } Exemple de méthode public static String formaterNombre(Integer s) { if(s<10) return '0'+s; else return String.valueOf(s); } PARTIE 7 - PROGRAMMATION APEX 7.1-Le langage Apex est un langage gouverné. Les langages traditionnels sont flexibles et peuvent demander au système de faire l’action x, y, z ….. Le langage Apex est un langage gouverné où il est possible de faire tout ce que le système autorise. 7.2-Les types de variable Il existe plusieurs types de données sous APEX : •Integer : entier (-2,147,483,648 à 2,147,483,647 ) •String : Chaine de caractère : String nomClient= ‘TEST_APEX’ •Boolean : true ou false •Date : les dates •Long •Décimal •Double •Blob : données binaire http://www.developpeurapex.eu 8
  9. 9. •ID : identifiant •Object :ce sont les objets •Integer : i = 50; 7.3-Les opérateurs 7.3.1-Les conditionnels 7.3.1.1-L’instruction if permet de faire un test booléen. Si la condition est respectée, alors on exécute une ou plusieurs actions. public static void formaterNombre(Integer s) { if(nbEssai<3) { nbTentative++; nbTest++; } } 7.3.1.2-L’instruction if – else permet de faire un test booléen. Si la condition est vraie, alors on exécute une ou plusieurs actions. Sinon on va exécuter d’autres actions. public static void formaterNombre(Integer s) { if(nbEssai<3) { nbTentative++; nbTest++; } else { estTerminee = true; } } 7.3.2-Les répétitives 7.3.2.1-L’instruction for L’instruction for permet de faire une action n fois. Syntaxe de l'instruction for for(indice de départ ; condition ; pas d'incrémentation) { instruction A; instruction B; instruction C: } Exemple de code public static void formaterNombre(Integer s) { for(integer i=0; i<50;i++) { http://www.developpeurapex.eu 9
  10. 10. System.debug('***Compter ' + i ); } } 7.3.2.2-L’instruction while L’instruction while permet de faire une ou plusieurs actions tant que la condition est respectée. Syntaxe de l'instruction while while(condition) { instruction A; instruction B; instruction C: } Exemple de code public static void compterLivre(Integer s) { nbLivre=s; while(nbLivre<50) { System.debug('***Livre ' + nbLivre ); nbLivre++; } } 7.4 - Les collections Une collection contient des éléments de même type. Les principaux méthodes d'une collection sont : •clear : effacer tout le contenu d’une collection •clone : retourner une copie de la collection •isEmpty : retourner false si la liste n’est pas vide . Sinon retourne true •size : retourner la taille de la collection •add : ajouter un élément dans la collection 7.4.1 - Les listes Le type List hérite de la collection. Une liste permet de stocker x éléments de même type. Elle peut contenir des doublons. Sa taille s’adapte automatiquement. Syntaxe : public List<Type> NomListes = new List<Type>(); Exemple de code list<Sportif__c> mesSportifs = new list<Sportif__c>(); mesSportifs= [Select Id,Name,FirstName__c ,Age__c from Sportif__c where Age__c >18]; 7.4.2 - Les sets Une collection de type Set permet de stocker un ensemble d’objet de même type de façon unitaire. C'est à dire, elle refuse les doublons. http://www.developpeurapex.eu 10
  11. 11. Syntaxe: public Set<Type> SetName = new Set<Type>(); 7.4.3 -Map Une map est une collection de paires clé valeurs. Chaque clé est unique pour une seule valeur. La clé et la valeur peuvent avoir différent type. La map suivante représente le code et le nom des produits : Clé B200 C300 D400 Valeur Poire Orange Citron Une map peut être déclarée de la manière suivante : map<Id, String> mapProduits = new map<Id, String>(); 7.4.3.1-Alimenter une map Il existe deux moyens pour alimenter une map. •Requête SOQL •boucle for et instruction put 7.4.3.1.1-Requête SOQL mapString<Id,UserString> users = new mapString<Id, UserString>([Select Id, Name From User where UserRoleId IN :allSubRoleIds]); 7.4.1.2-Boucle for et instruction put map<String,Id> mapRecordTypes = new map<String,Id>(); list<RecordType> listRecordType = [Select DEVELOPERNAME,Id from RecordType]; for(RecordType eachrecord :listRecordType ) { mapRecordTypes.put(eachrecord.DEVELOPERNAME , eachrecord.Id); } 7.4.1.3-Récupérer des valeurs à partir d'une map L'instruction get permet de recupérer l'identifiant du recordtype dont le developerName est RT_ComptePersonnel mapRecordType.get('RT_ComptePersonnel'); 8 - LE LANGAGE SOQL Il est similaire au langage SQL.Il permet de faire des opérations dans la base de données Salesforce. •Insert :créer un nouvel enregistrement •Update :mettre à jour un enregistrement existant. Il faut connaitre l'identifiant de l'enregistrement •Upsert :créer si inexistant sinon mettre à jour l’enregistrement. Il faut connaitre la clé externe •Delete :supprimer un enregistrement http://www.developpeurapex.eu 11
  12. 12. 8.1- Eclipse Schéma L’écran Salesforce schéma dispose de 3 zones : •Requête •Zone d’affichage des résultats •Objet La construction d’une requête se réalise de la manière suivante : •Choisir l’objet •Cliquer sur les champs souhaités •La requête est automatiquement affichée. •Cliquer sur « Run me » pour voir les résultats dans la zone d’affichage des résultats. 8.2- Salesforce Workbench L'outil Salesfore workbench permet de faire les opérations dans la base de donées. Son adresse url est https://workbench.developerforce.com/login.php Pour utiliser le workbench, il faut : •Choisir le type d'environnement : Sandbox ou Production •Choisir la version •Entrer le login et le mot de passe 8.3- Ecrire des réquêtes avancés Dans Salesforce, il est possible de faire des requêtes aggrégés. 8.3.1- Exemple de reqûete La lecture du résultat se réalise par le biais d'une boucle for et du mot clé "get". list<AggregateResult> dateAchatMaximum = [Select max(MaxDateAchat__c) from Client__c where Id in: listeClient]; for (AggregateResult ar : dateAchatMaximum) { thisDate = Date.valueOf(ar.get('expr0')); } Salesforce place le résultat d'une requête aggrégé dans une list "AggregateResult". http://www.developpeurapex.eu 12
  13. 13. list<AggregateResult> dateAchatMaximum = [Select max(MaxDateAchat__c) from Client__c where Id in: listeClient]; On va parcourir la liste "AggregateResult" pour récupérer la date : " ar.get('expr0') " . Le mot clé "expr0" permet de prendre la date for (AggregateResult ar : dateAchatMaximum) { thisDate = Date.valueOf(ar.get('expr0')); } 8.3.2- Calculer la moyenne Le mot clé AVG permet de faire la moyenne. AggregateResult[] moyenneVente = [SELECT NumeroSemaineHotellier__c, AVG(MontantVente__c) FROM Facture__c GROUP BY NumeroSemaineHotellier__c]; for (AggregateResult ar : moyenneVente) { System.debug(' Pour la semaine : "Semaine Hotellier" ' + ar.get('NumeroSemaineHotellier__c')); System.debug("la vente moyen est : ' + ar.get('expr0')); } Cette requête permet de calculer la moyenne des ventes par semaine hôtellier (NumeroSemaineHotellier__c). 8.3.3 - Obtenir le montant maximum le mot clé max permet de sélectionner le montant maximum. AggregateResult[] VenteParSalarie= [SELECT Name, max( MontantVente__c) FROM Employe__c group by Name]; for (AggregateResult ar : VenteParSalarie) { System.debug(' Nom Employé:' + ar.get('Name')); System.debug("le montant est : ' + ar.get('expr0')); } 8.3.4 - Obtenir le montant minimum le mot clé min permet de sélectionner le montant minimum. AggregateResult[] VenteParSalarie= [SELECT Name, min( MontantVente__c) FROM Employe__c group by Name]; for (AggregateResult ar : VenteParSalarie) { System.debug(' Nom Employé:' + ar.get('Name')); System.debug("le montant est : ' + ar.get('expr0')); } PARTIE 9 - TEST METHODE Dans un projet, il faut écrire des méthodes de test pour valider le code. Il existe différente technique de développement. Il est préconisé de centraliser la définition des objets dans une classe nommé ABS_TestFactory. Chaque classe de test va s'alimenter à partir de la classe ABS_TestFactory. http://www.developpeurapex.eu 13
  14. 14. Quels sont les avantages de la centralisation de la définition d'un objet? •Centraliser :Si un objet change de caractéristique, il faut apporter la modification dan la classe ABS_TestFactory. Toutes les autres classes verront la modification. Par exemple, un champ devient obligatoire. •Dupliquer: Evite d'avoir à dupliquer le même code X fois dans chaque classe de test. 9.1- Exemple de code Dans la classe ABS_TestFactory, la définition d'un Vendeur__c est la suivante: public static Vendeur__c createVendeur() { Vendeur__c unVendeur = new Vendeur__c(); unVendeur.Name = 'DUPOND'; unVendeur.Prenom__c = 'ALICE'; unVendeur.Adresse__c =' 45 rue de France '; unVendeur.CodePostal__c = '92600'; unVendeur.Ville__c = 'ASNIERES'; unVendeur.DateNaissance__c = Date.today().addYears(-440); unVendeur.Entretien1__c = 'UN ENTRETIEN DE TEST'; return unVendeur; } Dans les autres classes, on peut créer un vendeur(Vendeur__c) de la manière suivante : Vendeur__c unVendeur = ABC_TestFactory.createVendeur(); insert unVendeur; 9.2 - Lancer le test en tant qu'un utilisateur Il est préconisé de faire des tests réels afin de vérifier que le code est opérationnel. User unUtilisateur = ABC_TestFactory.createUserVendeur(); insert unUtilisateur; System.runAs(unUtilisateur) { } 9.3 - Vérifier l'exactitude des données attendues Il est possible de vérifier l'exactitude des données attendues dans une test méthode. Ainsi, on s'assure que le code est opérationnel. La commande System.AssertEquals permet de comparer deux valeurs. salarie__c salarie = ABS_Salarie.traiterSalarie(salarieDupond); Salarie__c unSalarie = [Select Id, Name , Salaire__c from Salarie__c where Id =: salarie.Id limit 1]; System.AssertEquals(unSalarie.Name , 'DUPOND'); Pour l'exemple ci dessus : •Créer l'enregistrement : La méthode traiterSalarie permet de créer le salarié ( Salarie__c ) reçu en paramètre. •Réquêter dans la base de données: Il faut réquêter le salarié dans la base de données •Vérifier la données : Il faut vérifier l'exactitude des données. 9.4 - Ergonomie Il est possible d’écrire les méthodes de test dans la classe. Pour une meilleure ergonomie et organisation, il est préconisé de créer une nouvelle classe http://www.developpeurapex.eu 14
  15. 15. Il est préconisé d'adopter la convention de nommage suivante : NomDeLaClasse_TEST 9.5- Création d'une test méthode Pour créer une classe de test, il faut •Cliquer sur classes •Cliquer sur new •Cliquer sur Apex Class Entrer le nom de la méthode de test Dans la liste de sélection Template : Sélectionner Test Class 9.6 - Taux de couverture du code Pour mettre notre code en production, il faut avoir 75% de couverture minimum. Pour vérifier le taux de couverture du code actuel, il faut effectuer la manipulation suivante : •Cliquer sur Setup •Cliquer sur Develop •Cliquer sur Apex Class •Cliquer sur Run All Test •Test failure:nombre d’erreurs •Code Coverage : taux de couverture •Test Success:liste les tests OK •Code Coverage : Taux de couverture par classe et trigger PARTIE 10 - VISUALFORCE 10.1- Introduction Visualforce est un langage balisé. Il est utilisé pour des écrans personnalisés. Chaque écran peut avoir un style personnalisé où bien le style salesforce. Chaque page Visualforce peut contenir jusqu’à 1Mo de http://www.developpeurapex.eu 15
  16. 16. texte, soit 1 million de caractère. Une page visualforce commence avec le tag et se termine avec le tag . 10.2- Architecture d'une page visualforce Fonctionnement : •L’utilisateur veut consulter une page visualforce •La page visualforce appel les méthodes du contrôleur •Les résultats sont retournés à la page visualforce •L’utilisateur peut consulter les résultats sur la page visualforce 10.3- Contenu d'une page Visualforce <apex:page > <!-- Ceci est un commentaire --> //Juste un texte de bienvenue <h1>Félicitations, vous venez de réaliser votre 1ère page. </h1> </apex:page> •Tag Visualforce: Une page visualforce commence toujours par le tag <apex:page> et se termine par le tag </apex:page> •Commentaire :Un commentaire commence toujours avec <!-- et se termine par -- > •On peut mettre des commentaires de la manière suivante : <!-- Ceci est un commentaire --> •Adresse : Une page Visualforce s’obtient à l’adresse suivante : Adresse de l’environnement + /apex/ + Nom de la page Visualforce •Pour la page VF01_PageBienvenue : sur l’environnement de test : on aura comme adresse : https://test.salesforce.com/apex/VF01_PageBienvenue 10.4 -Générer un PDF Il est possible d’afficher la page visualforce sous forme d’un fichier pdf. Il faut ajouter le mot clé : RenderAs="PDF" <apex:page RenderAs="PDF" > <!-- Ceci est un commentaire --> //Juste un texte de bienvenue <h1>Félicitations, vous venez de réaliser votre 1ère page. </h1> </apex:page> http://www.developpeurapex.eu 16
  17. 17. 10.5-Droit Profil Pour permettre à un utilisateur de voir la page Visualforce, il faut donner l’accès à son profil : •Il faut aller dans le profil •Dans la partie « Accès à la page Visualforce Page activé » , il faut cliquer sur « Modifier » •Il faut ajouter la page dans la liste des pages accessibles. 10.6 -Mode de développement sous Salesforce Il est possible de faire du développement directement sur la page visualforce.Pour cela, il faut activer le mode développeur dans la fiche profil de l’utilisateur. •Cliquer sur « Mes informations personnelles » •Cliquer sur « Informations personnelles » •Cocher la case « Mode de développement » Sur la page Visualforce, l’icône situé à droite permet d’activer l’outil de développement. Pour modifier votre code, il faut cliquer sur la disquette. Tout enregistrement est définitif. 10.7- Exemple d'application Je vais construire une page visualforce qui permet de créer, modifier des enregistrements. 10.7.1 - Créer un objet personnalisé Il faut créer un objet personnalisé http://www.developpeurapex.eu 17
  18. 18. •Cliquer sur « Créer » •Cliquer sur « Objets » •Cliquer sur « Nouvel objet personnalisé » La création des champs personnalisés se réalise au niveau de la section « Champs personnalisés et rélations » 10.7.2 - Créer un onglet personnalisé pour la page visualforce •Cliquer sur « Créer » •Cliquer sur « Onglet » Dans la section « Onglets de l’objet personnalisé », il faut cliquer sur « Nouveau » Dans la liste de sélection Objet, il faut choisir votre objet. Puis il faut choisir un style d’onglet. La description n’est pas obligatoire mais plutôt conseillé. 10.7.3 - Le contrôleur personnalisé Un contrôleur personnalisé va nous permettre de programmer des actions personnalisées.Sur la page visualforce, il faudra déclarer le contrôleur standard et personnalisé. •Le contrôleur standard se déclare avec le mot clé : Standardcontroller •Le contrôleur personnalisé se déclare avec le mot clé : extensions Important: Il ne faut pas omettre de mentionner le contrôleur standard. Si le contrôleur standard est omis, alors il n'est pas possible d'utiliser la page visualforce pour créer un onglet, surcharger une action , …. http://www.developpeurapex.eu 18
  19. 19. 10.7.4 - Le constructeur Dans le contrôleur, il faudra avoir obligatoirement un constructeur. Ce constructeur aura pour argument le contrôleur standard. Le constructeur s’exécute au lancement de la page. public class ControllerFilm{ private ApexPages.StandardController mycontroller; list<film__c> monfilm{get;set;} public ControllerFilm(ApexPages.StandardController controller) { mycontroller = controller; } } 10.7.5 - Afficher une variable public class ControllerFilm{ private ApexPages.StandardController mycontroller; list<film__c> monfilm{get;set;} public Integer i{get;set;} public ControllerFilm(ApexPages.StandardController controller) { mycontroller = controller; i=5; } } Dans le contrôleur, nous allons définir une valeur entière. Il ne faut pas oublier de préciser get ;set ; public Integer i{get;set;} Dans le constructeur, i va avoir la valeur 5. public ControllerFilm(ApexPages.StandardController controller) { mycontroller = controller; i=5; } Sur la page visualforce, il faut écrire la commande suivante : <apex:page Standardcontroller="film__c" extensions="ControllerFilm"> Bienvenue au Cinema Axel Apex Formation Le nombre de film en vision aujourd'hui est : {!i} </apex:page> 10.7.6 - Créer un titre <apex:page Standardcontroller="film__c" extensions="ControllerFilm"> <fieldset> <legend>Bienvenue au Cinema Axel Apex Formation</legend> Le nombre de film en vision aujourd'hui est : {!i} </fieldset> </apex:page> http://www.developpeurapex.eu 19
  20. 20. Le composant fieldset et legend permettent de faire un affichage avec un titre et un cadre au tour du contenu. 10.7.7 - Afficher les enregistrements existants Sur la page visualforce, il faut ajouter plusieurs composants. <apex:page Standardcontroller="film__c" extensions="ControllerFilm"> <apex:pageBlock > <apex:pageBlockTable value="{!monfilm}" var="film"> <apex:column value="{!film.Name}"/> <apex:column value="{!film.Prix_du_ticket__c}"/> <apex:column value="{!film.Type__c}"/> <apex:column value="{!film.Date_de_sortie__c}"/> <apex:column value="{!film.Nombre_de_jours_restant_en_vision__c}"/> <apex:column value="{!film.is3D__c}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:page> •<apex:pageBlockTable value="{!monfilm}" var="film">: ce composant permet de traiter le contenu de la liste monfilm. Pour chaque élément de la liste monfilm, on utilisera la variable film. •Le composant <apex :pageBlock> doit obligatoirement être mentionné avant le composant <apex :pageBlock.> •Le composant <apex :column> permet de choisir l’attribut à afficher. Par exemple, { ! film.Name} permet d’afficher le nom du film. Pour afficher les enregistrements sur la page visualforce, il est fortement conseillé d’utiliser les composants standards Visualforce. Ainsi vous n’aurez pas besoin d’écrire les feuilles de style css. 10.7.8 - Lire les enregistrements Sur le contrôleur, il faut créer une méthode qui va récupérer les enregistrements à partir de la base de données. public class ControllerFilm{ private ApexPages.StandardController mycontroller; public list<film__c> monfilm{get;set;} public ControllerFilm(ApexPages.StandardController controller) { mycontroller = controller; monfilm = retournerListeFilm(); } public list<film__c> retournerListeFilm(){ return [Select Name,Prix_du_ticket__c,Type__c,Nombre_de_jours_restant_en_vision__c, Date_de_sortie__c, is3D__c from film__c ]; } } la méthode suivante remplit la liste à partir de la base de données : public list<film__c> RetournerListeFilm(){ return [Select Name,Prix_du_ticket__c,Type__c,Nombre_de_jours_restant_en_vision__c, Date_de_sortie__c, is3D__c from film__c ]; } http://www.developpeurapex.eu 20
  21. 21. Dans le contrôleur, cette ligne permet de récharger la liste. monfilm = retournerListeFilm(); Nous venons de voir que le composant « <apex :column> » nous a permis d’afficher les enregistrements. Nous allons voir d’autres types de composant dans la suite du tutoriel. 10.7.9 - Le mode Edit La solution suivante permet d'éditer les enregistrements. <apex:page Standardcontroller="film__c" extensions="ControllerFilm"> <apex:form > <apex:commandButton action="{!changeEditMode}" value="edit" rendered="{!!isEditMode}" /> <apex:commandButton action="{!cancelEdit}" value="cancel" rendered="{!isEditMode}"/> <apex:commandButton action="{!saveFilm}" value="Save" rendered="{!isEditMode}"/> <apex:commandButton action="{!createFilm}" value="Create" rendered="{!!isEditMode}"/> <apex:pageBlock > <apex:pageBlockSection columns="3" title="Liste des films" > <apex:repeat value="{!monfilm}" var="film"> <apex:inputField value="{!film.Name}" rendered="{!isEditMode}" /> <apex:outputField value="{!film.Name}" rendered="{!!isEditMode}" /> <apex:inputField value="{!film.Prix_du_ticket__c}" rendered="{!isEditMode}" /> <apex:outputField value="{!film.Prix_du_ticket__c}" rendered="{!!isEditMode}" /> <apex:inputField value="{!film.Type__c}" rendered="{!isEditMode}" /> <apex:outputField value="{!film.Type__c}" rendered="{!!isEditMode}" /> </apex:repeat> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page> •<apex:pageBlockSection columns="3" title="Liste des films"> permet de spécifier une zone en 3 colonnes avec un titre. •<apex:repeat value="{!monfilm}" var="film">: on va lire le contenu de la liste nommée monfilm. La variable de lecture de la liste s’appelle film. C’est-à-dire, on va automatiquement accéder à chaque élément avec la variable film. •Le composant <apex:inputField> : l’utilisateur pourra modifier le contenu de la variable Name du film. Ce composant s’affichera en mode edit uniquement. rendered="{!isEditMode}" permet de spécifier le mode d’affichage. •Le composant <apex :outputField> : permet d’afficher le contenu de la variable Name du film. Il s’affichera en mode lecture. rendered="{!!isEditMode}" permet de spécifier l’affichage en mode lecture. http://www.developpeurapex.eu 21
  22. 22. •<apex:commandButton action="{!changeEditMode}" value="edit" rendered="{!! isEditMode}" /> Le bouton edit s’affichera en mode lecture. Il va appeler la méthode changeEditMode. •<apex:commandButton action="{!createFilm}" value="Create" rendered="{!! isEditMode}"/> Le bouton Create s’affichera en mode lecture. Il va appeler la méthode createFilm. •<apex:commandButton action="{!cancelEdit}" value="cancel" rendered="{! isEditMode}"/> Le bouton cancel s’affichera en mode edit Il va appeler la méthode cancelEdit. •<apex:commandButton action="{!saveFilm}" value="Save" rendered="{! isEditMode}"/> Le bouton Save s’affichera en mode edit. Il va appeler la méthode saveFilm. 10.8.0 - Le contrôleur public class ControllerFilm{ public list<film__c> monfilm{get;set;} public ControllerFilm(ApexPages.StandardController controller) { monfilm = RetournerListeFilm(); } public list<film__c> RetournerListeFilm() { return [Select Name,Prix_du_ticket__c,Type__c,Nombre_de_jours_restant_en_vision__c, Date_de_sortie__c, is3D__c from film__c ORDER BY Name ASC ]; } public boolean isEditMode { get { if (isEditMode == null){ isEditMode = false; } return isEditMode; } set; } public PageReference createFilm() { isEditMode = true; film__c f = new film__c(); monfilm.clear(); monfilm.add(f); return null; } public PageReference changeEditMode() { isEditMode = true; return null; } public PageReference saveFilm() { isEditMode = false; upsert monfilm; monfilm = RetournerListeFilm(); return null; } public PageReference cancelEdit() { isEditMode = false; monfilm = RetournerListeFilm(); return null; } } 10.8.1 - Changer le mode Le mode Edit permet d'afficher les composants en mode edit. la variable boolean "isEditMode" recevra la valeur true où false. Cette variable va conditionner les affichages des composants. public boolean isEditMode { get { if (isEditMode == null){ isEditMode = false; } http://www.developpeurapex.eu 22
  23. 23. return isEditMode; } set; } Lorsque l’utilisateur appuie sur le bouton « edit », la méthode changeEditMode est exécutée. Ainsi, la variable isEditMode reçoit la valeur true. public PageReference changeEditMode() { isEditMode = true; return null; } 10.8.2 - Le bouton Cancel Lorsque l’utilisateur appuie sur le bouton cancel, la méthode cancelEdit est exécutée. Ainsi, la variable isEditMode reçoit la valeur false. La liste sera rafraichit et le mode lecture seule sera affiché. public PageReference cancelEdit() isEditMode = false; monfilm = RetournerListeFilm(); return null; } 10.8.3 - Le bouton Save Lorsque l’utilisateur appuie sur le bouton save, la méthode saveFilm est exécutée. Ainsi, la variable isEditMode reçoit la valeur False.La liste sera rafraichit et le mode lecture seule sera affiché. public PageReference saveFilm() { isEditMode = false; upsert monfilm; monfilm = RetournerListeFilm(); return null; } 10.8.4 - Afficher les composants <apex:commandButton action="{!saveFilm}" value="Save" rendered="{!isEditMode}"/> Le bouton Save s’affichera en mode edit. Il appel la méthode saveFilm. Le mot clé rendered permet d’afficher le composant sur la page. la commande { !isEditMode} permet d’afficher le composant en mode edit. Pour afficher le composant en mode lecture seule, il faudra spécifierrendered="{ !!isEditMode}" 10.8.5 - Créer un enregistrement La création d’un nouvel enregistrement se réalise par le biais du bouton create . Si l’utilisateur appuie sur le bouton create, la méthode CreateFilm s'exécute public PageReference createFilm() { isEditMode = true; http://www.developpeurapex.eu 23
  24. 24. film__c f = new film__c(); monfilm.clear(); monfilm.add(f); return null; } •isEditMode = true on passe en mode edit •film__c f = new film__c(); on va créer un nouveau film •monfilm.clear(); on vide le contenu de la liste d’affichage •monfilm.add(f); on ajoute le nouveau élément à la liste d’affichage 10.8.6 - Sauver l'enregistrement courant A l’appui du bouton save, la méthode saveFilm s'exécute. public PageReference saveFilm() { isEditMode = false; upsert monfilm; monfilm = RetournerListeFilm(); return null; } •isEditMode = false on passe en mode lecture seule •upsert monfilm : on va effectuer l’insertion où la mise à jour en base de donnée •monfilm = RetournerListeFilm on va rafraichir la liste d’affichage. 10.8.7 - Annuler A l’appuie sur le bouton cancel, on exécute la méthode cancelEdit public PageReference cancelEdit() { isEditMode = false; monfilm = RetournerListeFilm(); return null; } •isEditMode : on passe en mode lecture seule •monfilm = RetournerListeFilm on va rafaichir la liste d’affichage. 10.9.1 - Le mode inline Editing Le mode inline Editing permet à l'utilisateur de pouvoir éditer un champ et enregistrer la modification. •L'utilisateur clique sur un champ. •Le champ devient éditable •Le bouton enregistrer et annuler sont activés http://www.developpeurapex.eu 24
  25. 25. 10.9.2 - Le contrôleur public with sharing class ABS_Account_VFCx { //Enregistrement courant public Account compteCourant{get;set;} public ABS_Account_VFCx(ApexPages.StandardController controller) { //On récupère l'enregistrement courant compteCourant = [Select Id,Name,Phone,Description from Account where Id =: ApexPages.currentPage().getParameters().get('id')]; } //on enregistre le compte courant public PageReference enregistrer() { update compteCourant; return null; } //on va annuler public PageReference annuler() { return null; } } 10.9.3 - Le page visualforce <apex:page standardController="Account" extensions="ABS_Account_VFCx" cache="false" tabStyle="Account" > <apex:form > <apex:pageBlock mode="inlineEdit" title="Agenda Client"> <apex:pageBlockButtons id="buttonListe"> <apex:commandButton style="display:none" id="enregistrer" value="Enregistrer" action="{!enregistrer}" /> <apex:commandButton style="display:none" id="cancel" value="Annuler" action="{!annuler}" immediate="true" /> </apex:pageBlockButtons> <apex:pageBlockSection columns="2" title="Information" id="tabInformation"> <apex:outPutField value="{!compteCourant.Name}" label="{!$ObjectType.Account.fields.Name.label}"> <apex:inlineEditSupport showOnEdit="enregistrer,cancel" hideOnEdit="edit" event="ondblclick" /> </apex:outPutField> <apex:outPutField value="{!compteCourant.Phone}" label="{!$ObjectType.Account.fields.Phone.label}"> <apex:inlineEditSupport showOnEdit="enregistrer,cancel" hideOnEdit="edit" event="ondblclick" /> </apex:outPutField> <apex:outPutField value="{!compteCourant.Description}" label="{!$ObjectType.Account.fields.Description.label}"> <apex:inlineEditSupport showOnEdit="enregistrer,cancel" hideOnEdit="edit" event="ondblclick" /> </apex:outPutField> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page> 10.9.4 - Comment programmer l'inline editing ? <apex:outPutField value="{!compteCourant.Phone}" label="{!$ObjectType.Account.fields.Phone.label}"> <apex:inlineEditSupport showOnEdit="enregistrer,cancel" hideOnEdit="edit" event="ondblclick" /> http://www.developpeurapex.eu 25
  26. 26. </apex:outPutField> •label="{!$ObjectType.Account.fields.Phone.label}" : permet de prendre l'étiquette du champ •apex:inlineEditSupport showOnEdit="enregistrer,cancel" : permet d'activer les boutons enregistrer et annuler •event="ondblclick" : active le mode edit pour le double clic de la souris. 10.10.1 - Ajax sur une page visualforce Sur une page visualforce, il est possible de faire des actions dynamiques en fonction des choix de l'utilisateur L'utilisateur peut cocher où décocher la case "Professionnel" : le champ "Professionnel" est coché le champ Secteur d'activité apparait le champ "Professionnel" est décoché le champ Profession apparait 10.10.2 - le contrôleur public with sharing class ABS_Account_VFCx { //Enregistrement courant public Account compteCourant{get;set;} public Boolean afficherChampPro{get;set;} public ABS_Account_VFCx(ApexPages.StandardController controller) { //On crée un nouveau account compteCourant = new Account(); } //on enregistre le compte courant public PageReference enregistrer() { insert compteCourant; return null; } //on va annuler http://www.developpeurapex.eu 26
  27. 27. public PageReference annuler() { return null; } /* @Action Ajax */ public PageReference activerChampProfessionel() { if(compteCourant.Professionnel__c) { afficherChampPro=true; } else { afficherChampPro=false; } return null; } } 10.10.3 - la page Visualforce <apex:page standardController="Account" extensions="ABS_Account_VFCx" cache="false" tabStyle="Account" > <apex:form > <apex:pageBlock mode="inlineEdit" title="Agenda Client"> <apex:pageBlockButtons id="buttonListe"> <apex:commandButton id="enregistrer" value="Enregistrer" action="{!enregistrer}" /> <apex:commandButton id="cancel" value="Annuler" action="{!annuler}" immediate="true" /> </apex:pageBlockButtons> <apex:pageBlockSection > <apex:inputField value="{!compteCourant.Professionnel__c}" > <apex:actionsupport event="onchange" action="{!activerChampProfessionel}" rerender="form" /> </apex:inputField> </apex:pageBlockSection> <apex:pageBlockSection id="form"> <apex:inputField value="{!compteCourant.Industry}" rendered="{!afficherChampPro}" /> <apex:inputField value="{!compteCourant.Profession__c}" rendered="{!!afficherChampPro}" /> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page> 10.10.4 - Comment programmer le comportement Ajax ? <apex:inputField value="{!compteCourant.Professionnel__c}" > <apex:actionsupport event="onchange" action="{!activerChampProfessionel}" rerender="form" /> </apex:inputField> <apex:actionsupport event="onchange" action="{!activerChampProfessionel}" rerender="form"> •event="onchange" : L'utilisateur coche où décoche le champ •action="{!activerChampProfessionel}" : la méthode qu'il faut appeler dans le contrôlleur. •rerender="form" : la zone à rafraichir 10.11.1 - Envoyer des informations au contrôleur via un lien L'utilisateur peut afficher des données en cliquant sur un lien la page affiche tous les clients http://www.developpeurapex.eu 27
  28. 28. l'utilisateur clique sur le lien "U" : seul les comptes dont le nom commence par "U" s'affichent. l'utilisateur clique sur le lien "G" : seul les comptes dont le nom commence par "G" s'affichent. 10.11.2 - le contrôleur public with sharing class ABS_Compte_VFCx { public list<Account> listAccount{get;set;} public ABS_Compte_VFCx(ApexPages.StandardController controller) { //On affiche les 10 comptes au démarrage listAccount = [Select Id, Name, Phone,Industry from Account limit 10]; } /* @Action Ajax */ public PageReference rechercherCompte() { String premierlettreName=ApexPages.currentPage().getParameters().get('lettreAccount') ; String requete= 'Select Id, Name, Phone,Industry from Account where Name LIKE '+ '''+ premierlettreName +'%' '; listAccount=Database.query(requete); return null; } } 10.11.3 - la page Visualforce <apex:page standardController="Account" extensions="ABS_Compte_VFCx" cache="false" tabStyle="Account" > <apex:form > <apex:pageBlock mode="inlineEdit" > <apex:PageblockSection title="Filtre" columns="30"> <apex:panelGrid columns="26"> <apex:commandLink reRender="tableau" value="D" action="{!rechercherCompte}"> <apex:param name="lettreAccount" value="D" /> </apex:commandLink> <apex:commandLink reRender="tableau" value="E" action="{!rechercherCompte}"> <apex:param name="lettreAccount" value="E" /> </apex:commandLink> <apex:commandLink reRender="tableau" value="G" action="{!rechercherCompte}"> <apex:param name="lettreAccount" value="G" /> </apex:commandLink> <apex:commandLink reRender="tableau" value="U" action="{!rechercherCompte}"> <apex:param name="lettreAccount" value="U" /> </apex:commandLink> </apex:panelGrid> http://www.developpeurapex.eu 28
  29. 29. </apex:PageblockSection> </apex:pageBlock> <apex:pageBlock title="Compte" id="tableau"> <apex:pageBlockTable value="{!listAccount}" var="item"> <apex:column value="{!item.Name}"/> <apex:column value="{!item.phone}"/> <apex:column value="{!item.Industry}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page> 10.11.4 - Comment programmer le comportement Ajax ? Sur la page visualforce <apex:commandLink reRender="tableau" value="U" action="{!rechercherCompte}"> <apex:param name="lettreAccount" value="U" /> </apex:commandLink> Sur le contrôleur public PageReference rechercherCompte() { String premierlettreName=ApexPages.currentPage().getParameters().get('lettreAccount') ; String requete= 'Select Id, Name, Phone,Industry from Account where Name LIKE '+ '''+ premierlettreName +'%' '; listAccount=Database.query(requete); return null; } •action="{!rechercherCompte}" apex:param name="lettreAccount" value="U" : appel la méthode rechercherCompte et envoie la lettre U dans le paramètre lettreAccount •premierlettreName=ApexPages.currentPage().getParameters().get('lettreAccount') : l e contrôleur récupère la lettre envoyée par le composant commandLink. La commande soql est exécutée. les comptes sont placés dans la liste pour être affichés. •reRender="tableau" : permet de rafraichir la zone du tableau. 10.12.1 - Envoyer des informations en entrant des lettres L'utilisateur peut rechercher un compte en tapant le nom. La page visualforce affiche les comptes qui répondent au critère. la page affiche tous les clients l'utilisateur saisit le texte "uni" : seul les comptes dont le nom commence par "uni" s'affichent. l'utilisateur saisit sur le lien "unit" : seul les comptes dont le nom commence par "unit" s'affichent. http://www.developpeurapex.eu 29
  30. 30. l'utilisateur saisit sur le lien "ax" : seul les comptes dont le nom commence par "ax" s'affichent. 10.12.2 - le contrôleur public with sharing class ABS_Account_VFCx { public String compteCherche{get;set;} public list<Account> listAccount{get;set;} public ABS_Account_VFCx(ApexPages.StandardController controller) { //On affiche les 10 comptes au démarrage listAccount = [Select Id, Name, Phone,Industry from Account limit 10]; } /* @Action Ajax */ public PageReference rechercherCompte() { String requete= 'Select Id, Name, Phone,Industry from Account where Name LIKE '+ '''+ compteCherche +'%' '; listAccount=Database.query(requete); return null; } } 10.12.3 - la page Visualforce <apex:page standardController="Account" extensions="ABS_Account_VFCx" cache="false" tabStyle="Account" > <apex:form > <apex:pageBlock mode="inlineEdit" > <apex:PageblockSection title="Filtre" columns="1"> <apex:inputText label="Rechercher un Compte" id="accountSearch" value="{!compteCherche}"> <apex:actionSupport event="onkeyup" action="{!rechercherCompte}" rerender="tableau" /> </apex:inputText> </apex:PageblockSection> </apex:pageBlock> <apex:pageBlock title="Compte" id="tableau"> <apex:pageBlockTable value="{!listAccount}" var="item"> <apex:column value="{!item.Name}"/> <apex:column value="{!item.phone}"/> <apex:column value="{!item.Industry}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page> 10.12.4 - Comment programmer le comportement Ajax ? Sur la page visualforce <apex:inputText label="Rechercher un Compte" id="accountSearch" value="{!compteCherche}"> <apex:actionSupport event="onkeyup" action="{!rechercherCompte}" rerender="tableau" /> </apex:inputText> http://www.developpeurapex.eu 30
  31. 31. Sur le contrôleur public String compteCherche{get;set;} String requete= 'Select Id, Name, Phone,Industry from Account where Name LIKE '+ '''+ compteCherche +'%' '; listAccount=Database.query(requete); •actionSupport event="onkeyup" : lorsque l'utilisateur entre une lettre •value="{!compteCherche} : on place la valeur saisit par l'utilisateur dans la variable compteCherche •action="{!rechercherCompte}": appeler la méthode rechercherCompte pour ré-calculer le contenu du tableau •rerender="tableau" rafraichir la zone tableau 10.13.1 - Faire une pagination Ce module explique la pagination des éléments sur un tableau. 10.13.2 - le contrôleur public with sharing class ABS_Animal_VFCx { public list<Animal__c> listAnimal{get;set;} public ABS_Animal_VFCx(ApexPages.StandardController controller) { } public ApexPages.StandardSetController controllerAnimal{ get { if(controllerAnimal== null) { /* On réalise une réquête pour récupérer les enregistrements de la base de données*/ controllerAnimal= new ApexPages.StandardSetController(Database.getQueryLocator( [Select Id, Name, Caractere__c,Type__c, DateNaissance__c, PaysOrigine__c, Prix__c from Animal__c order by Name asc ])); } /* Définir le nombre d'élémént par page*/ controllerAnimal.setPageSize(5); return controllerAnimal; } set; } public list>Animal__c> getAnimals() { return (list<Animal__c>) controllerAnimal.getRecords(); } /* Le page suivante exist-il?*/ public Boolean hasNextt { get { return controllerAnimal.gethasNext(); } set; } /* Le page précédente exist-il?*/ public Boolean hasPreviouss { get { return controllerAnimal.getHasPrevious(); } set; } /* Le contrôleur standard renvoie la prémière page*/ public void first() { controllerAnimal.first(); } /* Le contrôleur standard renvoie la dernière page*/ public void last() { http://www.developpeurapex.eu 31
  32. 32. controllerAnimal.last(); } /* Le contrôleur standard renvoie la page précédente*/ public void previous() { controllerAnimal.previous(); } /* Le contrôleur standard renvoie la page suivante*/ public void next() { controllerAnimal.next(); } } 10.13.3 - la page Visualforce <apex:page standardController="Animal__c" readOnly="true" tabStyle="Animal__c" extensions="ABS_Animal_VFCx" > <apex:form > <apex:pageBlock title="Animaux"> <apex:pageBlockTable value="{!Animals}" var="animal" id="listAnimal"> <apex:column headervalue="{!$ObjectType.Animal__c.fields.Name.label}"><apex:outputLink target="_blank" value="/{! animal.Id}">{!animal.Name}</apex:outputLink> </apex:column> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Type__c.label}" value="{!animal.Type__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Caractere__c.label}" value="{!animal.Caractere__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.DateNaissance__c .label}" value="{!animal.DateNaissance__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.PaysOrigine__c.label}" value="{!animal.PaysOrigine__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Prix__c.label}" value="{!animal.Prix__c}"/> </apex:pageBlockTable> </apex:pageBlock> <apex:panelGrid columns="4"> <apex:commandLink action="{!first}">First</apex:commandlink> <apex:commandLink action="{!previous}" rendered="{!hasPreviouss}">Previous</apex:commandlink> <apex:commandLink action="{!next}" rendered="{!hasNextt}">Next</apex:commandlink> <apex:commandLink action="{!last}"> Last</apex:commandlink> </apex:panelGrid> </apex:form> </apex:page> 10.14.1 - Trier une colonne Ce module explique le tri des éléments par colonne. 10.14.2 - La page visualforce <apex:page standardController="Animal__c" readOnly="true" tabStyle="Animal__c" extensions="ABS_Animal_VFCx"> <apex:form id="form"> <apex:pageBlock title="Animaux"> <apex:pageBlockTable value="{!Animals}" var="animal" id="listAnimal"> <apex:column> <apex:facet name="header"> <apex:outputpanel > <apex:outputText value="{!$ObjectType.Animal__c.fields.Name.label}"/> <apex:commandLink reRender="listAnimal" action="{!trierColonne}"> <apex:image value="/img/sort_asc_arrow.gif" /> <apex:param name="critere" value="order by Name asc" /> </apex:commandLink> <apex:commandLink reRender="listAnimal" action="{!trierColonne}"> <apex:image value="/img/sort_desc_arrow.gif" /> http://www.developpeurapex.eu 32
  33. 33. <apex:param name="critere" value="order by Name desc" /> </apex:commandLink> </apex:outputpanel> </apex:facet> < apex:outputLink target="_blank" value="/{!animal.Id}">{!animal.Name} </apex:outputLink> </apex:column> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Type__c.label}" value="{!animal.Type__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Caractere__c.label}" value="{!animal.Caractere__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.DateNaissance__c .label}" value="{!animal.DateNaissance__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.PaysOrigine__c.label}" value="{!animal.PaysOrigine__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Prix__c.label}" value="{!animal.Prix__c}"/> </apex:pageBlockTable> </apex:pageBlock> <apex:panelGrid columns="4"> <apex:commandLink action="{!first}">First</apex:commandlink> <apex:commandLink action="{!previous}" rendered="{!hasPreviouss}">Previous</apex:commandlink> <apex:commandLink action="{!next}" rendered="{!hasNextt}">Next</apex:commandlink> <apex:commandLink action="{!last}"> Last</apex:commandlink> </apex:panelGrid> </apex:form> </apex:page> 10.14.3 - le contrôleur public with sharing class ABS_Animal_VFCx { public list<Animal__c> listAnimal{get;set;} public String critereTri{get;set;} public ABS_Animal_VFCx(ApexPages.StandardController controller) { } public ApexPages.StandardSetController controllerAnimal{ get { if(controllerAnimal== null) { String soql = 'Select Id, Name, Caractere__c,Type__c, DateNaissance__c, PaysOrigine__c, Prix__c from Animal__c'; if(critereTri == null || critereTri =='' ) { soql= soql+' order by Name asc'; } else { soql= soql+' '+critereTri ; } controllerAnimal= new ApexPages.StandardSetController(Database.getQueryLocator(soql)); } controllerAnimal.setPageSize(5); return controllerAnimal; } set; } public list<Animal__c> getAnimals() { return (list<Animal__c>) controllerAnimal.getRecords(); } public PageReference trierColonne() { critereTri= ApexPages.currentPage().getParameters().get('critere'); String soql = 'Select Id, Name, Caractere__c,Type__c, DateNaissance__c, PaysOrigine__c, Prix__c from Animal__c'; soql= soql+' '+critereTri ; controllerAnimal= new ApexPages.StandardSetController(Database.getQueryLocator(soql)); return null; } public Boolean hasNextt { get { return controllerAnimal.gethasNext(); } set; } public Boolean hasPreviouss { get { return controllerAnimal.getHasPrevious(); http://www.developpeurapex.eu 33
  34. 34. } set; } public void first() { controllerAnimal.first(); } public void last() { controllerAnimal.last(); } public void previous() { controllerAnimal.previous(); } public void next() { controllerAnimal.next(); } } 10.14.4 - Comment programmer le comportement Ajax ? <apex:column> <apex:facet name="header"> <apex:outputpanel > <apex:outputText value="{!$ObjectType.Animal__c.fields.Name.label}"/> <apex:commandLink reRender="listAnimal" action="{!trierColonne}"> <apex:image value="/img/sort_asc_arrow.gif" /> <apex:param name="critere" value="order by Name asc" /> </apex:commandLink> <apex:commandLink reRender="listAnimal" action="{!trierColonne}"> <apex:image value="/img/sort_desc_arrow.gif" /> <apex:param name="critere" value="order by Name desc" /> </apex:commandLink> </apex:outputpanel> </apex:facet> < apex:outputLink target="_blank" value="/{!animal.Id}">{!animal.Name} </apex:outputLink> </apex:column> Sur la page visualforce , on utilise un composant nommé apex:facet pour placer le nom de la colonne et les icônes haut et bas name="header" : indique qu'il s'agit de l'entête. <apex:outputpanel > : le composant <apex:facet> reçoit un seul élément.Or on souhaite placer trois éléments. C'est pourquoi, il faut un composant <apex:outputpanel > pour cela. <apex:commandLink reRender="listAnimal" action="{!trierColonne}"> <apex:image value="/img/sort_asc_arrow.gif" /> <apex:param name="critere" value="order by Name asc" /> </apex:commandLink> •apex:commandLink : est un composant permettant de proposer un lien •reRender="listAnimal" : rafraichir seulement le tableau à la fin de l'action •action="{!trierColonne}" : appel la méthode trierColonne pour faire l'action •<apex:param name="critere" value="order by Name asc" />" : envoyer des paramètres au contrôleur. le paramètre s'appel "critere" et la valeur envoyée est "order by Name asc". •image value="/img/sort_asc_arrow.gif" : on utilise une image standard de l'outil. La liste des images est disponible sur internet Sur le contrôleur, la méthode récupère le paramètre envoyé et recalcule les données du tableau. http://www.developpeurapex.eu 34
  35. 35. public PageReference trierColonne() { critereTri= ApexPages.currentPage().getParameters().get('critere'); String soql = 'Select Id, Name, Caractere__c,Type__c, DateNaissance__c, PaysOrigine__c, Prix__c from Animal__c'; soql= soql+' '+critereTri ; controllerAnimal= new ApexPages.StandardSetController(Database.getQueryLocator(soql)); return null; } •critereTri= ApexPages.currentPage().getParameters().get('critere') : récupère le critère envoyé par le lien •soql= soql+' '+critereTri ; : recompose la requête •new ApexPages.StandardSetController(Database.getQueryLocator(soql)); : effectue la réquête avec le nouveau critère 10.15.1 - StandardSetController Un contrôleur de type StandardSetController permet de créer des listes de sélection à partir des éléments sélectionnés dans une vue de liste. l'utlisateur sélectionne plusieurs enregistrements et appuie sur le bouton "Vendre". Les animaux sont affichés sur la page visualforce. 10.15.2 - le contrôleur public class ABS_Animal { public list<Animal__c> listAnimalSelected{get;set;} private set<Id>setIdentifiant{get;set;} private ApexPages.StandardSetController standardSetController; public ABS_Animal(ApexPages.StandardSetController stdSetController) { this.standardSetController = stdSetController; setIdentifiant = new set<Id>(); for (Animal__c animal : (list<Animal__c>)standardSetController.getSelected()) { setIdentifiant.add(animal.Id); } listAnimalSelected = [Select Id, Name, Type__c, Caractere__c, DateNaissance__c, PaysOrigine__c , Prix__c from Animal__c where Id in: setIdentifiant]; } } 10.15.3 - La page visualforce <apex:page standardController="Animal__c" readOnly="true" tabStyle="Animal__c" recordSetVar="Animaux" extensions="ABS_Animal"> <apex:form id="form"> <apex:pageBlock title="Animaux"> <apex:pageBlockTable value="{!listAnimalSelected}" var="animal" id="listAnimal"> http://www.developpeurapex.eu 35
  36. 36. <apex:column headerValue="{!$ObjectType.Animal__c.fields.Type__c.label}" value="{!animal.Name}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Caractere__c.label}" value="{!animal.Caractere__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.DateNaissance__c .label}" value="{!animal.DateNaissance__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.PaysOrigine__c.label}" value="{!animal.PaysOrigine__c}"/> <apex:column headerValue="{!$ObjectType.Animal__c.fields.Prix__c.label}" value="{!animal.Prix__c}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page> 10.14.4 - Comment programmer le contrôleur ? standardSetController.getSelected(): permet de récupérer tous les enregistrements sélectionnés. setIdentifiant.add(animal.Id) : permet de placer tous les identifiants des enregistrements sélectionnés listAnimalSelected : faire une réquête et placer dans la liste pour traitement sur la page visualforce. for (Animal__c animal : (list<Animal__c>)standardSetController.getSelected()) { setIdentifiant.add(animal.Id); } listAnimalSelected = [Select Id, Name, Type__c, Caractere__c, DateNaissance__c, PaysOrigine__c , Prix__c from Animal__c where Id in: setIdentifiant]; 10.14.5 - Comment créer le bouton sur la vue de liste Il faut aller sur l'objet et appuyer sur le bouton "nouveau bouton" Il faut sélectionner "List Button" et sélectionner la page visualforce de destination Il faut aller sur la vue de liste Il faut rajouter le bouton sur la vue de liste http://www.developpeurapex.eu 36
  37. 37. PARTIE 11 - WEBSERVICE VIA HTTP - 11.1 - Faire un appel Webservice - Salesforce peut utiliser le protocole HTTP pour faire un appel webservice. Il se base sur le modèle Client / Serveur. Salesforce (Client) envoie une requête (HttpRequest ) et un serveur ( Système hétérogène) qui renvoie une réponse (HttpResponse). HttpRequest : c'est la demande envoyée par le client •contient le ou les entêtes •contient le corps du message •contient la définition du timeout : préconisé à 120000 HttpResponse : c'est la réponse reçue du serveur •contient la réponse du serveur •contient le statut de la réponse •contient le ou les entêtes @Future(callout=true) private static void envoyerAppelWebservice(Id account, String message) { Httprequest request = new Httprequest(); request.setEndpoint('http://www.developpeurapex.eu/axel?service=3'); request.setMethod('POST'); request.setTimeout(120000); String nom = 'axel@developpeurapex.eu'; String pass = 'testmp'; request.setHeader('userName', nom); request.setHeader('password', pass); req.setHeader('Content-Type', 'text/xml'); request.setBody(message); Http http = new Http(); HTTPResponse response = http.send(request); try{ parResponseWeb(response.getBody() , account); } catch (System.CalloutException e) { System.debug('**Une erreur est survenue' + e); } catch (Exception e) { System.debug('**Une erreur est survenue' + e); } } •request.setEndpoint('http://www.developpeurapex.eu/axel?service=3'):permet de définir l'endpoint •request.setMethod('POST'):permet de définir la méthode post •request.setTimeout(120000):permet de définir le timeout client : Salesforce autorise un max de 120000 •request.setHeader:permet de définir différent élément pour l'entête •request.setBody(message):permet de définir le paquet à envoyer http://www.developpeurapex.eu 37
  38. 38. •HTTPResponse response = http.send(request):le paquet request est envoyé via http. la réponse est placée dans la variable response. 11.2 - Parser un XML- Salesforce propose des méthodes pour parser un fichier XML. String xmlRecu = '<enveloppe>' + ' <Body>' + ' <hotels>' + ' <hotel>' + ' <nom>SALESFORCE HOTEL</nom>' + ' <adresse>20 RUE DE NANTERRE</adresse>' + ' <ville>NICE</ville> ' + ' <codePostal>06500</codePostal>' + ' <telephone>0199119911</telephone>' + ' <chambres>' + '<chambre>' + '<nom>Chambre Famille</nom>' + '<capacite>4</capacite>' + '<prix>50</prix>' + '<surface>150.5</surface>' + '<etage>2</etage>' + '<numero>3478</numero>' + '</chambre>' + '<chambre>' + '<nom>Chambre Suite</nom> ' + '<capacite>4</capacite>' + '<prix>200</prix>' + '<surface>200.5</surface>' + '<etage>7</etage>' + '<numero>3462</numero>' + '</chambre>' + '</chambres>' + '<capacite>1200</capacite>' + '<dirigeant>Mr LOUIS DURANDON</dirigeant> ' + '<daterenovation>15/05/2010</daterenovation> ' + '<dateouverture>2000-02-01</dateouverture> ' + '</hotel>' + '</hotels>' + '</Body>' + '</enveloppe>'; La méthode load de la classe DOM.Document permet de transformer la chaine de caractère en DoM.XmlNode DOM.Document doc = new DOM.Document(); doc.load(xmlRecu); DOM.XMLNode root = doc.getRootElement(); doc.load(xmlRecu); DOM.XMLNode root = doc.getRootElement(); list<Dom.XmlNode> listEnvelope = root.getChildElements(); list<Dom.XmlNode> nodeHotels = listEnvelope[0].getChildElements(); list<Dom.XmlNode> listHotels = nodeHotels[0].getChildElements(); Le code ci dessus permet de se déplacer au niveau hotels. •La méthode getChildElement permet de récupérer chaque node enfant. On s'arrête au niveau de la node parente, ici 'hotel'. •le mot clé getText permet de récupérer le texte de la balise. •String.valueOf permet de spécifier le type de la variable attendue •La méthode getChildElements() permet de récupérer plusieurs enfants du même parent. http://www.developpeurapex.eu 38
  39. 39. •listEnvelope[0].getChildElements() : Il est possible de spécifier 0 lorsqu'il y a une seule node fille. Ainsi, cette commande sert à récupérer la premier élément. Dans notre XML, la node <Body> a une seule fille <hotels>. for (Dom.XmlNode eachHotel : listHotels) { if(eachHotel.getName() == 'hotel') { System.debug('***Name :' + String.valueOf(eachHotel.getChildElement('nom', null).getText())); System.debug('***Adresse : ' + String.valueOf(eachHotel.getChildElement('adresse', null).getText())); System.debug('***Code Postal :' + String.valueOf(eachHotel.getChildElement('codePostal', null).getText())); System.debug('***Ville : ' + String.valueOf(eachHotel.getChildElement('ville', null).getText())); System.debug('***telephone :' + String.valueOf(eachHotel.getChildElement('telephone', null).getText())); System.debug('***capacite : ' + Integer.valueOf(eachHotel.getChildElement('capacite', null).getText())); System.debug('***dirigeant : ' + String.valueOf(eachHotel.getChildElement('dirigeant', null).getText())); System.debug('***date Ouverture : ' + Date.valueOf(eachHotel.getChildElement('dateouverture', null).getText())); System.debug('***date Rénovation : ' + Date.parse(eachHotel.getChildElement('daterenovation', null).getText())); } Si le format de la date est YYYY-mm-dd, il faut utiliser Date.valueof() Si le format de la date est dd/mm/YYY, il faut utiliser Date.parse() Le résultat d'affichage est le suivant : ***Name :SALESFORCE HOTEL ***Adresse : 20 RUE DE NANTERRE ***Code Postal :06500 ***Ville : NICE ***telephone :0199119911 ***capacite : 1200 ***dirigeant : Mr LOUIS DURANDON ***date Ouverture : 01-02-2000 ***date Rénovation: 15/05/2010 Pour parser plusieurs éléments, il faut s'arrêter au niveau de la node parente puis récupérer tous les enfants. Enfin, il faut parcourir tous les nodes enfants. •if(eachElement.getName() == 'chambres') permet de s'arrêter au niveau de la node chambres •for (Dom.XmlNode eachChambre : listChambres) { permet de parcourir chaque élément enfant de la node parente for (Dom.XmlNode eachElement : eachHotel.getChildElements()) { if(eachElement.getName() == 'chambres') { list<Dom.XmlNode list> listChambres = eachElement.getChildElements(); for (Dom.XmlNode eachChambre : listChambres) { System.debug('***Nom de la chambre :' + String.valueOf(eachChambre.getChildElement('nom', null).getText())); System.debug('***Capacité de la chambre :' + Integer.valueOf(eachChambre.getChildElement('capacite', null).getText())); System.debug('***Prix de la chambre :' + Integer.valueOf(eachChambre.getChildElement('prix', null).getText())); System.debug('***Etage de la chambre :' + Integer.valueOf(eachChambre.getChildElement('etage', null).getText())); System.debug('***Numéro de la chambre :' + Integer.valueOf(eachChambre.getChildElement('numero', null).getText())); System.debug('***Surface de la chambre :' + Double.valueOf(eachChambre.getChildElement('surface', null).getText())); } } } Le résultat d'affichage est le suivant : ***Nom de la chambre :Chambre Famille ***Capacité de la chambre :4 http://www.developpeurapex.eu 39
  40. 40. ***Prix de la chambre :50 ***Etage de la chambre :2 ***Numéro de la chambre :3478 ***Surface de la chambre :150.5 ***Nom de la chambre :Chambre Suite ***Capacité de la chambre :4 ***Prix de la chambre :200 ***Etage de la chambre :7 ***Numéro de la chambre :3462 ***Surface de la chambre :200.5 NOTE IMPORTANT : le webservice peut retourner des nodes en fonction du type d'enregistrement. Pour éviter une erreur, il faut placer chaque node dans un bloc try catch. try{ System.debug('***Nom de la chambre :' + String.valueOf(eachChambre.getChildElement('nom', null).getText())); }catch(Exception e){} http://www.developpeurapex.eu 40

×