Recherche sur le blog

dimanche 21 novembre 2010

[.NET] Implémentation de Linq pour .NET : ALinq

Vous désirez faire du Linq en .NET et vous ne trouvez pas d'implémentation correcte ? Alors les bibliothèques de classes ALinq sont faites pour vous. Attention cependant, vous ne pouvez les utiliser que pendant 30 jours, après la bibliothèque génère une exception de licence. Cependant vous disposerez de tous les éléments nécessaires pour créer des requêtes. Les classes, maintenant en version 2.5.2, existent pour SQLite, MySQL, DB2, PostGreSQL et d'autres systèmes de gestion de bases de données. Vous pouvez les télécharger sur le site officiel. Rendez-vous dans la section "documentation" pour plus d'informations quant à son utilisation dans votre projet .NET.

Image : site officiel.

[Web] PHP et Zend : Créer des Web Services

Dans la programmation orientée objet, vous aurez souvent entendu parler de "Web services". De tels services web sont des interfaces de programmation ou des programmes que l'on interroge pour récupérer des données. L'échange de données se fait via le protocole SOAP (pour Simple Object Access Protocol), qui est basé sur XML. Il nous est donc possible d'appeler une fonction d'un service distant, celui-ci retournant des données selon un format défini dans un fichier XML appelé WSDL (pour Web Services Description Language), qui décrit notamment le protocole de communication, le format des messages que le service peut recevoir ou envoyer et les méthodes qui peuvent être invoquées à distance. Les messages et les opérations sont décrits de manière abstraite, mais ils seront ensuite liés à un protocole réseau et traduits dans un format concret.

Les principaux éléments du WSDL

<binding>
  • Définition du protocole d'échange des données.
  • Spécifie le format des données échangées pour les opérations.
  • Possibilité d'utiliser SOAP en tant que protocole.
<port>
  • Spécifier une adresse unique pour un "binding" choisi, donc l'emplacement actuel du service.
