Truc 18 : Un système CRUD Angular-Mysql-PHP fonctionnel. (Lecture-Ecriture-Mise à Jour-Suppression)

Introduction


Lorsque l’on crée une application MVC avec AngularJs, vient un moment ou se pose la question de la persistance des données(Autrement dit, la sauvegarde des données) .

4 Solutions existent :

1. Localstorage : Sauvegarder dans la mémoire du navigateur les objets Json

2. MongoDb : Avec un stack MEAN qui stocke de l’objet Json.

3. Un sytème Crud PHP en Back End avec une base de données relationnelle (Mysql).

4. Un système Crud en Java en Back End avec une base de données relationnelle(Mysql).

Nous allons voir un exemple d’un système Crud en PHP à tester ici .

DESCRIPTION :


J’ai Copié sur le  code de

https://github.com/Maddyzone/CRUD-In-AngularJS-with-Php

, je l’ai traduit en Français(sauf les noms des variables) et me suis assuré qu’il marche bien.

http://tech-blog.maddyzone.com/javascript/perform-addeditdeleteview-php-using-angular-js

J’ai remarqué qu’il avait bien organisé son code, ce qui est une bonne base pour commencer.

Le code est assez générique. J’ai supprimé tout ce qui ne m’intéressait pas.

Pour faire simple, y’a 4 fichiers :

1. La vue qui s’appelle angular_example.html qui contient l’appel aux librairies et la vue.

2. Le controleur qui est dans un fichier Séparé, et qui assure la communication avec le fichier PHP

3. config.php qui comprends les paramêtres de connxion à la BDD

4. db.php qui se connecte à la Base de données Mysql.

Voici un schéma de ce qui se passe lors de l’utilisation de l’application :

VUE ANGULAR-> CONTROLEUR ANGULAR -> FICHIER PHP -> MYSQL

MYSQL -> FICHIER PHP -> CONTROLEUR ANGULAR -> VUE ANGULAR

Remarque importante : Il a conservé les appels CRUD dans le controleur Angular, alors qu’il aurait fallu faire une factory Angular dédiée au CRUD. Je pense le faire bientôt puis livrer une version modifiée.

2 ème remarque : Ce qui plait beaucoup dans son code, c’est que Angular appelle des fonctions distincte de PHP, à l’aide de la fonction $http. Par exemple $http.post(‘db.php?action=add_product’) permet d’ajouter directement un produit. C’est grâce à un Switch Case qu’il a mis dans le fichier db.php, que ça marche bien.

Mais dis moi, quel est ton but ?


Le but ? C’est de faire fonctionner en symbiose une technologie ultra moderne : AngularJS avec une techno plus ancienne, Php-Mysql pour se garder sous le coude une possibilité de faire évoluer d’anciens sites WEB ou applications WEB.

Le second But est de savoir déconstruire un objet JSON, pour l’insérer dans une base de données relationnelle. On est dans le dilemne : Un objet n’est pas structuré comme une base de données, il faut donc convertir à l’aide de la fonction json_encode et json_decode de PHP.

Le code :


En étape un, créer la base de données suivante dans mysql :


-- phpMyAdmin SQL Dump
-- version 4.0.4.2
-- http://www.phpmyadmin.net
--
-- Client: localhost
-- Généré le: Mar 14 Juillet 2015 à 21:34
-- Version du serveur: 5.6.13
-- Version de PHP: 5.4.17

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Base de données: `shopping`
--

-- --------------------------------------------------------

--
-- Structure de la table `product`
--

