Traitement Back-end PHP Try Catch avec réception et traitement Front-end AngularJs 1.6.5

INTRODUCTION :


Gérer les TRY CATCH dans les web service PHP, et communiquer le message contenu dans un THROW directement au FRONT END ANGULARJS

Le système de try catch PHP est puissant et pratique à utiliser, en particulier pour les problèmes de droits par exemple mais cela peut être pour n’importe quoi d’autre !!

Seulement, il faut savoir le faire communiquer avec le FRONT END !!

DETAIL


Pour info, voici le look d’une méthode de ma classe, dans le BACKEND PHP, fichier backend.php , qui enregistre les permissions, on peut voir un test de permission avant l’exécution  de la requête qui enregistre un tableau d’objets JSON décomposé grâce au foreach, l’important ici est de regarder le THROW et son message STRING ( Les contrôles de sécurité ne sont pas affichés dans cet exemple):

    /**
     * Update Permissions after front end management
     * 
     * Required Permission : $_SESSION['auth'] = true | UPDATE_PERMISSIONS
     * 
     * @return true
     * 
     * 
     */
    public function updatePermissions($jsonArray)
    {

        // Check User Permissions
        if (!$this->has_permission('UPDATE_PERMISSIONS', $_SESSION['permissions'])) {
            throw new Exception("Error : You are restricted to do this.");
        };


        foreach ($jsonArray as $index => $row) {
            $row                      = $this->escape_data_object($row);
            $id                       = $row['id'];
            $name                     = $row['name'];
            $permissions              = strval($row['permissions']);
           

            $sql = "UPDATE Job SET name='$name',permissions='$permissions' WHERE id = '$id'";
            $this->conn->query($sql);

        }

        mysqli_close($this->conn);
        return true;
    }

Le Web Service en PHP qui catche une éventuelle erreur de permission et renvoie le message d’erreur STRING du THROW pour pouvoir l’afficher directement dans le front end, (json_encode() permet de créer du JSON, compréhensible par angularJs, ou vue.js, ou angular 5 …) :

 if(!empty($_POST["updatePermissions"]) AND $_SESSION['auth']) {

    $jsonArray = $_POST["updatePermissions"];
    $jsonArray = json_decode($jsonArray,true); 
    $status = 200;

    try{
        $db->updatePermissions($jsonArray);
    } 
    catch(Exception $e){
         echo json_encode(array("response"=>$e->getMessage()));
         exit();
    } 

    echo json_encode(array("response"=>$status));

} 

Et enfin le FRONT END en ANGULARJS 1.6.5 qui traite le message d’erreur dans le .then() et affiche le STRING du THROW originel directement dans le FRONT END (Remarquez que la requête POST ajax s’adressait bien à mon WEBSERVICE en php ):

//~ AJAX CALL -> Sending whole $scope.permissions array of json objects
        $http.post(wsUrl, {updatePermissions: JSON.stringify($scope.permissions)})
            .then(function(data, headers, config) {
                console.log(data.data);

                $scope.ajaxCall = false;
                $scope.record_button_disable = false;

                // Errors management Responses
                if (data.data.response == 200) {
                    Notification.success($translate.instant('REQUESTSUCCESS'));
                    console.log("Réponse Serveur: " + data.data);

                }
                if (data.data.response != 200) {
                    Notification.error(data.data.response);
                }
            })
        }

Et enfin… Juste pour info, la petite fonction privée PHP has_permission() du cru qui permet d’ejecter les gars qui tentent de faire un truc alors qu’ils n’ont pas la permission dans leur array de permissions (séparé par ;), par le back end, hi hi . Par ecemple si il na pas la permission DISPLAY_USERS, le back end throw une erreur, et angularjs(ou vue.js) affiche le message d’erreur:

/**
	 * This function is looking for the permission inside user PHP SESSION permissions variables, if the permission is not present, then it returns false !
	 * 

	 * @return false|true
	 * 

	 */

	private function has_permission($permission, $permissions)
	{

		$permissions = explode(";", $permissions);

		if (in_array($permission, $permissions)) {
			return true;
		}

		return false;
	}

 

240px-Sheep_Shaf_Mouton.JPG‘Bhee, t »es un ouf pourquoi t’utilises pas que Php pour simplifier plutôt que de faire tout ça bhee?’

Parce que AngularJs et Javascript disposent de l’atout temps réel, d’énormément de librairies et sont très puissants, voir par exemple le jeux LARA CROFT http://xproger.info/projects/OpenLara/ avec une lib dédiée graphique js , voir Three.js, ou alors ne serait ce que D3.JS qui permet une modélisation innovante pour analyse de données, bon courage pour faire ça avec php !!!

Publicités

[AngularJs + Php MYSQL ] Une table Html infinite scroll simple, sur base de donnée

angularjsphp_1_

Introduction