<service>
  • Un service est un ensemble de ports, eux-mêmes associés à un "binding".
  • Décrit un ensemble de points finaux du réseau ("endpoint").

    L'utilisation de Zend Framework pour implémenter le Web Service

    Le framework Zend propose aux utilisateurs des classes qui permettent l'utilisation ou l'appel de Web Services.  Bien sûr il nous faut créer au préalable notre service ! Ensuite, il faut logiquement créer le WSDL correspondant, ou plutôt le générer grâce aux outils PHP. Mais Zend Framework nous permet de générer le descripteur de service à la volée.

    La classe du Web Service

    ini_set("soap.wsdl_cache_enabled", "0");
    require_once 'Zend/Soap/AutoDiscover.php';

    class helloWS
    {
        /**
        * @return string
        */
        public function getHello() {
            return 'Hello World';
        }
    }

    La première ligne permet de désactiver le cache afin que le descripteur soit recréé lorsque la classe du Web Service a été modifiée. On empêche ainsi le service d'être stocké en mémoire ou sur disque. La seconde ligne est comme un "import" en Java, on demande à utiliser la classe "AutoDiscover" de Zend. Elle offre des fonctions permettant par exemple de générer et envoyer le descripteur WSDL au client lorsque celui-ci l'a exigé.

    La classe décrite ici possède une fonction qui retourne une chaîne de caractères. Le commentaire, précisant le type de donnée retournée, est obligatoire. Il permet au générateur d'inclure le type de données dans le descripteur du service, pour l'opération donnée.

    A la fin de la classe, il faudra rajouter les lignes suivantes :

    if(isset($_GET['wsdl'])) {
        $wsdl = new Zend_Soap_AutoDiscover();
        $wsdl->setClass('helloWS'); // Ajouter le nom de classe
        $wsdl->handle();
    }
    else
    {
        $server = new
        SoapServer('http://yoursite.com/service/helloWS.php?wsdl');
        $server->setClass('helloWS');
        $server->setObject(new helloWS());
        $server->handle();
    }

    Ces instructions permettent de générer le WSDL mais aussi de créer un "serveur" SOAP qui utilise la classe du Web Service et un nouvel objet, basés bien sûr sur le WSDL généré.

    Sur la version testée de Zend Framework, il était impossible de créer une nouvelle instance de la classe "Zend_Soap_Server". Ainsi, comme PHP intègre déjà cette fonctionnalité, c'est cette dernière qui a été utilisée dans l'exemple, comme vous aurez très bien pu constater.

    Le code côté client

    $client = new Zend_Soap_Client('http://yoursite.be/service/helloWS.php?wsdl');
    $newString = $client->getHello();
    // Affiche la chaîne récupérée
    echo $newString;

    On crée un nouveau client de type "Zend_Soap_Client", avec comme paramètre l'URL vers le descripteur du service en question. Ensuite on appelle la fonction "getHello()" de helloWS, qui nous retourne une chaîne de caractères. On affiche celle-ci à l'écran grâce à "echo".


    Comme toujours les services web sont très pratiques surtout si on souhaite appeler des fonctions d'une librairie se trouvant sur un serveur distant, grâce aux requêtes SOAP. Il est aussi possible de communiquer dans le format JSON grâce à une autre méthode de communication qui n'existe pas telle quelle dans le framework mais qu'on peut créer soi-même.

    samedi 20 novembre 2010

    [MySQL] Bases de la création d'un événement

    Le programmateur d'événements a été introduit dans MySQL à partir de sa version 5.1. Il est donc possible de créer des tâches qui se déclenchent à une heure et une date donnée, un peu à la manière de triggers (ou en français, des déclencheurs) sauf que ces derniers sont lancés par des mises à jour de tables ou de simples lignes, par exemple. Dans le cas du programmateur, on peut déclencher une même tache plusieurs fois par jours, voire par semaine... Il y a plusieurs utilités à ça, dont :
    • Un nettoyage d'une table,
    • Une optimisation après un ajout massif de tuples (ou enregistrements), 
    • Un calcul quelconque,
    • Etc...
    Activation du "event_scheduler" de MySQL

    Il vous faudra éditer le fichier "my.ini" du répertoire MySQL. Dans le cas d'EasyPHP 5.3.3., si l'installation a été effectuée dans le dossier par défaut, vous devez vous rendre dans C:\Program Files\EasyPHP-5.3.3\mysql pour trouver le fichier de configuration en question. Ajoutez la ligne event-scheduler=VALEUR si elle n'existe pas et définissez la valeur à : 
    • 0, pour que le service de programmation d'événements ne démarre jamais ou ne puisse être démarré.
    • 1, pour que le service soit lancé mais qu'il puisse être mis en pause (suspendu) par requête.
    • 2, pour qu'il soit démarré mais directement en mode "suspendu". Une requête peut le réactiver.
    Bien sûr, MySQL doit être redémarré. EasyPHP permet le redémarrage automatique de ses services lorsque l'un des fichiers de configuration est modifié. Pour vérifier que le service est actif, utilisez la requête suivante, soit en interface de ligne de commandes, soit grâce à PHPMyAdmin :

    SHOW GLOBAL VARIABLES LIKE 'event_scheduler'

    Il est aussi possible d'activer ou désactiver le programmateur d'événements en ligne de commande en rajoutant, aux paramètres de lancement du processus "mysqld", --event-scheduler=VALEUR, où la valeur est égale à 0, 1, ou 2. Une dernière méthode a été prévue : l'utilisation de la requête SET GLOBAL, permettant d'éditer des variables d'environnement.

    Créer l'événement

    La syntaxe est la suivante :

    CREATE
        [DEFINER = { user | CURRENT_USER }]
        EVENT
        [IF NOT EXISTS]
        nom_evenement
        ON SCHEDULE schedule
        [ON COMPLETION [NOT] PRESERVE]
        [ENABLE | DISABLE | DISABLE ON SLAVE]
        [COMMENT 'comment']
        DO corps_evenement;

    schedule:
        AT timestamp [+ INTERVAL interval] ...
      | EVERY interval
        [STARTS timestamp [+ INTERVAL interval] ...]
        [ENDS timestamp [+ INTERVAL interval] ...]

    interval:
        quantité {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
          WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
          DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

    L'événement ne peut être créé que si on en a l'autorisation. Pour travailler en local sur votre projet, l'utilisateur 'root' devrait déjà disposer de l'autorisation de création et d'exécution (Commandes GRANT et REVOKE). La permission doit être donnée pour une base donnée et éventuellement pour une table donnée, sinon toutes (.*).

    Un événement de destruction de sessions trop anciennes

    CREATE EVENT IF NOT EXISTS delete_sessions
    ON SCHEDULE EVERY 180 MINUTE
    DO DELETE FROM WEB_SESSIONS WHERE lastdate < (NOW() - INTERVAL 3600 SECOND);

    Cet événement se déclenchera toutes les 180 minutes pour supprimer les sessions qui ont expiré, celles-ci étant stockées dans une table appelée WEB_SESSIONS. Dans celle-ci le champ 'lastdate' est en fait au format TIMESTAMP (MySQL, et non Unix). Les 3600 secondes correspondent au temps de session défini, et donc, vous pouvez librement modifier cette valeur, puisque ici c'est vous le boss ! Notez aussi que vous pouvez utiliser la fonction TIMESTAMPDIFF() qui permet de calculer la différence entre deux TIMESTAMP et de retourner le résultat sous forme de minutes ou de secondes par exemple (voir la documentation sur les fonctions de date et heure). La requête suivante est aussi valable :

    DELETE FROM WEB_SESSIONS WHERE (TIMESTAMPDIFF(SECOND,lastdate,NOW()) > 3600);

    Maintenant, il faut activer l'événement (le programmateur doit être actif pour que l'événement s'exécute, sinon son activation n'aura aucun impact) :

    ALTER EVENT nom_evenement ENABLE;

    Si vous voulez le désactiver :

    ALTER EVENT nom_evenement DISABLE;

    Connaître son état

    Il est possible de connaître l'état d'un événement en consultant le schéma d'information de votre base de données, grâce à la requête suivante :

    SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'nom_evenement' AND EVENT_SCHEMA = 'nom_schema';

    Vous pouvez aussi consulter la table "mysql.event" qui contient toutes les informations à propos de votre événement (qui en est le créateur, etc). Exécutez par exemple la requête suivante pour afficher tous les événements créés :

    SELECT * FROM mysql.event;

    Pour l'instant, ce sera tout à propos des événements. Il est également possible de voir plus loin, par exemple créer un événement qui exécute une fonction. Pour l'instant n'hésitez pas à consulter les deux sources afin d'en apprendre un peu plus à ce sujet.


    Sources :

    Developpez.
    Documentation MySQL 5.1.

    mardi 9 novembre 2010

    [Java] La pagination simple...

    Certains d'entre vous se demandent encore comment réaliser une pagination correcte. Ce petit tutorial va vous venir en aide. Dans celui-ci, il sera rapidement expliqué comment récupérer un nombre d'enregistrements limité dans une base de données, selon des critères bien précis. Note : Le langage utilisé est : Java, avec un modèle JSP-servlets.

    Nombre d'éléments, page actuelle et compter le total de pages...

    Lorsque vous souhaitez paginer une liste de membres sur votre site web par exemple, vous allez avoir besoin de deux paramètres importants : le numéro de la page que vous voulez afficher, et le nombre d'éléments que vous souhaitez sur celle-ci. Dans l'exemple ci-dessous, nous allons récupérer des paramètres passés à la requête lors de l'appel de la servlet, soit le nombre d'éléments qu'on souhaite voir, et la page courante :

    // Votre fonction de la servlet
    int nombre_a_afficher = request.getParameter("n"); 
    int page_a_afficher = request.getParameter("p");

    Ensuite, il faut compter le nombre de pages selon le nombre d'enregistrements dans la base de données, de la manière qui suit.

    // Votre fonction de la servlet
    int NbrePages = dbFunctions.getPageCount(nombre_a_afficher);

    L'objet "dbFunctions", dans ce cas-ci, fait référence à une classe (que j'ai nommée DBFunctions") qui contient un objet "Connection", initialisé et ouvert, ainsi qu'une multitude de fonctions qui permettent d'accéder aux tables, de récupérer des utilisateurs, si on utilise par exemple une table qui contient des enregistrements de membres, et d'autres opérations que j'ai définies. Dans notre cas, peu importe la table, vous devez juste retenir la manipulation suivante pour compter le nombre de pages. Notez l'utilisation de "Math.Ceil" pour arrondir au nombre supérieur le nombre obtenu :

    // DBFunctions
    int public int getPageCount(int n) 
    {
       ResultSet rsN = stmt.executeQuery("SELECT COUNT(id) FROM user");
       if(rsN.next()) {
         int pgCount = (int)Math.ceil((double)rsN.getInt(1)/(double)n);
         rsN.close(); return pgCount;
       }
       (...)
    }

    Récupérer le nombre d'enregistrements pour la page courante. 

    Dans notre exemple, nous allons utiliser une liste d'utilisateurs.  Encore une fois nous faisons appel à une fonction qui s'appelle très finement "getUsers()" et qui prend deux paramètres, qui ont été précédemment cités : le nombre d'éléments à afficher et le numéro de la page actuelle. Rien de bien compliqué, voici le bout de code :

    // Votre fonction de la servlet
    LinkedList<Users> lst= dbFunctions.getUsers(nombre_a_afficher,page_a_afficher);

    La fonction appelée va utiliser une requête qui utilise la clause LIMIT. A celle-ci, nous devons fournir deux paramètres : un offset, qui est en fait une sorte d'indice d'un tableau, donc qui indique où l'on doit commencer à récupérer les enregistrements, et le nombre d'éléments à récupérer (on commence à avoir l'habitude de ce paramètre !). L'offset doit être calculé selon la formule (page_a_afficher-1) * nombre_a_afficher.

    // DBFunctions
    int public LinkedList<Users> getUsers(int n, int p) 
    {
       int offset = (p - 1) * n; 
       (...)
       ResultSet rsU = stmt.executeQuery("SELECT...LIMIT "+offset+","+n);
       while(rsU.next()) {
            // Ajout dans la liste
       }
        
       // Autres opérations et retourner la liste créée.
    }

    Pour l'affichage...

    Vous voilà avec un nombre limité de lignes ! Il ne reste plus qu'à les afficher. Vous devez donc définir des paramètres supplémentaires à récupérer dans la JSP :

    // Votre fonction de la servlet
    request.setAttribute("n", nombre_a_afficher);

    request.setAttribute("NbrePages", NbrePages);
    request.setAttribute("list_users", lst);

    Pour l'affichage, vous devrez donc utiliser (dans votre page JSP) :
    • "n", pour le réutiliser lors de l'affichage de la page suivante par exemple.
    • "NbrePages", pour créer une boucle et afficher le nombre de pages sous forme de lien.
    • "list_users", à parcourir pour extraire les informations et les formater.
    Je ne vous donne pas plus d'indice, vous pouvez trouver comment ça marche comme des grands. Après tout, ce tutorial était principalement destiné à vous donner les points importants pour le calcul de l'offset notamment, ou pour le calcul du nombre de pages à afficher.  Bien sûr, ces calculs sont valables pour n'importe quelle pagination dans n'importe quel langage : PHP, PL/SQL,...