Firebase d’avoir une base de données NoSQL principalement dans le cloud. Mais ça ne se limite pas à ça, il y a aussi du stockage d fichier, de code, de l’analytics, mais le principal usage à ma connaissance est la base temps réel NoSQL, son avantage est de permettre de mettre sur pied rapidement une application, pour peu qu’on soit familier avec lui.
Création d’un compte Firebase
Pour créer un compte Firebase, vous devez disposer d’un compte Google, et ensuite activer votre compte Firebase.
Contexte du tutoriel
Le contexte de l’application est une application dans une page html, donc pas besoin d’avoir NodeJs, nous verrons qu’il est possible de créer un projet de cette façon et de faire appel aux librairies, mais pour des raisons de simplicité, nous allons au plus simple.
Ensuite vous devez créer un projet et remplir des informations sur votre projet. Vous disposez d’niformation de configuration pour votre application.
Inclusion des scripts
Il y a plusieurs scripts à inclure en fonction de ce que vous voulez faire (analytics ou non) mais le principal fichier à inclure est le firebase-app.js
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.17.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-firestore.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-analytics.js"></script>
#exemple de configuration Firebase
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "DCZ28p7gilP15WoymVHn-A",
authDomain: "myapp-bull3503.firebaseapp.com",
databaseURL: "https://myapp-bull3503.firebaseio.com",
projectId: "myapp-bull3503",
storageBucket: "myapp-bull3503.appspot.com",
messagingSenderId: "2017024",
appId: "1:2017024:web:e282485405d09",
measurementId: "G-J4XXXQPHT9"
};
// initialisation de l'app
firebase.initializeApp(firebaseConfig);
Créer une base de données orientée documents Cloud Firestore
Cette base est en accès public pour une durée de 30 jours, vous pourrez vous y connecter sans mot de passe, passé ce délai, vous recevrez une alerte comme quoi la base ne sera plus accessible en public. Dans la cnsole, vous verrez Realtime Database et Cloud Firestore, quelle est la différence? C’est expliqué sur cet article.
#paramétrage de la base de données
à l'origine le paramétrage est permissif pour vous permettre de tester la base
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.time < timestampe.date(2020,7,6);
}
}
}
Mais au bout de 30 jours vous recevez un mail pour modifier l'accès à la base avec des règles plus strictes.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Mais au bout de 30 jours vous recevez un mail pour modifier l'accès à la base avec des règles plus strictes.
Créer un utilisateur
Pour créer un utilisateur, chargez d’abord la librairie auth, qui vous permet de créer un utilisateur et de gérer les connexion.
#création d'un utilisateur via un formulaire
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, ':', errorMessage)
});
Si la création d’un utilisateur s’est faite avec succès, vous êtes automatiquement loggé. Si vous n’arrivez pas à créer un utilisateur de cette façon (probablement parce que vous avez oublié d charger la librairie auth) et que vous désirez rapidement en créer un, vous pouvez aller directement sur la console, dans la sidebar de gauche Authentification puis Ajouterun utilisateur
Connexion d’un utilisateur
firebase.auth().signInWithEmailAndPassword(email, password).catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, ':', errorMessage)
});
Pour maintenir la connexion de l’utilisateur entre différentes pages, il vous faudra utiliser le localStorage.
Lire une table
Je suppose que vous incluiez à chaque page les librairie correspondantes.
var firebaseConfig = {
...
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.auth().signInWithEmailAndPassword(email, password).catch(function (error) {
...
});
#instanciation de la connexion à Firestore
var db = firebase.firestore();
Découvrez comment administrer la base de données depuis le site de Firebase.
Il existe dans Symfony plusieurs façons de faire des requêtes SQL, dont l’une spécifique à Doctrine, l’utilisation de Query Builder est sans doute la plus utilisée. Notez qu’il y a aussi Native Query qui se veut ‘proche’ de SQL de base.
Parfois on peut se tromper dans Git ! Il est donc utile de savoir comment annuler une action (en ligne de commande c’est mieux)
Défaire une modification de fichier non ajouté dans le staging area
git checkout -- nomfichier
Défaire un add
git reset fichier
Défaire un commit
# défaire le dernier commit
git reset --soft HEAD~1
# on revient à l'état où les fichiers sont ajoutés au staging area
$git reser --hard HEAD~1
#on revient à l'état où les fichiers sont non ajoutés au staging area
Défaire un commit qui été poussé
Ne plus trackere un fichier et l’ignorer du versioning
Je vous présente une commande assez peu utilisée, considérée par certain comme une pas bonne pratique. J’ai u l’utiliser dans une situation bien particulière, en effet j’étais sur develop et j’ai fait une modif dans une autre branche on va dire une feature, que j’aurais dû faire sur develop. Ok on n’est pas sensé bosser sur develop en direct !
Mais c’est un projet où j’étais tout seul, donc je me permettais quelques arrangements.
Branch bleu (develop), branche rouge (feature), je prend le commit ‘taux valeur admin OK’
Je me place dans la branche de destination, develop donc en faisant un git checkout develop
Ensuite je repère le hash du commit de la branche feature, et je fait :
$ git cherry-pick hashDuCommit
Le résultat est le suivant :
On voit que develop a maintenant le commit avec le message ‘taux valeur admin ok’
N’utilisez le cherry-pick qu’avec parcimonie, je pense que si c’est mal fait, vous risquer de mettre votre git dans un sale état.
Plutôt que de lire des données et effectuer la division en code PHP par exemple, si vous avez la possibilité, faites directement la division dans la requêtes SQL
Il y a plusieurs façons de le faire, soit avec un sous requêtes (mais il semble qu’il y ait des problèmes de performance), mais c’est le plus simple à mon avis, ou alors il faut utiliser des variables SQL locales.
Méthode avec une sous requête
Le principe est de calculer le dénominateur (par exemple) dans une sous requête, et de le mettre au dénominateur de la requête principale
# la sous requête
SELECT count(*) FROM table1 WHERE type='toto'
# la requête principale
SELECT count(*) FROM table1 WHERE type='tata'
#le tout
SELECT count(*)/
(SELECT count(*) FROM table1 WHERE type='toto')
FROM table1 WHERE type='tata'
Attention à la division par zéro (la question à se poser systématiquement quand on a une division, ce doit être un réflexe), on utilise NULLIF
SELECT count(*)/
NULLIF((SELECT count(*) FROM table1 WHERE type='toto'),0)
FROM table1 WHERE type='tata'
Récemment pour un projet, j’ai eu à faire une série de diagramme voir image ci-dessous :
Le soucis c’est que chaque mois, on n’a pas forcément chaque libellé, donc les données qui sont fournit avec une requête inner join, ne retourne rien, et j’ai des fois deux barre au lieu de 5 voir plus.
Il fallait trouver un moyen de retourner tous les libellé, même si le décompte retournait 0.
Ainsi on aura des graphiques plus harmonieux, et pas des barres de différentes tailles suivant les périodes.
Le technique : elle consiste à retourner dans un premier temps dans une sous requêtes des données faites avec un INNER JOIN, donc dans ce cas, on aura seulement deux barres, mais dans un second temps on va prendre le résultat de cette sous-requête et faire une jointure à nouveau avec la table de tous les libellés existants, mais cette fois ci avec un LEFT JOIN, ainsi on aura tous les libellés. Il faut voir le résultat de la sous requête comme une nouvelle table, c’est la clé de cette technique.
Requête d’origine menant au graphique présenté
SELECT count(*) as count, MD.ID_ETAT_MATRICE_DETAILS, MD.LIBELLE_ETAT_MATRICE_DETAILS as libelle
FROM MATRICE M
LEFT JOIN ETAT_MATRICE_DETAILS MD on MD.ID_ETAT_MATRICE_DETAILS = M.ID_ETAT_MATRICE_DETAILS
where M.ID_ETAT_MATRICE = 3 and M.DATE_SIGNATURE BETWEEN '2020-07-01' AND '2020-07-30'
AND USR_ID = '9999'
GROUP BY MD.ID_ETAT_MATRICE_DETAILS;
Nouvelle requête en transformant en sous requête la requête actuelle, et en faisant une jointure avec la table des libellés
SELECT IFNULL(count,0), C.ID_ETAT_MATRICE_DETAILS , EMD.LIBELLE_ETAT_MATRICE_DETAILS
FROM ETAT_MATRICE_DETAILS EMD
LEFT JOIN
(SELECT count(*) as count, MD.ID_ETAT_MATRICE_DETAILS , MD.LIBELLE_ETAT_MATRICE_DETAILS as libelle
FROM MATRICE M
INNER JOIN ETAT_MATRICE_DETAILS MD on MD.ID_ETAT_MATRICE_DETAILS = M.ID_ETAT_MATRICE_DETAILS
where M.ID_ETAT_MATRICE = 3 and M.DATE_SIGNATURE BETWEEN '2020-07-01' AND '2020-07-30'
AND USR_ID = '9999'
GROUP BY MD.ID_ETAT_MATRICE_DETAILS)
C on C.ID_ETAT_MATRICE_DETAILS = EMD.ID_ETAT_MATRICE_DETAILS
WHERE EMD.ID_ETAT_MATRICE = 3;
Notez que j’ai forcé à zéro le décompte si il vaut null (en effet LEFT JOIN retourne une donnée même s’il n’y a pas de correspondance, donc ça devient NULL.)
ça ne marche pas en effet, vous devez passer la fonction par référence, autrement dit vous devez passer le handler, en ajoutant des parenthèses vous exécutez la fonction. Donc on doit avoir la syntaxe suivante, mais qui amène à poser la question : mais comment on passe le paramètre data?
Il existe en Javascript la variable argument, qui fait référence aux paramètres qui sont passés, c’est un tableau commençant à l’index 0 pour le premier paramètre (donc data dans notre cas)
function callback() {
console.log(argument[0])
}
#marche quelquesoit le nombre de paramètres
Petit article pour consigner les techniques de Twig qu’on a trop tendance à oublier car peu utilisée, il est ici utilisé dans un contexte Symfony
Chercher l’url d’une route
{{ url('home') }} << ou un autre nom de route, ici on a le nom de domaine
Boucle for dans twig
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
Comment dumper une variable
Vraiment très fondamental, le dump permet de voir ce que contient une variable, et c’est un raccourci très efficace dans la connaissance d’une librairie
{{ dump(app.request) }}
Ainsi l’exemple ci-dessus peut nous donner plein d’informations sur l’objet request et ainsi nous permettre dde récuérer des informations comme path_info ou des variable de paramétrage dans les fichier de configuration de Symfony.
#exemple de dump
public 'server' =>
object(Symfony\Component\HttpFoundation\ServerBag)[16]
protected 'parameters' =>
array (size=41)
'REDIRECT_STATUS' => string '200' (length=3)
'HTTP_HOST' => string 'terrav2' (length=11)
'HTTP_CONNECTION' => string 'keep-alive' (length=10)
'HTTP_CACHE_CONTROL' => string 'max-age=0' (length=9)
'HTTP_UPGRADE_INSECURE_REQUESTS' => string '1' (length=1)
'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' (length=121)
'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' (length=124)
'HTTP_REFERER' => string 'http://terrav2/matrice/export' (length=33)
'HTTP_ACCEPT_ENCODING' => string 'gzip, deflate' (length=13)
'HTTP_ACCEPT_LANGUAGE' => string 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7' (length=35)
'HTTP_COOKIE' => string 'PH..
# pour getter le hTTP_HOST par exemple :
{{ dump(app.request.server.get('HTTP_HOST')) }}
Comment accéder à un rôle d’un user
{{ app.user.roles[0] }}
Créer un lien hypertexte
{{ url('nomDeLaRoute',{ 'param':'value'}) }}
Accès aux variables de configuration de Symfony depuis Twig : Substitution de variable
Il hy a la table Users qui contient le champ IdGroupe ,puis la table UtilisateurGroupe qui contient l’IdGroupe (jointure donc) et le libellé du groupe auquel on veut accéder
Phpmyadmin lorsque vous faites une requêtes peut ne mpas montrer toutes les données d’une celluele, ce qui est OK lrsque que vous faites une requêtes classqieu (SELECT), mais il y a des cas où vous avez besoin de connaitre une donnée en particuliers (par exemple lister la requête de création d’une table) et il vous faut toute la donnée. Voici la marche à suivre pour avoir la totalité des données
Après avoir fait votre requête, cliquez sur +Options et il y a un bouton radio FUL TEXT et voilà
exemple :
SHOW CREATE TABLE CHALLENGE
CREATE TABLE `CHALLENGE` (
`ID_CHALLENGE` int(50) NOT NULL AUTO_INCREMENT,
`ID_CHALLENGE_TYPE` int(50) NOT NULL,
`ACTIF_CHALLENGE` int(1) NOT NULL DEFAULT '1',
`LIBELLE_CHALLENGE` varchar(250) NOT NULL,
PRIMARY KEY (`ID_CHALLENGE`),
KEY `ID_CHALLENGE_TYPE_idx` (`ID_CHALLENGE_TYPE`),
CONSTRAINT `CHALLENGE_TYPE` FOREIGN KEY (`ID_CHALLENGE_TYPE`) REFERENCES `CHALLENGE_TYPE` (`ID_CHALLENGE_TYPE`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
Dans un précédent article je parlais de la création d’un application WPF en général, dans cet article on va se concentrer sur le XAML, el langage xml qui permet de disposer les élément WPF dans la fenêtre.
Concevoir son interface en XAML
Au démarrage d’une application XAML, il y a une fenêtre vide, mais le code XAML n’est pas vide pour autant. Il y a un code minimal :
Toujours sur un serveur dédié, et sous Debian voici la procédure à faire pour accélérer votre site web:
Installez APC : aptitude install php-apc
Configurer le fichier php.ini en éditant le ichier « /etc/php5/conf.d/apc.ini » et en ajoutant: apc.enabled=1 apc.shm_segments=1 apc.shm_size=128
Redémarrez Apache
Créez une page web pour pourvoir monitorer les performance de ce cache (remplacez mysite par le bon répertoire de votre serveur) :gzip -dc /usr/share/doc/php-apc/apc.php.gz > /home/mysite/public_html/apc.php
Le fichier info.plist contient les informations diverses et variées mais importantes sur votre application que vous allez déployer sur l’Appstore
Récemment pour résoudre le problème d’une application rejetée car ne fonctionnant pas sur Ipad, j’ai dû trouver un moyen pour forcer le déploiement sur iphone. Même sur Stackoverflow c’était pas clair pour beaucoup de gens qui pensaient que ce n’était pas possible.
Après un build Ionic, le fichier info.plist se trouve sur dans /platform/ios/nom-appli/nom-appli-Info.plist.
L’éditer avec un éditeur de texte, et ajouter une clé UIRequiredDeviceCapabilities
Pourquoi vous devez éditer le fichier directement, parce que il me semble que dans Xcode lui même je ne pouvais pas ajouter la clé manuellement (bug?)
Note 1 : Si vous avez ce message parce que vous avez essuyé un refus, puis refait un upload, il vous faut aller dans « General » et « Build » et incrémenter le numéro de build. Un numéro de build correct doit être un entier, il est différent de la version de l’application. En incrémentant le numéro de build vous n’avez pas besoin de changer le numéro de version de l’application pour resoumettre.
Note 2 : si vous avez une application ciblant Iphone et Ipad, vous ne pouvez plus dans une version ultérieure restreindre aux Iphone seulement.
ReactJS à la différence de Angular et de VueJS, est une librairie qui s’occupe uniquement de la vue, très véloce, grâce à l’utilisation d’un virtual DOM. Le principe es de ne mettre à jours que ce qui est nécessaire.
Mise en place du projet
$ npx create-react-app myApp
# npx fourni depuis la version npm@5.2.0 est sensé vous faciliter la vie, si npx <command>, et que la <command> n'est pas dans le PATH, iil est capable d'installer la commande depuis NPM et l'invoquer.
# sortie de la commande npx create-react-app
Initialized a git repository.
Success! Created jeu at /Users/poste5hookipa/sites/reactapplication/jeu
Inside that directory, you can run several commands:
yarn start
Starts the development server.
yarn build
Bundles the app into static files for production.
yarn test
Starts the test runner.
yarn eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back!
We suggest that you begin by typing:
cd jeu
yarn start
Votre MacBookPro livré, il faut maintenant installer un environnement d’exécution pour vos sites web, et aussi un environnement de développement.
Pour ce qui est de l’environnement d’exécution, reportez vous à ces liens:
Pour ce qui est de l’environnement de développement, nous allons voir dans les lignes qui suivent les opérations à faire
Installation de Xcode ou Xcode Command Line Tool (CLT)
Pourquoi installer Xcode CLT? il est nécessaire pour exécuter certaines commandes en Shell, notamment pour installer Homebrew le gestionnaire de package de MacOS.
Pour vérifier si vous avez déjà mis en place(on en sait jamais) Xcode CLT, vous pouvez tapez les commandes:
$ gcc
# ou
$ xcode-select -p
Si Xcode CLT n'est pas installé, vous aurez une popup vous invitant à l'installer.
Choisissez bien le package, il y a beaucoup de fichiers listés, et vous risquez de ne pas télécharger la bonne version, classez dans un premier temps par date et regardez le nom commençant par « Command line tools for Xcode xx », et regardez bien la version de Xcode la plus récente.
# testons voir si c'est bien installé
$ xcode-select -p
/Library/Developer/CommandLineTools
# c'est bon c'est installé
Installation de Homebrew
Maintenant que Xcode est installé, nous pouvons faire la ligne de commande suivante pour installer Homebrew, qui va nous permettre d’installer MySQL et autres applicatifs.
#il est conseillé d'installer Homebrew sous /usr/local/homebrew
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Installation des logiciels
MySQL
#la version par défaut de MySQL est la 8 pour Homebrew
#si on veut la 5.7 voici les étapes
# montrer les infos de la version 5.7
$ brew info mysql@5.7
mysql@5.7: stable 5.7.29 (bottled) [keg-only]
#installation
$ brew install mysql@5.7
We've installed your MySQL database without a root password. To secure it run:
mysql_secure_installation
MySQL is configured to only allow connections from localhost by default
To connect run:
mysql -uroot
mysql@5.7 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have mysql@5.7 first in your PATH run:
echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profile
For compilers to find mysql@5.7 you may need to set:
export LDFLAGS="-L/usr/local/opt/mysql@5.7/lib"
export CPPFLAGS="-I/usr/local/opt/mysql@5.7/include"
To have launchd start mysql@5.7 now and restart at login:
brew services start mysql@5.7
Or, if you don't want/need a background service you can just run:
/usr/local/opt/mysql@5.7/bin/mysql.server start
==> Summary
🍺 /usr/local/Cellar/mysql@5.7/5.7.29: 319 files, 232MB
==> Caveats
==> openssl@1.1
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
/usr/local/etc/openssl@1.1/certs
and run
/usr/local/opt/openssl@1.1/bin/c_rehash
openssl@1.1 is keg-only, which means it was not symlinked into /usr/local,
because openssl/libressl is provided by macOS so don't link an incompatible version.
If you need to have openssl@1.1 first in your PATH run:
echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.bash_profile
For compilers to find openssl@1.1 you may need to set:
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
==> mysql@5.7
We've installed your MySQL database without a root password. To secure it run:
mysql_secure_installation
MySQL is configured to only allow connections from localhost by default
To connect run:
mysql -uroot
mysql@5.7 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have mysql@5.7 first in your PATH run:
echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profile
For compilers to find mysql@5.7 you may need to set:
export LDFLAGS="-L/usr/local/opt/mysql@5.7/lib"
export CPPFLAGS="-I/usr/local/opt/mysql@5.7/include"
To have launchd start mysql@5.7 now and restart at login:
brew services start mysql@5.7
Or, if you don't want/need a background service you can just run:
/usr/local/opt/mysql@5.7/bin/mysql.server start
Lisez bien les information ci-dessus pour savoir comment démarrer, arrêter, et faire quelques opérations en ligne de commande.
Il est l’équivalent de plusieurs fonction de cycle dans les composant de classe. Il remplace ComponentDidMount, ComponentDidUpdate.
#invocation au premier rendu
useEffect( () => {
},[])
#invocation au premier rendu et à chaque update du state
useEffect( () => {
},[variable])
#invocation uniquement à chaque update (et pas au premier chargement)
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false; //grâce à cette astuce on bypasse l'exécution du code d'update au premier rendu
} else {
// le code pour chaque update
}
});
Une des choses qui m’énervent le plus (et les développeur) est que dans certains processus de build avec NodeJs, on est confronté à des erreurs qui résultent de droits d’accès à des répertoires parce qu’on n’est pas utilisateur root. Ce problème se produit surtout en environnement MacOS et Linux. sous Windows vous travaillez en Administrateur en général.
Sur le site de NPM, il vous est expliquée ue procédure d’installation de NodeJS qui vous évite cet écueil. Le principe consiste à changer le répertoire par défaut de NPM.
D’abord il faut installer l’environnement de développement. Pou rle JDK, Gradle,NodeJS, n’oubliez pas de configurer la variable Path!
Installation de JDK
Pour ce faire il vous faut aller sur le site d’Oracle et créer un compte 🙁
Installation de NodeJS (donc de NPM)
Installation de Ionic et cordova
Installation de Android Studio
Lors du build vous allez avoir des erreurs, mais ce doit être minime si vous avez effectué les étapes de ci-dessus.
Gradle qui est le builder doit être installé indépendamment même s’il vient avec Android Studio (ne me demandez pas pourquoi) Télécharger Gradle depuis ce site.
Premier build et possibles problèmes
Pour le premier build ou run, mettez vous en mode verbose pour voir les détail sdes potentiels problèmes :
ionic cordova run android --verbose
Problèmes possibles avec Gradle : à un moment vous pouvez avoir le message comme quoi vous n’avez pas validé la license du SDK
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':app'.
> Failed to install the following Android SDK packages as some licences have not been accepted.
platforms;android-28 Android SDK Platform 28
To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
J’ai du faire récemment une application démonstrateur (POC : proof of concept) avec Ionic et des iBeacon, devant le peu d’information je pose un petit tuto par ici en espérant que ça peut servir, n’hésitez pas à poser des questions j’aurais peut être réponse.
Ibeacon qu’est ce que c’est?
Un iBeacon est un objet électronique qui émet des signaux bluetooth à intervalles réguliers. Il émet un seul message, qui contient des données. Et si un smartphone est équipé du Bluetooth et un programme pour capter ces messages, il peut les interpréter et par exemple faire une action. Un iBeacon est un device qui doit être positionné de façon fixe. Il sert de repère géolocalisé. Une application exemple est celle d’un musée, si vous êtes équipé de l’application du musée, et que vous vous présentez devant un tableau, l’application peut vous fournir des informations sur ce tableau.
En commerce, le filon est exploité de façon un peu différente : quand vous disposez de l’application de la chaine de magasins, si vous passez à proximité, vous recevez une notification push sur une promotion.
Le iBeacon est capable d’émettre sur 70m ! en Bluetooth low energy (BLE), de fait un distingue 3 zones, proximité immédiate, proximité, et éloigné.
Ibeacon est une émanation de Apple, Google a répliqué avec les eddystones. Il y a une différence entre les eddystones et les ibeacons, les devices sont identifiés par leur uuid, un identifiant qui est sensé les rendre unique. Une des différences à ma connaissance est que sur IOS, il faut connaitre à l’avance les uuid de vos iBeacons, sinon votre application IOS ne verra rien. Par contre une application Android avec des eddystones pourra scanner tous les eddystones se trouvant à proximité, même si ces derniers n’ont pas le même uuid que celui mis dans l’application.
Ionic qu’est-ce que c’est?
Ionic est un framework de développement d’application mobile, vous développez des applications sans avoir à connaitre Java, ni Swift. Donc c’est destiné aux développeurs d’application web, qui n’auront pas besoin d’avoir la douleur d’apprendre un nouveau langage. Ceci dit, le plus difficile au début c’est de comprendre comment fonctionne Ionic.
Ionic est basé sur Cordova, une solution open source d’application mobile en y ajoutant une couche plus « native ». Depuis la version 3 il fonctionne avec le framework Javascript Angular 2+ et le langage est TypseScript, une surcouche de Javascript en plus typé. En mode développement, l’application peut être vue sur un navigateur web. Vous pouvez ensuite déployer sur une des plateforme prise en charge (Android ou IOS), et il vous faudra disposer de Android Studio pour faire marcher dans un émulateur virtuel Android, et de Xcode pour émuler sur un device IOS.
Vous pouvez aussi déployer sur un smartphone en phase de développement, ceci est nécessaire car nous utilisons des fonctionnalités disponibles seulement sur un device physique.
Il faut savoir que si vous êtes sur Windows, vous ne pourrez pas déployer sur IOS. Par contre sur Mac, vous pourrez déployer sur IOS et Android.
Bootstrapper une application ionic
ionic start MyApp --type=ionic-angular
Importer les librairies pour iBeacon
#installation des librairies
Paramétrer vos iBeacons : importante distinction entre les iBeacons et les EddyStones (rappel)
Pour configurer les iBeacons, téléchargez l’application iBKS config. Reportez vous à la documentation pour paramétrer chaque iBeacon, un peu laborieux au début.
Note : uuid doit être en minuscule ! pas de trait d’union pour paramétrer l’uuid dans le iBeacon.
Déployer l’application Ionic sous IOS
Note : Pour builder pour Android, voir cet article pour builder une application Ionic sous Windows, c’est à peu près la même chose, mais sachez que vous avez besoin d’un Mac pour builder pour IOS, impossible de faire autrement que d’investir dans un macbook PRO par exemple (16 Go de RAM conseillé)
Déployer pour le device
ionic cordova build ios --device
Ensuite allez dans le répertoire projet et les sous répertoire /platforms/ios et cliquez sur le fichier .xcodeproj pour ouvrir Xcode. Configurez Xcode pour le lier à votre compte développeur Apple sans quoi vous ne pouvez rien faire. En effet vous devez créer un provisioning profile.
Ensuite cliquez sur la liste des devices en haut à gauche, puis sur le triangle noir pour déployer sur votre device.
Déployer pour la production IOS
ionic cordova build ios --prod
Répétez les mêmes process que précédemment, mais en buildant vous aurez une erreur de type code signing ou pas suivant si vous avez sélectionné le certificat que vous aurez créé pour votre application. Pour paramétrer le certificat, il faut aller dans votre projet dans Xcode (icône bleue dans la sidebar), puis General puis la section Signing et cochez la case « Automatically manage signing »
Cliquez sur à côté du triangle noir en sélectionnant dans la liste le device Generic ou si vous avez un device branché, le device correspondant. En fait il faut sélectionner Generic Device lorsque vous n’avez pas de device branché.
1 – Création de l’archive
Ensuite allez dans Produit > Archive dans le menu en haut de l’écran de votre Mac, l’archivage se lance et une nouvelle fenêtre se lance.
2 – Choix du type de distribution
3 – Optionnel : App thinning
4 – Le chemin de votre archive sur le site web
5 – Export de l’IPA
6 – Installation over the air
Une fois que vous avez mis votre archive en ligne, vous pouvez le télécharger depuis le l’adresse paramétré à l’étape 4.
Une fois téléchargé, l’application ne se lancera pas, vous avez un avertissement de droit. Pour autoriser l’application, allez dans Paramètres, Général > Gestion de l'appareil > App d'Entreprise (Nom entreprise) puis cliquer sur Faire confiance à « Nom Entreprise ».
Le fichier contenant le lien pour télécharger l’archive :
<html>
<head>
<title>Mon application</title>
<meta name="viewport" content="width=device-width" />
<meta charset="utf-8">
</head>
<body>
<ul>
<li><a href="itms-services://?action=download-manifest&url=https://www.monsite.fr/app10/manifest.plist">Installer/MAJ New App IBeacon V 1.0.12 Build 1</a></li>
</ul>
<p>Instruction : Après installation allez dans Paramètres, Général > Gestion de l'appareil > App d'Entreprise (Mon entreprise) puis cliquer sur Faire confiance à "Mon entreprise"</p>
</body>
</html>
Débugger votre application sur un device
Il est possible de débugger votre application même s’il tourne sur un smartphone, pour ce faire, si c’est pour Android, il faut ller à l’url :
chrome://inspect/#devices
Si votre smartphone est connecté par USB et que vous avez autorisé le debug par USB dans les paramètres de votre smartphone,dès que l'application tourne (après avoir fait la commande : ionic cordova run android --device )
vous aurez l'option pour ouvrir une nouvelle fenêtre :
Le bundle généré par la précédente commande n’est pas signée, il faut le faire manuellement. Pour ce faire il faut générer une clé, si vous avez déjà la clé, passer cette étape
Il vous sera demandé un mot de passe pour le keystore, un fichier nommé my-release-key.keystore sera créé. CE FICHIER EST ULTRA IMPORTANT NE LE PERDEZ PAS ! il n’est pas versionné de base.
Maintenant on est prêt à déployer sur Google Play !!
Note sur Android App Bundle (.aab)
C’est un nouveau format qui permet une taille d’application plus réduite. C’est le format du futur qui remplacera le format apk. L’idée est de laisser la plateforme Google Play optimiser le code pour vous, et l’on obtient une taille d’application diminuée de moitié par rapport à un apk (sur un apk de 50 Mo)
Note si pas de réseau sur la version déployée sur Android
A partir du SDK28 (ou 27) vous ne pouvez plus faire de requêtes vers les url non sécurisées, sauf si vous ajoutez une directive dans AndroidManifest.xml
Pour lancer un test unitaire (cela suppose que vous avez installé ce qu’il faut pour lancer les tests):
./bin/phpunit
#pour lancer un test en particulier
./bin/phpunit tests/Utils/HelperTest.php //indiquer le chemin complet
Pour les tests fonctionnels, on va faire comme si on avait un navigateur (mais ce n’est pas un vrai navigateur au sens où l’on démarre vraiment Google Chrome ou Firefox, pour ça il faut voir le plugin Panther)
Le cod eminimal pour ce genre de test est :
<?php
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Controller\SecurityController;
class RouteTest extends WebTestCase
{
public function testLoginRoute()
{
$client = static::createClient();
$client->request('GET', '/login');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
}
En fait on se sert du code PHP directement pour faire le rendu logique de la page. Pour se logger on fera de la manière suivante :
public function testAdminLoginToApp()
{
$client = static::createClient([], [
'PHP_AUTH_USER' => 'moi@mail.com',
'PHP_AUTH_PW' => 'monpass',
]);
// go to dashboard
$crawler = $client->request('GET', '/dashboard');
$elem = $crawler->filter('html > body > div > h1');
// Verify the text in h1 as a proof i'm in
$this->assertEquals('Dashboard', $elem->text());
}
A la création du client, on injecte les identifiant et mot de passe, et on est loggé. Ensuite on émule le crawler en lui passant une requête de type GET. Puis on va explorer le DOM en utilisant la fonction filter pour extraire un élément du DOM
Suivre une redirection
Il est possible de suivre une redirection :
$crawler = $client->request('GET', '/dashboard');
$crawler = $client->followRedirect();
$elem = $crawler->filter('html > body > div > h1');
Les tests fonctionnels peuvent prendre du temps, à la différence des test unitaires, vous pouvez vous rendre compte du temps avec la commande shell suivante :
time ./bin/phpunit
Restreindre le coverage des tests
Dans le fichier phpunit.xml.dist, vous pouvez indiquer les répertoires dont les tests seront exécutés.
Cette méthode est intéressante pour affiner votre contrôle d’un champ de formulaire. Par exemple nous allons ajouter un contrôle d’unicité de numéro de téléphone. Nous allons créer depuis le terminal un validateur
Création du validateur
php bin/console make:validator
Un prompt vous demande le nom de la classe validateur
The name of the validator class (e.g. EnabledValidator):
> UniquePhoneValidator
created: src/Validator/UniquePhoneValidator.php
created: src/Validator/UniquePhone.php
On doit avoir deux classes, UniquePhone qui va servir pour créer l’annotation et UniquePhoneValidator qui contient le code qui va faire le contrôle d’unicité proprement dit.
Ensuite l’entité sur laquelle cette vérification va se faire, imaginons qu’on ait une entité Contrat, importons la classe créée qui se trouve dans la répertoire validator
Préparation de la classe UniquePhone
Pour pouvoir utiliser les annotation plus tard, nous devons importer une classe
<?php
namespace App\Validator;
use Doctrine\Common\Annotations\Annotation\Target;//ajouté
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY","METHOD","ANNOTATION"}) // ajouté
*/
class UniquePhone extends Constraint
{
/*
* Any public properties become valid options for the annotation.
* Then, use these in your validator class.
*/
public $message = 'Le numéro de téléphone {{ value }} existe déjà.'; // modifié
}
Préparation de la classe UniquePhoneValidator
<?php
namespace App\Validator;
use App\Repository\MatriceRepository;//ajouté
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class UniquePhoneValidator extends ConstraintValidator
{
private $matriceRepository;v // on a besoin du repository pour faire le check
public function __construct(MatriceRepository $matriceRepository)
{
$this->matriceRepository = $matriceRepository;
}
public function validate($value, Constraint $constraint)
{
/* @var $constraint \App\Validator\UniquePhone */
$existingPhone = $this->matriceRepository->findOneBy(['clientTelFixe' => $value]); // ajouté
if(!$existingPhone){ // ajouté
return;
}
// TODO: implement the validation here
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $value)
->addViolation();
}
}
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Validator\UniquePhone;
Ensuite plus loin nous avons la propriété ( le champ) qui sera concernée par cette vérification.
Remarquez que tout se fait par annotation, c’est Doctrine qui se charge de faire marcher ces annotations. Donc il suffit d’ajouter l’annotation@uniquePhone() aux deux propriétés de l’entité pour activer la vérification.
Contrainte sur une classe entière
Pour placer l’annotation sur une classe et non sur une méthode, vous devez modifier la classe de contraint UniquePhone
<?php
namespace App\Validator;
use Doctrine\Common\Annotations\Annotation\Target;//ajouté
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY","METHOD","ANNOTATION","CLASS"}) // modifié
*/
class UniquePhone extends Constraint
{
/*
* Any public properties become valid options for the annotation.
* Then, use these in your validator class.
*/
public $message = 'Le numéro de téléphone {{ value }} existe déjà.'; // modifié
public function getTargets()
{
return self::CLASS_CONSTRAINT; // ajouté
}
}
On a modifié l’annotation Target pour ajouter CLASS, et on a ajouté la méhode getTargets() pour que le validator puisse retourner la classe. Et au dessus de l’entité, enlever les annotations au dessus des propriétés de l’entité pour mettre au dessus de la class.
* MyEntity
* @UniquePhone()
....
class MyEntity
{
...
Modifier la classe UniquePhoneValidator, cette étape est très importante sinon le messagene s’affichera pas. $value représente désormais la classe, et plus le numéro de téléphone (évidemment),
class UniquePhoneValidator extends ConstraintValidator
{
private $matriceRepository;
public function __construct(MatriceRepository $matriceRepository)
{
$this->matriceRepository = $matriceRepository;
}
public function validate($value, Constraint $constraint)
{
/* @var $constraint \App\Validator\UniquePhone */
// at matrice creation we do the check,
if (is_null($value->getIdMatrice())) {
$existingPhone = $this->matriceRepository->findOneBy(['clientTelFixe' => $value->getClientTelFixe()]);
} else {
// at edition we do not do the check
return ;
}
if (!$existingPhone) {
return;
}
// TODO: implement the validation here
$this->context->buildViolation($constraint->message)
->atPath('clientTelFixe') // la propriété concernée par la contrainte, avec cette ligne le message d'erreur s'affichera
->setParameter('{{ value }}', $value->getClientTelFixe())
->addViolation();
}
}
Note sur la vérification d’unicité
Cela fait beaucoup de travail pour une simple vérification d’unicité, je vous suggère de garder à l’idée qu’une vérification clientside peut être utile et plus simple, couplé à une requête Ajax.
#dans le fichier info.plist
<key>NSCameraUsageDescription</key>
<string>Usage de camera</string>
#dans le fichier Podfile
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
#après faites un
cd ios && pod install
Le provisioning profile vous permet de développer et déployer des application mobile sur IOS.
Pour qui n’a jamais fait, c’est un véritable challenge, tant sur la complexité et le sens obscure des mots techniques.
C’est quoi un provisioning profile? Avant tout dites vous que Apple a envie de tout controler, et veut s’assurer qu’on montre patte blanche avant de pouvoir utiliser sa plateforme. Ainsi pour installer une application, à la différence d’Android, il faut que votre application soit signée électroniquement. Et c’est là qu’intervient le provisioning profile.
Résumons : pour pouvoir installer votre application sur un device IOS, il vous faut un compte développeur sur developer.apple.com, il vous en coûtera 99 euros au minimum par an.
En phase de développement, vous choisissez quelle application doit tourner sur quel device (c’est très limitatif, mais c’est Apple !)
Le provisioning profile se construit à partir de l’id du device physique (UDID), du certificat (qui lui même est fait à partir du CSR qui est généré plus tôt)
Le provisioning profile est à télécharger depuis votre compte développeur sur votre ordinateur pour pouvoir dans XCode builder votre application. Ce provisioning profile sera ensuite mis sur votre device, sans quoi votre application ne pourra démarrer. Ceci peut arriver quand vous avez un provisioning profile effacé du compte développeur, vous pouvez installer l’application, mais elle ne démarrera pas (voire ne s’installera pas)
Le development certificate : nécessaire pour tester une application sur une device physique (pour un émulateur pas besoin)
Unique Device Identifier, le UDID de votre device (grâce à Itunes vous pouvez le voir en connectant votre device à votre Mac, oui si vous n’avez pas de Mac, vous pouvez oublier les app IOS, il est possbile de contourner, mais est ce que le temps perdu à bidouiller en vaut-il la peine?
App ID, c’est l’Id de votre application (à créer sur le compte développeur)
Les étapes de création du provisioning profile:
créer un CSR (Certificate Signing Request)
sur votre compte développeur créez une application (il aura un AppId)
composer votre provisioning profile ensuite
Créer un CSR
Ouvrir l’application Trousseau D’accès (Keychain en anglais) et aller dans Certificate Assistant > demander un certificat. Enregistrez le
Sauvez votre certificat, allez dans votre compte développeur Apple, allez à la section « Certificates, Identifier & Profile », cliquez sur le + pour créer un certificat, uploader votre CSR, et un certificat (fichier avec extension .cer)sera généré que vous allez télécharger. Sur votre Mac, double cliquez sur ce certification pour le mettre dans le trousseau (keychain). Votre certificat a une durée de validité.
Si vous avez pris le soin de nommer votre clé, vous verrez dans votre trousseau la clé publique et privée. On peut passer à la suite
Sur le compte Apple, créez l’app Id (ou BundleId)
Il s’agit , allez dans la rubrique « Identifier », cliquez sur le +, vous allez créer une application avec un nom et un reverse domain (nom de domaine inversé en guise d’identifiant technique)
Ajoutez un device physique (entrez le UDID de votre appareil)
Pour une application React Native, allez dans le Finder, le répertoire IOS, et cliquez sur le fichier avec extension xcworkspace et non celui avec l’extension xcodeproj .
Créez votre provisioning profile
Enfin nous y sommes pour cette partie importante ! Allez dans la rubrique « Profile », créez un profile.
En phase de développement, choisissez « Development », pour déployer sur le store, ce sera un « Distribution » provisioning profile. Sur l’écran suivant vous allez choisir sur quelle application vous allez créer ce provisioning profile.
Enfin sur l’écran suivant, sélectionnez le certificat (le fichier avec extension .cer que vous avez téléchargé plus tôt)
Après avoir choisi le certificat (qui représente votre ordinateur Mac en fait) vous allez affecter au device (que vous avez entré plus tôt)
Ensuite vous pouvez télécharger votre provisioning profile, mais ce n’est pas nécessaire si vous laisser XCode gérer le signin automatiquement (recommandé)
Vous avez fini votre application et vous êtes sur la dernière ligne droite?
Pour avoir une application mobile professionnelle, il vous faut les icônes qui vont bien et le splash screen.
Image du splash screen, il est conseillé d’avoir une image de 3000 x 3000 pixels, et pour les icônes, il faut aussi une grande image, la méthode présentée va générer les différentes résolutions. icon.png sert de base à la génération d’icône, et monSplash.png à la génération du splash screen
Télécharger les packages npm nécessaires :
npm i @bam.tech/react-native-make
npm i react-native-splash-screen
# pour IOS il faut faire un pod install
cd ios && pod install
# génération du splash
# If you are using our cover splash
react-native set-splash --path "monSplash.png" --resize cover
#génération des icônes (pour Android et IOS)
react-native set-icon --path "icon.png"
La façon la plus commune que j’ai vu jusqu’à ce jour de créer une date en PHP est:
$today = date('Y-m-d')
la fonction date() et la classe DateTime
Traditionnellement on utilise date(), mais il existe aussi une classe DateTime, d’une utilisation plus complexe (car orienté objet et possédant plus de méthode et attributs). Voyons comment créer une date avec cette classe :
Ajouter des jours
$date = new DateTime(); // date d'aujourd'hui
#ajouter une durée à un objet DateTime
# on ajoute un DateInterval
$date = new DateTime('2020-06-01');
$date->add(new DateInterval('P10D'));// ajoute 10 jours
echo $date->format('Y-m-d') . "\n";//on formate pour pouvoir afficher
on le voit sur l’exemple de l’ajout de durée, l’écriture est un peu plus lourde?La documentation officielle de PHP vous donnera plus d’informations. Le framework Symfony utilise l’objet DateTime.
Enlever des jours
# soustraire une durée DateInterval à un objet DateTime
$date = new DateTime('2020-06-01');
$date->sub(new DateInterval('P10D'));// enlève 10 jours
echo $date->format('Y-m-d') . "\n";
strtotime() est une fonction qui convertit une date en un temps UNIX, en seconde compté depuis le 1 Janvier 1970, ce jour est appelé EPOCH. Donc elle vous donne le nombre de secondes écoulées depuis EPOCH. Documentation officielle de strtotime()
strtotime est une fonction puissante, qui permet de convertir en temps UNIX une date même si elle exprimée dans différents formats.
Là où strtotime est très utile, c’est justement sa capacité à convertir en UNIX timestamp (ou temps UNIX) différents format de date, permettant ainsi de faire des manipulation de date.
Ajouter une journée à une date
Nous allons voir comment ajouter simplement une journée à une date
$format_us = '2020/06/16';
$timestamp = strtotime($format_us );
$format_fr = date('d/m/Y',$timestamp);
echo $format_fr; // 16/06/2020
#à noter que strtotime() selon la documentation "essait" de lire une date, il peut arriver qu'il ne parvienne pas à le faire.
#il n'y a pas vraiment de conversion automatique, on se sert de strtotime pour normaliser une date, en le convertissant en secondes.
Ajouter un fuseau horaire à une date
Parfois Javascript n’arrive pas à instancier une date si le string de la date n’est pas bien formé. Par exemple :
#format date envoyé par php :
date = '2020-06-12 12:21:22'
var d = new Date(date) // null
#il faut formater la date
date = '2020-06-12T12:21:22'
# pour ce faire lorsque que vous avez une date en PHP du type :
'2020-06-12 12:21:22'd, il faut utiliser strtotime :
$date = date('Y-m-d\TH:i:s',strtotime($abo['2020-06-12 12:21:22']) )
echo $date; //2020-06-12T12:21:22
TODO:
étant donné un mois, trouver le premier jour du mois précédent