Avec Angularjs 1.6 , on ne télécharge pas tout un modèle de données lorsqu’il est très grand. Par exemple, pour, afficher toute une table de log de 150 MO, évidemment, on ne charge pas toute la table d’un seul coup dans la mémoire vive, ce serait bien trop couteux. Dans d’autres cas, dans le cadre d’une vue spéciale dans une application, on peut envisager de télécharger tout le modèle de données ( Par exemple, 500 utilisateurs)

L’idée de l’infinite Scroll sur base de donnée


L’idée étant d’afficher les 20 premiers enregistrements de la table, puis ensuite, lorsque l’on atteints le bas de la page, charger les 20 suivants, puis ainsi de suite, de cette manière, l’utilisateur a la sensation d’être en temps réel.

Le problème


Le problème vient lorsque l’on commence à utiliser des filtres dans le Back End, en effet, cela complique le système car les enregistrements arrivent alors dans le désordre, et nous verront cela dans une seconde partie.

Petit Rappel de l’architecture MVC de AngularJs 1.6 ( != Angular 5) :


file-page1.jpg

UNE IDEE DE LINFINITE SCROLL EN ACTION :

infitie.jpg

PHASE 1 Le code pour une table auto incrémentale, dont aucun enregistrement n’a jamais été supprimé

LA VUE HTML

On commence à créer la table dans la vue comme ceci :

<table class="table table-hover sttable table-responsive table-bordered ">
   <thead>
      <th>Id</th>
      <th>identifiant principal</th>
      <th>sessionId</th>
      <th>ip</th>
      <th>message</th>
      <th>timestamp</th>
      <th>url</th>
      <th>data</th>
      </tr>
   </thead>
   <tbody>
      <tr ng-repeat="row in logs track by $index">
         <td>{{::row.id}}</td>
         <td>{{::row.identifiantP}}</td>
         <td>{{::row.sessionId}}</td>
         <td>{{::row.ip}}</td>
         <td>{{::row.message}}</td>
         <td>{{::row.timestamp}}</td>
         <td>{{::row.url}}</td>
         <td>{{::row.data}}</td>
      </tr>
   </tbody>
</table>

Notes :

  • Remarquer qu’il faut ajouter ‘track by $index’ au ng-repeat pour que cela fonctionne.
  • Les :: sont utiles pour debinder afin de récupérer de la mémoire, en effet, pas besoin de 2 ways binding dans un simple reporting.

Ensuite , dans mon controleur ANGULARJS 1.6, je tape les instructions suivantes :

var startRowId = 0;
$scope.read_logs = function() {

    $http.post(wsUrl, {
            read_logs: JSON.stringify({
                'startRowId': startRowId
            })
        })
        .then(function(data) {

            if (startRowId == 0) {
                $scope.logs = data.data;
            }

            if (startRowId >= 20) {

                angular.forEach(data.data, function(obj) {
                    $scope.logs.push(obj);
                })

            }

        })

}

$scope.read_logs();

angular.element($window).bind("scroll", function() {
    var windowHeight = "innerHeight" in window ? window.innerHeight : document.documentElement.offsetHeight;
    var body = document.body,
        html = document.documentElement;
    var docHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
    windowBottom = windowHeight + window.pageYOffset;
    if (windowBottom >= docHeight) {
        startRowId += 20;
        $scope.read_logs();
    }
});

