php-experts.org - développement php et internet » objet https://www.php-experts.org Ressources sur le développement internet, PHP/MySQL, Ajax, marketing online, référencement... Sat, 19 Jun 2010 14:23:03 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 Moteur de template : Smarty https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80 https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80#comments Sun, 08 Mar 2009 22:38:15 +0000 Didier https://www.php-experts.org/?p=80 Smarty est un moteur de template. Basiquement, l’utilité d’un moteur de templates est de séparer le code métier de l’affichage que génèrera votre application web. Smarty se présente sous la forme d’une classe qui gère un langage de balises permettant d’afficher dynamiquement du code. Ces templates sont compilés et mis en cache (les versions compilées étant en php, elles profitent d’éventuels accélérateurs comme APC). Le moteur de template Smarty est si riche de fonctionnalités que je lui consacrerai une série d’articles. Pour commencer, nous verrons l’utilisation basique de Smarty, l’utilisation du tag {literal} ainsi que la gestion des dates.

Principe de fonctionnement

Admettons que sur votre nouveau site social-2.0-multimedia (etc), vous avez une fiche utilisateur. Chaque fiche comportera, peu ou prou, les mêmes informations, notamment le login de l’utilisateur. Voici comment procéder. Créez d’abord un fichier user.tpl (Note sur les fichiers .tpl : l’extension est libre, mais l’usage du .tpl est une convention; la plupart des IDE possédent des plug-ins pour permettre l’analyse et la coloration syntaxique de ce language de balises. Pour les puristes -je ne parle pas pour moi-, on peut justifier l’emploi du “tpl” au lieu d’un “html” plus classique par le fait que les templates contiendront certes du HTML, mais aussi des instructions destinées au moteur de template… mais bref!) . Ce fichier contiendra :

  1. Login : <strong>{$login}</strong>

Le fichier php qui l’utilisera contiendra, lui :

  1. $smarty = new Smarty();
  2. $smarty->assign(‘login’,$user_login);
  3. $smarty->display(‘user.tpl’);

On instancie un objet de la classe Smarty (ligne 1) on déclare une variable de template appelée ‘login’ qui contiendra la valeur de la variable php $user_login (ligne 2). On demande ensuite à Smarty d’ “exécuter” et d’afficher le fichier user.tpl (ligne 3).
Vous l’aurez compris, le login de l’utilisateur apparaîtra en lieu et place du {$login} dans le fichier template. Les {} indiquent à Smarty que ce code doit être exécuté, et non directement reproduit en sortie (ce qui est le cas du HTML). Ces signes encadreront toutes les balises Smarty. Vous remarquerez que la variable se déclare en php sans le signe $, mais qu’il faut utiliser celui-ci lorsqu’on veut accéder à la valeur de la variable dans le fichier de template.

Gestion des tableaux sous Smarty

Si, en PHP, on assigne une tableau à une variable Smarty, on peut y accéder grâce au point, avec la syntaxe $tableau.index.

Fonctions prédéfinies

(lien vers la doc officielle)

Le tag {literal}

S’il vous arrive de devoir utiliser des accolades {} dans le code–source de votre template (par exemple pour y intégrer des fonctions JavaScript), il faut les entourer du tag Smarty {literal}{/literal}, afin d’indiquer au moteur de template de ne pas parser le contenu, ce qui provoquerait une erreur.

Gestion des dates avec Smarty

Smarty gère l’affichage des dates très efficacement grâce à un modificateur de variable (un filtre) nommé date_format. La syntaxe de date_format sous Smarty est la suivante :

  1. Date : {$date_user|date_format:"%A %d %B %Y à %Hh%M"}

Qui affiche :

  1. Date : Sunday 15 February 2009 à 13h59

Pour passer la date que Smarty va afficher en français, il suffit d’utiliser setlocale() en php, comme ceci:

  1. setlocale(LC_ALL, ‘fr_FR’)

(n’hésitez pas à me dire si vous voulez un post plus complet sur l’installation – au moins sous Debian – et l’utilisation des locales en php). La date affichée devient alors :

  1. Date : Dimanche 15 février 2009 à 13h59