CREATE TABLE IF NOT EXISTS `product` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `prod_name` varchar(255) NOT NULL,
  `prod_desc` text NOT NULL,
  `prod_price` int(10) NOT NULL,
  `prod_quantity` int(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;

--
-- Contenu de la table `product`
--

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Ensuite, à la racine du serveur, on place angular_example.html, il contient la vue qui va afficher les données en live-binding, c’est du MVC :

<!doctype html>
<html ng-app="listpp" lang="fr">
<head>
	<meta charset="UTF-8">
	<title>ANGULAR CRUD AVEC PHP</title>
	<!--	APPEL LIB ANGULAR -->
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>

	<!--	APPEL LIB BOOTSTRAP -->
	<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.no-icons.min.css" rel="stylesheet">
    <link href="http://netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" rel="stylesheet">

	<!-- Le controleur Angular de cet exercice est dans un fichier Séparé. -->
	<script src="controller.js"></script>
</head>

<!-- LA VUE -->
<body id="outer" ng-controller="mysqlCtrl">

	<div>
	  <h4> Un CRUD Angular AVEC Mysql-PHP : Créer, Lire, Mettre à jour, Supprimer dans Mysql</h4>

		<h4>Ajouter un produit</h4>
		<form name="add_product">
			<input type="hidden" 	name="prod_id" 			ng-model="prod_id">
			<input type="text" 		name="prod_name" 		ng-model="prod_name" 		placeholder="Enter Product Name">
			<input type="text" 		name="prod_desc" 		ng-model="prod_desc" 		placeholder="Enter Product Description">
			<input type="text" 		name="prod_price" 		ng-model="prod_price" 		placeholder="Enter Product Price">
			<input type="text" 		name="prod_quantity" 	ng-model="prod_quantity" 	placeholder="Enter Product Quantity">
			<input type="button" 	name="submit_product" 	ng-show='add_prod' 		value="Submit" ng-click="product_submit()">
			<input type="button" 	name="update_product" 	ng-show='update_prod' 	value="Update" ng-click="update_product()">
		</form>
		<br/>		

		<table border=1  class="table table-striped table-condensed table-hover">
	      	<thead>
	      		<th>ID&nbsp;				<a ng-click="sort_by('id')"><i class="icon-sort"></i></a></th>
	      		<th>Nom du Produit&nbsp;	<a ng-click="sort_by('name')"><i class="icon-sort"></i></a></th>
	      		<th>Description du Produit&nbsp;<a ng-click="sort_by('description')"><i class="icon-sort"></i></a></th>
	      		<th>Prix du Produit&nbsp;	<a ng-click="sort_by('field3')"><i class="icon-sort"></i></a></th>
	      		<th>Quantité du Produit&nbsp;<a ng-click="sort_by('field4')"><i class="icon-sort"></th>
	      		<th>Action&nbsp;			<a ng-click="sort_by('field5')"><i class="icon-sort"></i></a></th>
	      	</thead>	      	

            <tbody ng-init="get_product()">
            	<tr ng-repeat="product in pagedItems">
			      	<td>{{ product.id }}</td>
					<td>{{ product.prod_name | uppercase }}</td>
					<td>{{ product.prod_desc }}</td>
					<td>{{ product.prod_price }}</td>
					<td>{{ product.prod_quantity }}</td>
					<td><a href="" ng-click="prod_edit(product.id)">Edit</a> | <a href="" ng-click="prod_delete(product.id)">Delete</a></td>
				</tr>
            </tbody>
        </table>
	</body>
</html>

Ensuite, on écrit le controleur Angular dans le fichier controller.js qui va gérer le CRUD, comme précisé plus haut, les fonctions concernant le CRUD devraient normalement être regroupées dans une factory. Pour l’instant, cela marche comme ça,  je le ferais plus tard.

L’Exemple de la suppression : La function ANGULAR $scope.delete appelle la fonction php correspondante dans le fichier db.php pour que tout fonctionne en Symbiose.

A remarquer la gestion des erreurs Réseau qui est incluse, avec la fonction .error , comme en Java avec Catch etc …

    var listApp = angular.module('listpp', []);    

    /* variable listApp is  a variable which used to control the array values to show the data to show in view  using the module name 'listApp' with arguments as an array */

    /* Initialize the controller by name 'PhoneListCtrl' holds the information of phone in form of array with keys name, snipper, price , quantity */

    /* $scope argument passed in function is a key arguments should be passed with exactly the same name */

    listApp.controller('mysqlCtrl', function ($scope,$http) {
    $scope.filteredItems =  [];
    $scope.groupedItems  =  [];
    $scope.itemsPerPage  =  3;
    $scope.pagedItems    =  [];
    $scope.currentPage   =  0;

    /** toggleMenu Function to show menu by toggle effect , by default the stage of the menu is false as we click on toggle button, we make it to true or show and reverse on anothe click event. **/

    $scope.menuState = false;
    $scope.add_prod = true;

    $scope.toggleMenu = function() {
        if($scope.menuState) {
            $scope.menuState= false;
        }
        else {
            $scope.menuState= !$scope.menuState.show;
        }
    };

    /** Fonction pour récupérer tous les produits de la base Mysql **/

    $scope.get_product = function() {
        $http.get("db.php?action=get_product").success(function(data)
        {
            //$scope.product_detail = data;
            $scope.pagedItems = data;    

        });
    }

    /** Fonction pour ajouter un produit à  la base mysql **/

    $scope.product_submit = function() {
        $http.post('db.php?action=add_product',
            {
                'prod_name'     : $scope.prod_name,
                'prod_desc'     : $scope.prod_desc,
                'prod_price'    : $scope.prod_price,
                'prod_quantity' : $scope.prod_quantity
            }
        )
        .success(function (data, status, headers, config) {
          $scope.get_product();
        })

        .error(function(data, status, headers, config){

        });
    }

    /** Fonction pour supprimer un objet de la base Mysql **/

    $scope.prod_delete = function(index) {  

      $http.post('db.php?action=delete_product',
            {
                'prod_index'     : index
            }
        )
        .success(function (data, status, headers, config) {
             $scope.get_product();
        })

        .error(function(data, status, headers, config){

        });
    }

    /** Fonction pour récupérer les données d'un produit existant de la base mysql **/

    $scope.prod_edit = function(index) {
      $scope.update_prod = true;
      $scope.add_prod = false;
      $http.post('db.php?action=edit_product',
            {
                'prod_index'     : index
            }
        )
        .success(function (data, status, headers, config) {
            //alert(data[0]["prod_name"]);
            $scope.prod_id          =   data[0]["id"];
            $scope.prod_name        =   data[0]["prod_name"];
            $scope.prod_desc        =   data[0]["prod_desc"];
            $scope.prod_price       =   data[0]["prod_price"];
            $scope.prod_quantity    =   data[0]["prod_quantity"];

        })

        .error(function(data, status, headers, config){

        });

	}

    /** Fonction pour METTRE A JOUR un produit de la base de données Mysql **/

    $scope.update_product = function() {

        $http.post('db.php?action=update_product',
                    {
                        'id'            : $scope.prod_id,
                        'prod_name'     : $scope.prod_name,
                        'prod_desc'     : $scope.prod_desc,
                        'prod_price'    : $scope.prod_price,
                        'prod_quantity' : $scope.prod_quantity
                    }
                  )
                .success(function (data, status, headers, config) {
					$scope.get_product();
					$scope.update_prod = false;
					$scope.add_prod = true;
                })
                .error(function(data, status, headers, config){

                });
    }

});

Ensuite, on crée le fichier d’identifiction à MYSQL, en php, config.php

<?php

  /****** Database Details *********/

    $host      = "localhost";
    $user      = "root";
    $pass      = "usbw";
    $database  = "shopping";
    $con       = mysql_connect($host,$user,$pass);

    if (!$con) {
        die('Could not connect: ' . mysql_error());
    }

    //echo 'Connected successfully'; 

    mysql_select_db($database,$con);  

    /*******************************/

?>

Pour finir, voici l’unique fichier db.php qui gère tout le système CRUD, c’est super bien, parce qu’ il est très clair et simple à débugguer. En réflechissant on pourrait pb le rendre encore plus générique, mais c’est déjà pas mal ! Clair, robuste, avec gestion d’erreur, comme en Java !

<?php

include('config.php'); 

/**  Switch Case pour récupérer la l'action demandée par le controleur  Angular **/

switch($_GET['action'])  {
    case 'add_product' :
            add_product();
            break;

    case 'get_product' :
            get_product();
            break;

    case 'edit_product' :
            edit_product();
            break;

    case 'delete_product' :
            delete_product();
            break;

    case 'update_product' :
            update_product();
            break;
}

/**  Function qui ajoute le produit en base de données MYSQL  **/

function add_product() {
    $data = json_decode(file_get_contents("php://input"));
    $prod_name      = $data->prod_name;
    $prod_desc      = $data->prod_desc;
    $prod_price     = $data->prod_price;
    $prod_quantity  = $data->prod_quantity;

    print_r($data);
    $qry = 'INSERT INTO product (prod_name,prod_desc,prod_price,prod_quantity) values ("' . $prod_name . '","' . $prod_desc . '",' .$prod_price . ','.$prod_quantity.')';

    $qry_res = mysql_query($qry);
    if ($qry_res) {
        $arr = array('msg' => "Product Added Successfully!!!", 'error' => '');
        $jsn = json_encode($arr);
        // print_r($jsn);
    }
    else {
        $arr = array('msg' => "", 'error' => 'Error In inserting record');
        $jsn = json_encode($arr);
        // print_r($jsn);
    }
}

/**  Function to LIT les produits en Base de données Mysql **/

function get_product() {
    $qry = mysql_query('SELECT * from product');
    $data = array();
    while($rows = mysql_fetch_array($qry))
    {
        $data[] = array(
                    "id"            => $rows['id'],
                    "prod_name"     => $rows['prod_name'],
                    "prod_desc"     => $rows['prod_desc'],
                    "prod_price"    => $rows['prod_price'],
                    "prod_quantity" => $rows['prod_quantity']
                    );
    }
    print_r(json_encode($data));
    return json_encode($data);
}

/**  Function qui supprime un produit en base de donnée mysql  **/

function delete_product() {
    $data = json_decode(file_get_contents("php://input"));
    $index = $data->prod_index;
    //print_r($data)   ;
    $del = mysql_query("DELETE FROM product WHERE id = ".$index);
    if($del)
    return true;
    return false;
}

/**  Functionpour lire les caractéristiques d'un produit en base mysql afin de les éditer **/

function edit_product() {
    $data = json_decode(file_get_contents("php://input"));
    $index = $data->prod_index;
    $qry = mysql_query('SELECT * from product WHERE id='.$index);
    $data = array();
    while($rows = mysql_fetch_array($qry))
    {
        $data[] = array(
                    "id"            =>  $rows['id'],
                    "prod_name"     =>  $rows['prod_name'],
                    "prod_desc"     =>  $rows['prod_desc'],
                    "prod_price"    =>  $rows['prod_price'],
                    "prod_quantity" =>  $rows['prod_quantity']
                    );
    }
    print_r(json_encode($data));
    return json_encode($data);
}

/** Function de mise à jour d'un produit **/

function update_product() {
    $data = json_decode(file_get_contents("php://input"));
    $id             =   $data->id;
    $prod_name      =   $data->prod_name;
    $prod_desc      =   $data->prod_desc;
    $prod_price     =   $data->prod_price;
    $prod_quantity  =   $data->prod_quantity;
   // print_r($data);

    $qry = "UPDATE product set prod_name='".$prod_name."' , prod_desc='".$prod_desc."',prod_price='.$prod_price.',prod_quantity='.$prod_quantity.' WHERE id=".$id;

    $qry_res = mysql_query($qry);
    if ($qry_res) {
        $arr = array('msg' => "Product Updated Successfully!!!", 'error' => '');
        $jsn = json_encode($arr);
        // print_r($jsn);
    } else {
        $arr = array('msg' => "", 'error' => 'Error In Updating record');
        $jsn = json_encode($arr);
        // print_r($jsn);
    }
}

?>
Publicités

#039, #132959, #339, #371f57, #669, #99c, #b9c9fe, #ccc, #cecece, #ffffff, #tableau1