Explication :

  • startRowId est la valeur de la première ligne de notre tableau et dans la table SQL simultanément (C’est ‘synchro’).
  • $scope.read_logs() est la fonction qui lit et récupère en AJAX le tableau json habituel, si startRowId est = à 0 alors, il crée tout simplement les données dans la table HTML, par contre, si startRowId >= 20, alors il sait qu’il doit AJOUTER(push) au modèle de données les données qui arrivent, et qui sont forcément les 20 suivantes dans la table logs !.
  • angular.element($window).bind(« scroll », function() est la function qui détecte quand on arrive à la fin de la page, et exécute de nouveau $scope.read_logs() tout en incrémentant startRowId de 20 , de manière à dire au back end : ‘Lit moi les 20 suivants ‘
  • angular.forEach lui ajoute au tableau d’objet JSON $scope.logs les nouveaux objets récupérés.

Le Back End qui traite la requête SQL :

// Le web Service
if(!empty($_POST["read_logs"]) AND $_SESSION['auth']) {

	$json = $_POST["read_logs"];;
	$data = json_decode($json);
	echo json_encode($db->read_logs($data),JSON_NUMERIC_CHECK); // Renvoie le tableau JSON
} 

 //~ La fonction, normalement située dans une Classe PHP, je ne peux pas tout mettre ..
 public function read_logs($data) {
     $sql = " SELECT * FROM Log ";
     if ($data - > startRowId) {
         $sql. = " WHERE id >= ".$data - > startRowId;
     }

     $sql. = " LIMIT 20";

     $responseArray = array();
     if ($result = $this - > conn2 - > query($sql)) {
         while ($obj = $result - > fetch_object()) {
             array_push($responseArray, $obj);
         }
         mysqli_free_result($result); // Free result set
     }
     mysqli_close($this - > conn2);
     return $responseArray;
 }

Explication : Si le back end reçois la variable startRowId, alors il crée la requête SQL en conséquence, à chaque fois donc que l’on atteint la fin de la page…

Conclusion :

Voilà , on a un infinite scroll qui fonctionne seulement sur une table auto incrémentale et ou aucun enregistrement n’aura été supprimé.

Cependant, comment faire si l’on veut ajouter des filtres simultanés dans la requête SQL Back End , ou si on a supprimé des lignes (row) dans notre table SQL, du coup l’id auto increment ne respecte plus le n+1 ? Cela complique bien, puisque les ‘rows’ lignes n’arrivent pas forcément dans l’ordre…
C’est ce que nous allons analyser et voir dans la seconde partie.

PHASE 2 Le code pour une table auto incrémentale, dont des enregistrements ont été supprimés

ON voit que si l’on supprime 3 enregistrements au début de notre table SQL, par exemple eux qui ont respectivement les ids 3,4 et 5 , notre script de la phase 1 ne fonctionne plus correctement, et veut toujout nous afficher le slignes à partir de l’id 20 , puis de l’id 40 puis de l’id 60 etc …. Pourquoi ? et bien c’est à cause du ’20’ statique qui est ajouté à chaque fois dans le WHERE de la requête SQL et qui fausse alors notre résultat, si les 20 premiers résultats ne sont pas une suite en n+1 !

La solution est donc de passer l’id du dernier enregistrement acquis par le front endà notre requête SQL en lieu et place du chiffre statique (20 ou 40 ou 60 etc ..), afin qu’elle ne plante jamais ! Autrement dit, à chaque fois qu’une nouvelle page s’affiche, je récupère l’ID de la dernière ligne affichée, puis l’envoie au back end, qui lui, reconstitue la requête avec le dernièr ID obtenu (PAr exemple 23), puis renvoie les 20 prochaines données !

On modifie le code en conséquence :

Le controleur

var startRowId = 0;
$scope.read_logs = function() {

    $http.post(wsUrl, {
            read_logs: JSON.stringify({
                'startRowId': startRowId
            })
        })
        .then(function(data) {

            if (startRowId == 0) {
                $scope.logs = data.data;
            }

            if (startRowId != 0) {

                angular.forEach(data.data, function(obj) {
                    $scope.logs.push(obj);
                })

            }

        })

}

$scope.read_logs();

angular.element($window).bind("scroll", function() {
    var windowHeight = "innerHeight" in window ? window.innerHeight : document.documentElement.offsetHeight;
    var body = document.body,
        html = document.documentElement;
    var docHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
    windowBottom = windowHeight + window.pageYOffset;
    if (windowBottom >= docHeight) {
       startRowId = $scope.hk_logs[$scope.hk_logs.length - 1].id;
       $scope.read_hk_logs();
    }
});

Explication : On récupère lorsqu’on a scrollé l’id de la dernière ligne affichée dans le tableau, afin de l’envoyer à la requête SQL

Phase 3 : Mais moi je veux utiliser des filtres aussi, quand je fais de l’infinite Scroll !

En fait, maintenant que l’on a résolu le problème de la dernière ligne (Qu’on aurait également pu traiter dans le back end directement), Ajouter des filtres est plutôt facile, il faut ajouter un select dans le front end, contenant les critères de filtres, puis, envoyer le critère au back end qui l’ajoute à la fin de la requête SQL, dans un WHERE :

Ma requête $http.post envoie désormais des filtres (dans le front end):


$http.post(wsUrl, {
read_logs: JSON.stringify({
'startRowId': startRowId,
'start_month_date': $scope.start_month_date,
'start_year_date': $scope.start_year_date,
'kitIdFilter': $scope.kitIdFilter,
'hkmessageFilter':$scope.hkmessageFilter,
'hkIpFilter':$scope.hkIpFilter
})
})

Puis, mon back end crée la requête SQL en conséquence :

 //~ Read LOGS
    public function read_logs($data)

    {
        $sql  = " SELECT * FROM Log WHERE 1=1";

		if($data->startRowId){

			$sql .= " AND id >= ".$data->startRowId ;
		} 

		if ($data->start_month_date) {

            $sql .= " AND MONTH(timestamp) = '" . $data->start_month_date . "'";
        }
        if ($data->start_year_date)  {

            $sql .= " AND YEAR(timestamp) = '" . $data->start_year_date . "'";
        }

		 if ($data->homekitIdFilter)  {

            $sql .= " AND kitId = '" . $data-><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>kitIdFilter . "'";
        }

         if ($data->hkmessageFilter)  {

            $sql .= " AND message = '" . $data->hkmessageFilter . "'";
        }

        if ($data->hkIpFilter)  {

            $sql .= " AND ip = '" . $data->hkIpFilter . "'";
        }

		$sql.= " LIMIT 20";

        $responseArray = array();
        if ($result = $this->conn2->query($sql)) {
            while ($obj = $result->fetch_object()) {
                array_push($responseArray, $obj);
            }
            mysqli_free_result($result); // Free result set
        }
         mysqli_close($this->conn2);
        return $responseArray;
    }

[AngularJs + Php-SQL] Astuce : Copier-Coller des CRUDS pour aller plus vite.

angularjsphp_1_logo-mysql-170x170_400x400

Introduction


Dans les applications informatique, le CRUD revient tout le temps.

Il s’agit de faire de la Creation/Lecture/Mise à jour/Suppression.

L’idée est donc de faire du copié-collé d’un crud standard, puis de changer uniquement le nom du modèle de données, en faisant « controle+h » dans notepad, afin d’aller beaucoup plus vite.

Note : Java Hibernate permettrait de faire cela encore plus simplement( méthode comin’ soon ), sans compter les méthodes de création automatiques des POJO, mais ce n’est pas le sujet de ce post … Là on est sur du back end PHP-MYSQL

Un exemple en temps réel dans une App !


Dans mon application RdvJuristes, j’ai un Crud sur les personnes :

http://nicolash.org/rdvj/index.html#/personnes

crd1.jpg

 

Il est évident que je ne vais pas me retaper tout le code pour créer un CRUD sur les juristes :

http://nicolash.org/rdvj/index.html#/juristes

crd2.jpg

On comprends qu’on a affaire à 2 modèles de données relativement similaires, que l’on peut copier-coller, puis, ensuite adapter à notre convenance.

Lire la suite

[Java + AngularJS] Une application de gestion d’élèves partagée avec Eclipse, AngularJs et Java,Jersey,Maven + Mysql en Back end. Un Français Intégral pour ce système CRUD à Services WEB!

maisonSommaire


  • Introduction
  • Une photo de la micro application
  • Le but de l’application
  • Le matériel nécessaire
  • Les liens utiles en Anglais
  • On crée le projet dans Eclipse
  • On construit le Front End
  • On crée notre table SQL  » eleves »
  • On crée notre classe Pojo « eleve »
  • On construit la classe Back End des Web Services CRUD (Lire, Créer, Editer, Supprimer)
  • On construit la classe Back End DAO(Data Access Object) qui actionne MYSQL
  • On construit la classe connexion qui permet la connexion à la base  de données.
  • On teste l’application
  • Points non traités dans cette doc.
  • Conclusion .

Introduction javalogo-mysql-170x170_400x400angularjs


Vous l’attendiez depuis longtemps, voici enfin une micro-application CRUD (Lire, Créer, Editer, Supprimer) totalement exposée, en Français intégral, combinant  Angularjs en Front End, et Java en Back end, le tout pointant sur une base de données relationelle  Mysql.

L’autre nom utilisé pour cette technologie Back end serveur est « Service Web » ou « Web Services » en Anglais.

Elaborée suite à l’analyse de plusieurs forums en Anglais, cette solution entièrement Francophone est simple et robuste et s’ajoute aux solutions Full Stack AngularJs + Php Sql(Le système le plus fiable et clair) ainsi que Angularjs + noSql

Avec cette solution, on bénéficie d’une part de l’organisation très structurée de Java pour le Back End avec les classes, et d’autre part  de la facilité d’AngularJS ( Avec par exemple le Super 2 ways binding et la multitude de librairies Front end de AngularJs pour le front end).

Java étant très utilisé dans l’embarqué, cette technique permet une communication optimisée entre le navigateur et divers matériels (Domotique, robotique etc …)

Ceci nous donne un couple gagnant pour les applications à sgbd relationels. AngularJs étant d’une flexibilité et d’une simplicité extrême. Aucune limitation dans ce système, Jointures SQL, librairiesde type NVD3.js pour les graphes, Bootstrap pour les CSS, Elaboration de Statistiques  et j’en passe !

exp Comme d’habitude, j’utilise les mots les plus simples ainsi que l’état initial des choses pour expliquer le fonctionnement de cette micro application, cependant, les concepts sont ensuite expandables à l’infini pour de grosses applications complexes.

Il faut rappeler qu’un CRUD se doit d’être réduit à sa plus simple expression lorsqu’il est expliqué, ainsi qu’à ses 4 fonctions primaires :

Lire, Créer, Editer, Supprimer.

Une photo de la micro application


 microapp.jpg

Lire la suite

#7f4614, #a65b1a, #bf691e, #d9cfb8, #f0e5cc, #fff, #ffffff

[AngularJs + PHP BackEnd] Gérer des filtres redondants

Introduction :

Post non finalisé très important , concernant la concaténation de filtres redondants dans le back end.
On peut en effet concaténer une requête SQL à des filtres contenus dans une autre fonction, c’est incroyablement utile lorsque l’on a affaire à des filtres redondants dans plusieurs applications .

J’écrirais ici ma méthode pour gérer les filtres redondants. Lorsque l’on désire coller un AND dans une requête, soumise aux critères provenant du front end, cette méthode est trop bien.
Pour l’instant c’est ici :

http://stackoverflow.com/questions/41720715/glue-a-redondant-php-code-into-several-functions

avec un exemple :

function filter($data) {
$requete =  »;
if($data->secteur){
$requete .=  » AND etude.Secteur = ‘ ».$data->secteur. »‘ »;
}
if($data->region){
$requete .=  » AND etude.region = ‘ ».$data->region. »‘ »;
}
if($data->ca_min){
$requete .=  » AND etude.ca >= « .$data->ca_min. » »;
}
if($data->ca_max){
$requete .=  » AND etude.ca ca_max. » »;
}
if($data->revenus_min){
$requete .=  » AND Zone.Revenue_Zone >= ».$data->revenus_min. » »;
}
if($data->revenus_max){
$requete .=  » AND Zone.Revenue_Zone revenus_max. » »;
}
return $requete;
}

puis, pour s’en servir dans n’importe quelle function :
$requete .= filter($data);

[AngularJs + PHP] Créer des filtres dans le back-end avec des requêtes SQL additives, pour trier des coureurs cyclistes par groupes.

php_1_angularjs

Introduction


Avec AngularJs, lorsque l’on liste plus de 2000 objets, cela devient difficile en terme de performances, de calculer les filtres avec le front end, ce qui est normal.

En d’autres termes, admettons que j’ai 5000 coureurs cyclistes à trier par un critère, il faut alors le faire dans le back end avec SQL, bien que le tri par colonne d’angularJS fonctionne encore. Ceci pour soulager grandement le front-end, et pour plus de confort utilisateur.

On doit filtrer dans le Back end, afin que le navigateur ne rame pas.

Pour cela, on ajoute des « morceaux de requêtes SQL » de type WHERE la plupart du temps, en fonction de ce que l’utilisateur va choisir dans les menus déroulants des filtres.

A noter que le système est identique, dans l’esprit, avec du Jquery Ajax, mais la syntaxe sera légèrement différente. Anoter aussi que ce système est relativement similaire dans l’esprit à des scripts en VBA que j’avais vu en professionel, ce qui indique qu’il est conforme dans l’esprit.

Il faut bien comprendre que les critères doivent être additifs, qu’il y ait 1 critère de choisi ou 15 de choisis. Autrement dit, je veux pouvoir utiliser 15 filtres en même temps si j’en ai envie … Avec cette technique, c’est possible et cela fonctionne !

POUR TESTER LA MINI APPLICATION CLIQUER ICI

Sommaire



  1. Création de la table SQL coureurs
  2. Mise en place basique d’une application AngularJS avec un tableau de coureurs cyclistes.
  3. Ajout de la vue des 2 filtres : Ville et Groupe.
  4. Ajout des requêtes AJAX (liste des cyclistes et liste pour les filtres)
  5. Elaboration du fichier back end en PHP MYSQL qui convertit et envoie le tout au format JSON.
  6. Conclusion.
  7. Annexe : Code pour Postgre.

Création de la table SQL coureurs

On crée la table suivante dans MYSQl :

CREATE TABLE `test`.`coureurs` (
`id` INT NOT NULL AUTO_INCREMENT,
`nom` VARCHAR(45) NULL,
`prenom` VARCHAR(45) NULL,
`ville` VARCHAR(45) NULL,
`groupe` VARCHAR(45) NULL,
PRIMARY KEY (`id`));

On la remplit avec des données bateau :

LOCK TABLES `coureurs` WRITE;
/*!40000 ALTER TABLE `coureurs` DISABLE KEYS */;
INSERT INTO `coureurs` VALUES (1,'Durand','Henri','Marseille','junior'),(2,'Levy','Patrick','Lille','junior'),(3,'José','Conzola','Marseilles','anciens'),(4,'Shivaa','roberto','Marseilles','junior');
/*!40000 ALTER TABLE `coureurs` ENABLE KEYS */;
UNLOCK TABLES;

Voilà, rien de plus à faire, si ce n’est remarquer la présence des groupe junior et anciens, et les villes. Ce sont ces critères qui vont nous servir à filtrer notre liste.

Mise en place basique d’une application AngularJS avec un tableau de coureurs cyclistes.

Comme d’hab on créée un arborescence de ce type sur notre serveur web :

liste1.jpg

Je n’ai pas inclus de module de routing de vues pour cet exercice.

  • Le répertoire backend contient les fichiers qui gèrent les opérations PHP-MYSQL
  • Le répertoire bower_component permet de télécharger et gérer les versions des modules optionnels (non utilisé dans cet exo) ou de télécharger bootstrap par exemple. Bower est un logiciel optionnel.)
  • Le répertoire css contient le fichier css de l’application.
  • Le répertoire js contient le code js et angularjs dans un seul fichier app.js pour cet exercice.