Voici les options que vous pouvez passer à la fonction date_format de smarty :

  • %a – Abréviation du jour de la semaine, selon les paramètres locaux.
  • %A – Nom du jour de la semaine, selon les paramètres locaux.
  • %b – Abréviation du nom du jour, selon les paramètres locaux.
  • %B – Nom complet du mois, selon les paramètres locaux.%c – Préférences d’affichage selon les paramètres locaux.
  • %C – Siècle, (L’année divisée par 100 et tronquée comme un entier, de 00 à 99)
  • %d – Jour du mois, en tant que nombre décimal (de 01 à 31)
  • %D – même chose que %m/%d/%y
  • %e – Jour du mois en tant que nombre décimal. Un chiffre unique est précédé par un espace (de 1 à 31)
  • %g – Position de la semaine dans le siècle [00,99]
  • %G – Position de la semaine, incluant le siècle [0000,9999]
  • %h – identique à %b
  • %H – L’heure en tant que décimale, en utilisant une horloge sur 24 (de 00 à 23)
  • %I – L’heure en tant que décimale en utilisant une horloge sur 12 (de 01 to 12)
  • %j – jour de l’année (de 001 à 366)
  • %k – Heure (horloge sur 24). Les numéros à un chiffre sont précédés d’un espace. (de 0 à 23)
  • %l – Heure (horloge sur 12). Les numéros à un chiffre sont précédés d’un espace. (de 1 à 12)
  • %m – Mois en tant que nombre décimal (de 01 à 12)
  • %M – Minute en tant que nombre décimal
  • %n – Retour chariot (nouvelle ligne).
  • %p – soit am soit pm selon l’heure donnée, ou alors leurs correspondances locales.
  • %r – heure en notation a.m. et p.m.
  • %R – Heure au format 24 heures
  • %S – Secondes en tant que nombre décimal.
  • %t – Caractère tabulation.
  • %T – Heure courante, équivalent à %H:%M:%S
  • %u – Jour de la semaine en tant que nombre décimal [1,7], ou 1 représente le lundi.
  • %U – Le numéro de la semaine en nombre décimal, utilisant le premier dimanche en tant que premier jour de la première semaine.
  • %V – Le numéro de la semaine de l’année courante selon la norme ISO 8601:1988, de 01 à 53, ou la semaine 1 est la première semaine qui dispose au minimum de 4 jours dans l’année courante et ou Lundi est le premier jour de cette semaine.
  • %w – Jour de la semaine en tant que nombre décimal, dimanche étant 0
  • %W – Le numéro de la semaine de l’année courante en tant que nombre décimal, ou Lundi est le premier jour de la première semaine.
  • %x – Représentation préférée de la date selon les paramètres locaux.
  • %X – Représentation préférée de l’heure selon les paramètres locaux, sans la date.
  • %y – L’année en tant que nombre décimal, sans le siècle. (de 00 à 99)
  • %Y – L’année en tant que nombre décimal, avec le siècle.
  • %Z – Zone horraire, nom ou abréviation
  • %% – Un caractère litéral `%’

Lectures intéressantes sur Smarty:

Pour aider à la rédaction de ma série d’articles, n’hésitez pas à laisser un commentaire sur un sujet que vous voudriez voir abordé, ou à me signaler des docs intéressantes sur Smarty, je me ferais un plaisir de les rajouter dans les lectures intéressantes :)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/moteur-de-template-smarty-80/feed 5
Parser des XML volumineux avec XMLReader https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42 https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42#comments Fri, 28 Nov 2008 17:25:20 +0000 Didier https://www.php-experts.org/?p=42 Avec des classes comme DomDocument ou SimpleXML, le parsing de fichiers XML s’est considérablement simplifié en PHP 5. Mais quand on doit parser des fichiers très volumineux (comme j’ai eu à le faire récemment pour le catalogue produits de mon comparateur d’électroménager), on se retrouve très rapidement avec des scripts très gourmands en mémoire. En effet, ces classes lisent et analysent la totalité du fichier XML avant de pouvoir agir dessus. Ce n’est pas le cas de XMLReader, qui elle, fonctionne en mode flux: le fichier est alors lu au fur et à mesure des besoins. Il en résulte des scripts plus rapides et très peu consommateurs de RAM.

Utiliser XMLReader et SimpleXML de concert

Voici comment on procède:

  1. $xml = new XMLReader();
  2. $xml->open(‘gros_fichier.xml’);
  3. while($xml->read()){
  4.     if ($xml->nodeType == XMLREADER::ELEMENT &amp;&amp; $xml->localName == "product") {
  5.         $product = $xml->expand();
  6.         $product = new SimpleXMLElement(‘<product>’.$xml->readInnerXML().‘</product>’);
  7.         $prod[‘name’] = utf8_decode($product->name);
  8.     }
  9. }

Ligne 1, on instancie classiquement un objet XMLReader. Le constructeur ne prend pas de paramètres. Ligne 2, on assigne le fichier que l’on souhaite parser.
C’est ensuite que les joyeusetés commencent : $xml->read() permet de passer au node suivant. Tant que XMLReader trouvera des nodes, on continuera à lire le fichier séquentiellement. L’intérieur de la boucle contiendra le traitement que je souhaite effectuer sur chaque node. Ici, si le nodeType est “ELEMENT” si le localName (le libellé du tag) est “product”, nous sommes en présence de l’un des produits que je souhaite traiter.
Dans ce cas, $xml->expand() permet de copier le node courant afin de le manipuler plus aisément. L’astuce ligne 6 (j’imagine bien qu’il doit y avoir un moyen de faire ça beaucoup plus proprement) consiste à recréer le node à partir de son localName et de la chaîne de caractères au format XML qu’il contient, récupérée grâce à $xml->readInnerXML(). Etant habitué à l’utilisation courante de SimpleXML, et pour des raisons de confort personnel, je passe la chaîne de caractères obtenue en paramètre au constructeur de SimpleXMLElement afin de récupérer un élement XML classique, que j’utilise ensuite simplement en accédant aux données qu’il contient.

Vérifier le bon déroulement des opérations

  1. $i++;
  2. if (($i % 500) == 0) {
  3.         echo "$i – Ok\r\n";
  4.         flush();
  5. }

Pour les imports de gros fichiers (1.2 giga-octets dans mon cas), mieux vaut savoir exactement ce qu’il se passe. J’ai donc déclaré avant mon while une variable $i=0, que j’incrémente à la fin de ma boucle, après avoir traité un produit. Ligne 2, je vérifie que $i (le nombre de produits traités) est un multiple de 500. Si oui, j’affiche le nombre courant et le flush() permet d’envoyer immédiatement le contenu du buffer à la sortie du script. Ici, le but était de faire tourner le script en ligne de commandes (CLI), mais cela aurait aussi bien marché avec un navigateur. (Il aurait fallu remplacer les \r\n par un <br /> classique.

Si cet article vous a intéressé, j’apprécierais un peu de promotion : ;)


]]>
https://www.php-experts.org/developpement-web/php-developpement-web/parser-des-xml-volumineux-avec-xmlreader-42/feed 4
Coder une classe d’abstraction pour manipuler des objets en PHP5 https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18 https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18#comments Fri, 25 Jul 2008 20:38:22 +0000 Didier https://www.php-experts.org/?p=18 Sur chaque site, dans tous les projets, on a une base de données qui contient des tables, dont chaque ligne sont des items que l’on souhaitera manipuler à un moment où à un autre. Le code PHP à écrire pour effectuer les actions nécessaires – Ajouter des items, les modifier, les supprimer, récupérer leurs attributs… – varie peu, et pourtant ce travail est souvent répété d’un projet à l’autre. Il est possible de créer une classe générique d’abstraction, qui pourra manipuler toutes sortes d’objets de manière transparente.

Note: On m’a souvent déconseillé d’utiliser l’introspection (et donc notamment la méthode __get() ) pour des problèmes de performances. Or, et malheureusement, il est de nos jours nécessaire de se rappeler que l’hébergement d’un site, même si ses coûts pourraient être réduits par de l’optimisation poussée/poussive sur le code, coûtera bien moins cher qu’un développeur qualifié, à plein temps, occupé à maintenir du code “optimisé” mais dont on pourrait aisément se passer en achetant un serveur plus puissant. J’utilise donc __get et si ça vous choque, louez un serveur dédié (et en plus je me permets un lien d’affiliation…) et arrêtez de vous demander si vous devez utiliser echo ou print… Ce n’est pas là que sera votre valeur ajoutée en tant que développeur. Il est largement plus rentable à moyen et long terme de faire du code modulaire, réutilisable, en capitalisant sur les temps de développement.

Magic function : __get

Dans la programmation orientée objets en php5, il existe des méthodes de classes qui sont dites “magiques”. La plus célèbre, __construct(), est appélée à l’instanciation de la classe.
Une autre, moins connue, est appelée lorsqu’on tente d’accéder à une propriété qui n’est pas définie. C’est __get(). Cette méthode reçoit un argument, qui est le nom de la propriété en question. C’est celle-ci que nous allons utiliser pour réaliser notre classe d’abstraction. Pour l’exemple, nous assumerons que nous avons une variable globale (oui, je sais, encore quelque chose que je ne devrais pas faire… mais j’attends toujours qu’on m’explique pourquoi) $oDb qui est un objet Database capable de renvoyer la valeur d’une ligne (getRow) d’une table de la base de données.

Comme d’habitude, on va gérer une table Employes contenant des champs ID, nom, prenom et salaire (respectivement int, varchar, varchar et int…) :

  1. class GenericObject {
  2.     public function __get($var) {
  3.         print "Magic : get $var";
  4.     }
  5. }
  6. $emp = new GenericObject;
  7. print $emp->nom;

Comme on le voit, on essaye à la ligne 7 d’accéder à la propriété “nom”, alors que celle-ci n’existe pas. La méthode __get() est alors appelée et reçoit en argument le nom de la propriété inexistante (le script affichera donc bien Magic: get nom.

Dès lors, on peut imaginer construire une classe acceptant un nom de table (string) et un identifiant (integer) en argument et pouvant, déjà, rappatrier la valeur de n’importe quel champ. Imaginons le script suivant :

  1. class GenericObject {
  2.     public function __construct($table, $id) {
  3.         global $db;
  4.         // on charge la ligne de la base de données
  5.         $this->infos = $db->getRow("select * from $table where id = ‘$id’");
  6.     }
  7.     public function __get($var) {
  8.         // on renvoie la valeur tirée de la valeur (tableau) de la propriété $this->infos
  9.         return $this->infos[$var];
  10.     }
  11. }
  12. $emp = new GenericObject(‘emp’,1);
  13. var_dump(isset($emp->nom));
  14. print $emp->nom;

Ici, la classe est instanciée dans l’objet $emp. On lui passe l’ID (en base) de notre employé fictif. Dès lors, on peut, en une ligne, récupérer la totalité des informations le concernant. Pour preuve, la ligne 14 affiche bien “Dupont”. A noter, la ligne 13 qui renvoie bool(false) : $nom c’est vraiment pas défini avant le get.

Magic function : __set()

Bien sur, parralèlement à __get, on peut utiliser la méthode __set() pour changer la valeur d’une propriété qui n’est pas définie. Cette méthode accepte, cette fois, deux paramètres: le nom de la propriété en question et la valeur que l’on souhaite lui affecter. L’intérêt dans ce cas (pour différer du comportement “normal” de PHP, est, par exemple, de récupérer la liste des champs de la base dans une propriété, et de vérifier à chaque __set que la variable qu’on tente de déclarer aura bien une correspondance dans la table de la base de données.

Magic function : __destruct()

Quitte à utiliser des fonctions “magiques”, autant le faire jusqu’au bout. On peut, grâce à la méthode __destruct(), effectuer une action lorsque l’objet sera désinstancié. Cela peut se passer si on le unset, ou lorsque le script se terminera. Par exemple, pourquoi ne pas enregistrer les changements de notre objet dans la base de données ? Dans notre exemple, il suffit de faire une boucle foreach sur le tableau $this->infos et de formater une requête SQL UPDATE.

Bon, certes, j’ai pris pas mal de raccourcis, donc le code n’est pas vraiment exploitable “tel quel”, mais avouez que la classe est efficace dans le sens où elle peut gérer toutes sortes d’objets. Il faudrait notamment ajouter, avec __set, le système qui vérifie que le champ existera dans la table (en récupérant son type pour faire des contrôles avant d’insérer). Dans le __destruct, il faut faire en sorte de ne sauver que les champs ayant été modifiés. Et bien sur, éviter l’édition de l’ID sur un objet que l’on vient de charger. Tout un programme ;)
On pourrait par exemple utiliser ce système pour gérer les utilisateurs d’un site, avec gestion des droits en bit bashing.

On pourrait coder par-dessus tout ça un système d’itérateurs pour les gérer en lots. (et effectuer simplement des tâches comme “Afficher tous les employés”, “Augmenter tout le monde de 100 €”, etc).

Je tiens mon “work in progress” (WIP©) de la classe à disposition pour qui voudra, n’hésitez pas à me le demander dans les commentaires ou par mail. :)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/coder-une-classe-dabstraction-pour-manipuler-des-objets-en-php5-18/feed 8