Voici la « vue  » principale : index.html, qui charge les libriairies, et affiche la table des coureurs cyclistes. En bas, on peut constater la présence de la vue filtres, qui peut être inclue à loisir dans d’autres vues. Normalement, la vue filtre devrait être dans un répetoire vues contenant toutes les vues.


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Neutre</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
		<!-- CHARGEMENT DES LIBRAIRIES -->
		
		<!-- JQUERY ET BOOTSRAP -->
        <script src="bower_components/jquery/dist/jquery.min.js"></script>
        <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
        <link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
		<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css">
 
        <!-- ANGULARJS -->
        <script src='bower_components/angular/angular.min.js'></script>
		
		<!-- APPLICATION PERSO -->
		<script src="js/app.js"></script> <!-- Contient pour l'exemple le controleur et les appels aux modules. -->
		<link rel="stylesheet" type="text/css" href="css/style.css">
		
		<!-- FIN DE CHARGEMENT DES LIBRAIRIES -->
  </head>

<body ng-app="neutre" ng-controller="neutreCtrl">
	
	<!-- BARRE DE NAVIGATION -->
	<nav class="navbar navbar-inverse">
		<div class="container-fluid">
			<!-- for better mobile affichage-->
			<div class="navbar-header">
				<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
					<span class="sr-only">Toggle navigation</span>
				</button>
				<a class="navbar-brand" href="#">Neutre</a>
			</div>
			<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
			</div><!-- /.navbar-collapse -->
		</div><!-- /.container-fluid -->
	</nav>
	
	
	<!-- VUE UNIQUE  -->
	<div class="row ">
		<div class="col-lg-8 " >
			 <div class="panel panel panel-warning">
				
				<div class="panel-heading"> 
					<i class="fa fa-picture-o"></i> Liste
				</div>
				
				<div class="panel-body table-responsive" style="min-height:350px;" ng-show="!collapsed" >
					
					<table  class="table table-bordered table-hover  " border="1"  >
						<thead fix-head>
						  <tr> 
							<th>Nom</th>
							<th>Prénom</th>
							<th>Ville</th>
							<th>Groupe</th>
						  </tr>
						</thead>
			 
						<tbody >
						  <tr  ng-repeat="coureur in coureurs"   >
							 <td>{{coureur.nom}}</td>
							 <td >{{coureur.prenom}}</td>
							 <td >{{coureur.ville}}</td>
							 <td >{{coureur.groupe}}</td>
							 <td ><button class="btn btn-primary">Fiche</button></td>
						  </tr>
						</tbody>
					</table>
				
				</div>
				
				<div class="panel-footer ">
				</div>
				
			 </div>
		</div>
		
		<!-- VUE DES FILTRES -->
		<div class="col-lg-4 " ng-include="'filtres.html'" ></div>
	</div>
		

</body>
</html>

Ajout de la vue des 2 filtres : Ville et Groupe.

Les filtres sont des select HTML qui seront alimentés par des requêtes SQL AJAX $http :

Voici la vue des filtres filtres.html, remarquer $parent qui permet au controleur de la vue principale de récupérer les variables ng-model correctement :

         <div class="panel panel-warning">
 
            <div class="panel-heading">
                <span class="glyphicon glyphicon-filter" aria-hidden="true"></span>  Filtres 
            </div>
 
            <div  class="panel-body " > <!-- TOUS LES FILTRES  -->
			
				<select ng-model="$parent.filtres.ville" class="form-control">
					<option value="">Villes</option>
					<option ng-repeat="ville in $parent.villes | orderBy:'villes'" value="{{ville.nom}}">{{ville.nom}}</option>
				</select><br> 
				
            
				<select ng-model="$parent.filtres.groupe" class="form-control">
					<option value="">Groupe</option>
					<option ng-repeat="groupe in $parent.groupes | orderBy:'groupe'" value="{{groupe.nom}}">{{groupe.nom}}</option>
				</select><br>
			
			</div>
 
			<div class="panel-footer text-right">
			</div>
 
         </div>

Voilà, à ce stade on a ce look dans le navigateur :

rqtsadditives1.jpg

Ajout des requêtes AJAX (liste des cyclistes et liste pour les filtres)

Voici le fichier app.js qui contient mon controleur des vues précédentes, qui va lancer des requêtes AJAX  et récupérer des données:

  • Une requête ajax qui remplit le tableau des coureurs cyclistes ( Celle ci est relancée lors de chaque nouveau choix d’un critère par un utilisateur grâce à $watch() de angular. La requête Ajax contient alors en paramêtres les critères choisis par l’utilisateur, pour que le back end PHP crée à la volée la bonne requête SQL puis retourne les données au format JSON dans la fonction de rappel de la requête Ajax $http.
  • 2 Requêtes Ajax qui remplissent tout simplement les filtres (Listes de critères), Le Back end php retourne alors une requête SQL de type de DISTINCT pour éliminer les doublons.
angular.module('neutre', [])

.controller('neutreCtrl', function($scope,$http) {

	$scope.filtres 		= {}; 	// L'objet filtre contient en temps réel les choix de l'utilisateur, dans la vue filtres.html

	/* CHARGEMENT AJAX INITIAL DE LA LISTE DES COUREURS */
   $http.post('backend/backend.php?action=get_coureurs',$scope.filtres).success(function(data){
		$scope.coureurs = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* CHARGEMENT DES LISTES DE FILTRES */

   /* CETTE REQUETE VA REMPLIR LE SELECT AVEC LES NOMS DES VILLES */
   $http.get('backend/backend.php?action=get_villes').success(function(data){
		$scope.villes = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* CETTE REQUETE VA REMPLIR LE SELECT AVEC LES NOMS DES GROUPES */
   $http.get('backend/backend.php?action=get_groupes').success(function(data){
		$scope.groupes = data;
	}).error(function(data){console.log(data);}).finally(function() {});

	/* WATCHER DES FILTRES */
	/* ON RELANCE LE CHARGEMENT DU MODELE DE DONNEES DANS LE BACK END LORS DE CHAQUE CHANGEMENT DE FILTRES PAR L UTILISATEUR DANS LE NAVIGATEUR*/
	$scope.$watchCollection('filtres', function () {
		$http.post('backend/backend.php?action=get_coureurs',$scope.filtres).success(function(data){
			$scope.coureurs = data;
		}).error(function(data){ $scope.infos = data}).finally(function() {});

	});

/* FIN DU CONTROLEUR */
});

Remarque importante : $scope.filtres est un objet JSON qui stocke en temps réel les choix de l’utilisateur dans les select des filtres… C’est ça l’astuce parce que , lors de chaque choix, $scope.filtres est renvoyé au back end afin de recréer la requête SQL additive !!

Elaboration du fichier back end en PHP MYSQL qui convertit et envoie le tout au format JSON.

Le fichier backend.php permet de créer la requête SQL évolutive qui permet d’ajouter les critères de tri, indépendamment.

<?php

/* ---------------------------------------------BONJOUR BIENVENUE DANS LE BACK END EN PDO--------------------------------------------------  */
/* -------CE FICHIER PERMET A PHP D'EXECUTER DES REQUETES SQL ET DE LES ENVOYER AU FRONT END ANGULARJS OU JQUERY ENCODES EN JSON------------  */
/* --------------------------------------------IL PERMET DE FAIRE DU CRUD (CREE LIRE METTRE A JOUR SUPPRIMER -------------------------------  */


/* ---------------------------------------Paramêtres de connexion à la bdd et php--------------------------------  */
include('connexion_config.php');
header( 'content-type: text/html; charset=utf-8' );
error_reporting(E_ALL ^ E_NOTICE); // important pour ne pas afficher les notice PHP sans cela le script ne marche pas.
 

/* ------------------------Switch Case pour récupérer la l'action demandée par le controleur  AngularJs (appel $http ajax) ou par un appel ajax provenant de jquery-----------  */
 
switch($_GET['action'])  {
    case 'get_coureurs' 	:   get_coureurs();
    break;
	case 'get_villes' 		:   get_villes();
    break;
	case 'get_groupes' 		:   get_groupes();
    break;

}
 
 
/* ------------------------Fonctions qui récupère le résultat d'une requête SQL et encodent en JSON pour AngularJS ou Jquery qui le reçois dans la fonction de rappel des requêtes $HTPP ou les services -----------  */ 
 
function get_coureurs() {
	 
	  /* Récupération des données POST */
	 $data = json_decode(file_get_contents("php://input")); 

	try 
	{   
		$DB = connection();	
		
		/* Requête de base  */
		$sql = "SELECT * FROM coureurs WHERE 1=1";
		
		/* Requêtes Imbriquées à la requête de base avec les critères de filtres provenant du front end, on colle des morceaux de requêtes en fonction des critères*/
		if($data->ville){
			$sql .= " AND ville='".$data->ville."'";
		}
		if($data->groupe){
			$sql .= " AND groupe='".$data->groupe."'";
		}
		
		
		$data = $DB->query($sql);
		
		/* Convertit en JSON le résultat */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		
		/* ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 		
	
} 
 

/*  FONCTIONS QUI REMPLISSENT LES FILTRES */
function get_villes() {
	try 
	{   
		$DB = connection();	
		$data = $DB->query('SELECT distinct(ville) AS nom FROM coureurs');
		/* Convertit en JSON  */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		/* Ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 	
} 

function get_groupes() {
	try 
	{   
		$DB = connection();	
		$data = $DB->query('SELECT distinct(groupe) AS nom FROM coureurs');
		/* Convertit en JSON  */    
		print_r(json_encode($data->fetchAll(PDO::FETCH_ASSOC)));
		/* Ferme la connexion ? */
		$DB=null;
	}  
	catch(PDOException $e) 
	{
		file_put_contents('PDOErreurs.txt', $e->getMessage(), FILE_APPEND);  
	} 	
} 
 


?>

Bien sur ne pas oublier le script qui permet la connexion à mysql connexion_config.php:

<?php
function connection(){
    static $DBH;
	$DBH = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
          $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
		  /* $DBH->query("SET CHARACTER SET utf8"); */
	return $DBH;
}
?>

Conclusion.

Avec cette architecture, il nous est possible d’exploiter les formidables ressources angularJs et ses modules additionnels, ainsi que le super back end PHP, d’une manière très structurée, et facile à dépanner, tout semble logique. Je n’ai pas mentionné qu’il faut de préférence créer une factory angularJs pour les requêtes ajax parce que c’est facultatif.

Finalement, on a une application basée sur le framework AngularJs, mais on peut filtrer les données dans le back end si on a des soucis de performance.

Si on ne veut pas utiliser AngularJs, il est également possible de faire ecela avec Jquery Ajax.

Annexe : exemple de code Postgre.

Avec Post gre, le code du back end est un peu différent :

Voici un exemple RANDOM de fonction qui retourne un resultat en tenant compte des requêtes additives :

function get_etudes() {
	// Récupère les critères des filtres provenant du front end.
	$data = json_decode(file_get_contents("php://input")); 
	
	/* Connexion à la base de données */
	$linkdb = connexion();
	
	/* Requête de base  */
	$select = "SELECT Etude.Identifiant AS Id_Etude,Enseignes.Nom AS EnseigneE,Id_CRM,Etude.Ville,Etude.Nom,Type_Etude.Nom AS TypeE,Etude.Date_Etude,Etude.CA,Etude.departement,Etude.region,Etude.secteur,Etude.surface,zone.population_zone,zone.foyer_zone FROM ((base.Etude LEFT JOIN base.Enseignes ON Etude.Enseigne=Enseignes.Identifiant) LEFT JOIN base.Type_Etude ON Etude.Type=Type_Etude.Identifiant)LEFT JOIN base.Zone ON Etude.Identifiant=Zone.Id_Etude WHERE Etude.Domaine='Alimentaire' " ;
	
	/* Requêtes Imbriquées à la requête de base avec les critères de filtres provenant du front end*/
	if($data->enseigne){
		$select .= " AND enseignes.nom='".$data->enseigne."'";
	}
	if($data->filtre_dpt){
		$select .= " AND etude.departement='".$data->filtre_dpt."'";
	}
	if($data->filtre_region){
		$select .= " AND etude.region='".$data->filtre_region."'";
	}
	if($data->filtre_secteur){
		$select .= " AND etude.secteur='".$data->filtre_secteur."'";
	}
	
	$select .= " ORDER BY Etude.Date_Etude DESC";

	$result = pg_query($linkdb, $select);
	
	if (!$result) {
	  echo "Une erreur est survenue.\n";
	  echo ($data->enseigne);
	  exit;
	}
	
	$arr = pg_fetch_all($result);
	print_r(json_encode($arr));
	pg_close($linkdb);
} 

et le fichier connexion_config pour se connecter :

<?php

function connexion(){
	session_start();

	$linkdb=pg_connect("host='192.168.0.234' port='5432' user='jojo' password='*!6SM*J9' dbname='coureurs'");

	if (!$linkdb) {
	  echo "Une erreur de connexion à la base de données s'est produite.\n";
	  exit;
	}
	
	return $linkdb;
}


?>


[AngularJs] Faire une factory AngularJs pour PHP-MYSQL : un intérêt limité.

angularjslogo-php

Introduction


J’ai fait une factory AngularJs pour gérer le back end PHP-MYSQL, MYSQL étant une base de données relationnelle, et donc très structurée et normée, ce qui est extrêmement appréciable, parfois, face à noSql.

Comme pré supposé, l’intérêt est assez limité, ça fait perdre du temps et le code n’est pas beaucoup simplifié.

La factory centralise certes les données, mais d’un autre côté, il faut écrire une chose de plus… Cela sert pour faire les tests unitaires aussi.

Du coup , il est fortement possible que je continue à faire mes appels AJAX avec $http dans les controleurs, lorsqu’il s’agit d’un back end PHP (Mais pas dans le cas d’une app en noSql).

Le but est toujours le même : Faire du CRUD : CREER, LIRE, METTRE A JOUR, SUPPRIMER

Lire la suite