Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support...

39
Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog) Date de publication : 03/04/2007 Dernière mise à jour : 13/04/2007 Depuis Mars 2006 est apparu le Framework maison de chez Zend, pour PHP5. Pour rappel, Zend est une société qui commercialise tout un tas d'outils pour les entreprises, autour de PHP. Zend Framework est un d'entre eux. Distribué sous "New BSD Licence", il est gratuit, libre, developpé par Zend et par une grande communauté de développeurs interessés, et il propose génération de documents PDF, connecteurs vers des services, connecteurs vers des bases de données et support de MVC... On peut utiliser le Framework en tant que cadre de developpement directif, ou l'utiliser dans le cadre d'un simple support blibliothéquaire, à la manière de PEAR. Le projet Zend Framework est encore en cours de développement, il est en phase finale et ses contributeurs estiment une RC 1.0 pour mi Mai 2007.

Transcript of Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support...

Page 1: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du ZendFramework - Premiers pas

par Julien Pauli (Tutoriels, conférences PHP) (Blog)

Date de publication : 03/04/2007

Dernière mise à jour : 13/04/2007

Depuis Mars 2006 est apparu le Framework maison de chez Zend,pour PHP5. Pour rappel, Zend est une société qui commercialise tout untas d'outils pour les entreprises, autour de PHP. Zend Framework est und'entre eux. Distribué sous "New BSD Licence", il est gratuit, libre, developpépar Zend et par une grande communauté de développeurs interessés, et ilpropose génération de documents PDF, connecteurs vers des services,connecteurs vers des bases de données et support de MVC...

On peut utiliser le Framework en tant que cadre de developpement directif,ou l'utiliser dans le cadre d'un simple support blibliothéquaire, à la manière dePEAR.

Le projet Zend Framework est encore en cours de développement, il est enphase finale et ses contributeurs estiment une RC 1.0 pour mi Mai 2007.

Page 2: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 2 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

I - PrésentationI-A - PréambuleI-B - IntroductionI-C - Pré-requisI-D - Le coeur du FrameworkI-E - Les conventions de nommage - Vocabulaire

II - #Zend_LoaderIII - #Zend_Debug #Zend_VersionIV - #Zend_RegistryV - #Zend_ConfigVI - #Zend_FilterVII - #Zend_ValidateVIII - #Zend_ViewIX - #Zend_Db

IX-A - IntroductionIX-B - Requêtes simplesIX-C - Récupération de résultatsIX-D - Insert, Update et DeleteIX-E - TransactionsIX-F - SélectionsIX-G - Mapping Objet Relationnel

IX-G-1 - GénéralitesIX-G-2 - L'exempleIX-G-3 - Définition du mappingIX-G-4 - Les résultats (Row)IX-G-5 - Les jeux de résultats (Rowset)IX-G-6 - Gestion des dépendances

X - Conclusion - AnnexesX-A - Le mot de la finX-A - Annexes : Schémas UML des packages étudiés

Page 3: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 3 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

I - Présentation

I-A - Préambule

Actuellement en version 0.9.1, le Zend Framework (ZF) fait beaucoup de bruit sur la toile du développement PHPen ce moment. J'ai décidé de vous y faire goûter du bout des lèvres ;-). La presse spécialisée s'est emparée del'évènement, et de nombreux architectes PHP considèrent déjà ZF comme étant amené à devenir 'le cadre dedéveloppement standard que tout le monde attendait'.

Ce Framework a bien grandi. En l'espace d'un an, il a changé de licence pour s'ouvrir au développementcommunautaire, et il accuse déjà une quarantaine de composants opérationnels. Il est vrai qu'à ses débuts, tout étaitdifférent. Beaucoup de refactorisation et de correction de bugs ont été faits. Une si belle progression n'aurait pu êtrepossible sans un modèle de développement communautaire, mais bien architecturé.

Tout le monde peut reporter un bug sur le tracker, proposer ses idées, faire partager ses expériences, tout ceciorchestré par l'équipe de gestion du projet de Zend.

Personnellement, j'ai bien aimé mes débuts sous ZF, c'est en découvrant peu à peu sa structure et son articulationque j'ai décidé de contribuer un peu, tout d'abord via ce tutoriel de présentation. Viendra ensuite un tutoriel pluscomplet (une mini appli web), avec MVC. Je bosse sous ce Framework depuis environ Octobre 2006 (0.2), et je suisde près tout ce qui le touche, notamment son développement actuel qui tend à se rapprocher d'un style Ruby OnRails, de par certaines caractéristiques. Nul doute que les programmeurs habitués à du "full object", ne seront pasdépaysés (les adeptes de Java par exemple).

Je suis contributeur, je participe donc au développement de certains composants ainsi qu'à la correction de bugset à l'amélioration de certaines fonctions, et bientôt à la traduction du manuel. Il fallait bien un membre du clubdeveloppez.com qui mette les mains dedans, et Zend a bien apprécié ;-).

L'AFUP, Association Francaise des Utilisateurs de PHP, dont je suis membre, a organisé début décembre 2006 uneréunion ayant pour thème le Framework de Zend. Zeev Suraski était présent. Je vous revoie sur cette page pour plusd'infos, et pour télécharger les slides. Il ne s'agit pas ici de dresser un comparatif avec d'autres Frameworks PHP,mais tout simplement un avant goût sous forme de mini tutoriel, qui va s'étendre profondément sur certains points,ceci dans le but de faciliter votre apprentissage, et ce quel que soit votre niveau d'expérience dans la programmationsous Framework.

I-B - Introduction

Un Framework apporte un cadre standard pour le développement d'applications à interface web.

Il agrège différentes classes, ce qui augmente la couverture fonctionnelle d'un langage tout en en simplifiant samanipulation.

Toujours en développement mais déjà téléchargé plus de 500.000 fois, avec quelques 800 fichiers déjà et une bonnequarantaine de packages fonctionnels ; le Zend Framework propose "une collection modulaire de classes PHP 5 quisimplifient les tâches courantes du développeur".

Il s'agit pour l'essentiel de fonctionnalités très utilisées comme une couche d'abstraction de bases de données (fondéeprincipalement sur PDO), le support de MVC, la génération de documents PDF, l'envoi d'e-mails, la gestion deflux de syndication Atom et RSS, la gestion de l'internationalisation...

Page 4: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 4 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Le Zend Framework intègre aussi des "connecteurs" pour les services en ligne de Yahoo!, Google, Amazon, Flickr.On peut noter aussi une classe de gestion des dates, un package complet pour l'indexation de contenu basé sur lecélèbre moteur Lucène de l'Apache Group, tout un tas d'outils facilitant l'internationalisation, les sessions, etc.

Pour s'assurer du succès de son Framework, Zend s'est appuyé sur un modèle participatif et communautaireimpliquant plus de 115 participants au nombre desquels figurent de grands acteurs comme Yahoo!, Google, IBMet General Electric. La concision du code qu'apporte un Framework de haut niveau, plus fonctionnel que technique,augmente la productivité des développeurs. Par exemple, il faut environ 15 lignes de code PHP pour afficher un fluxRSS, tandis que 5 suffisent avec le Zend Framework.

I-C - Pré-requis

Ce tutoriel suppose que vous ayez de solides connaissances du travail sous PHP dans sa version 5, et notammentdu modèle objet de celui-ci, ainsi que de la SPL (Standard Php Library), qui fournit un ensemble de classes interneà PHP.

Dans le cadre de la lecture de cet article, il est conseillé de posséder de bonnes compétences en programmationorientée objet (POO), de bonnes notions de conception UML et des Design Patterns, ainsi que quelquesconnaissances du langage SQL.

Vous retouverez les diagrammes de classe des principaux packages étudiés en annexe.

L'environnement de travail étudié dans cet article est un serveur Apache, un SGBD MySQL dans sa version 5 et PHPversion 5.2. Zend Framework requiert PHP 5.1.4 minimum, mais recommande hautement PHP 5.2.

Sans nul doute, votre point de repère reste l'API en ligne, le mécanicien ne bossant pas sans sa caisse à outils...Histoire de ne pas se perdre dans les méthodes et les objets, on garde un oeil sur le manuel.

Attention tout de même, la version originale du manuel est la version anglaise. Les autres versions sontdes traductions, effectuées par des groupes de traduction dans la development team, et peuvent donc êtredésynchronisés, le temps de la traduction. Vérifiez donc les statuts des traductions, ou préférez la doc originale,en anglais.

Commençons par télécharger la dernière version stable de ZF. À ce jour, ce tutoriel est écrit avec ZF 0.9.1.

Il est important de vérifier la version, surtout sous la branche 1.0 (comme c'est le cas àl'heure où ces lignes sont écrites).

En effet, certains changements entre les versions doivent s'accompagner de patches,notamment pour MVC qui a connu une mutation entre 0.2 et 0.6.

Des méthodes naissent ou disparaissent ; mais tout ceci est bien entendu nécessaire audéveloppement d'un Framework compétitif et sérieux.

Cependant, à partir de 0.9.0, plus aucune modification ne devrait être recensée d'ici lasortie de la version finale 1.0, ce tutoriel devrait donc en théorie rester valide pour quelquetemps encore.

I-D - Le coeur du Framework

Page 5: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 5 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Voici les composants de la branche principale du Zend Framework que nous allonsétudier ici :• #Zend_Loader

• #Zend_Debug

• #Zend_Version

• #Zend_Config

• #Zend_Db_*

• #Zend_Filter_*

• #Zend_Validate_*

• #Zend_View

Rien qu'avec ses quelques composants, nous serons déjà en mesure de faire une petiteappli web sympathique, vous remarquerez que je n'utiliserai pas ici #Zend_Controller,donc pas de MVC pour le moment, un autre tuto sera dédié à ce vaste sujet.

Il n'est pas obligatoire de réaliser un projet à 100% sous ZF. Ainsi, même sans MVC, ZFva tout de même nous simplifier la vie.

Cet article n'a pas pour vocation d'être exhaustif, certaines méthodes ne seront pasprésentées, elles sont cependant bien présentes dans l'API.

Ce tutoriel sera cependant mis à jour de temps à autre, en décrivant de plus en plus decomposants, il sera de même accompagné dans le futur d'autres tutoriaux plus orientés"pratique".

Le coeur du Framework est représenté par le dossier Library de l'archive téléchargée. La structuration interne de ZFest régie par des conventions de nommage, que voici :

I-E - Les conventions de nommage - Vocabulaire

#Zend_Db représente un composant que l'on peut aussi apeller package (en référence à Java), il estmatérialisé par le script /ZF-path/Zend/Db.php, la classe représentée étant Zend_Db.

Cette convention de nommage sera utilisée pour charger des classes plus tard. Elle est identique à certains projets,tels que PEAR. Remplacez les underscores ( _ ) dans le nom de la classe par des slashs ( / ), pour voir apparaîtrel'arborescence du fichier.

Si votre application respecte la même norme, alors vous verrez que le développement devient encore plus souple.

Comme pour PEAR, chaque underscore ( _ ) dans le nom de la classe représente donc une descente dansl'arborescence, et un lien de dépendance fonctionnelle.

Chaque composant donne naissance à une classe, portant le même nom, et chaque composant est une entité duFramework, qui peut contenir d'autres classes qui l'enrichissent et qui dépendent d'elle.

Ainsi, Zend_Db_Adapter_Abstract est une classe dont le fichier est /ZF-path/Zend/Db/Adapter/Abstract.php, contenudans le package #Zend_Db

Page 6: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 6 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

On peut donc dire que tout ce qui descend, dépend. Une dépendance est un lien UML soit direct : héritage, soitindirect : utilisation, implémentation, etc. Mais un des avantages de ZF est son couplage relativement faible. Tousles packages ne dépendant pas les uns des autres, seules quelques liaisons internes sont effectuées, lorsque c'estnécessaire. Ainsi, vous pouvez sans problème utiliser #Zend_Db, par exemple, sans avoir à dépendre d'un autrepackage.

Seules quelques dépendances entre packages sont à noter (elles sont même de temps en temps facultatives) oùc'est réellement nécessaire : #Zend_Mail va utiliser #Zend_Mime (ça se comprend), #Zend_Http_Client va utiliser#Zend_Uri. Mais ce n'est pas le gros foutoir, dans lequel l'inclusion du moindre composant, entraîne une inclusionde dizaines d'autres (et donc un temps de traitement revu à la hausse).

Il est conseillé de placer le répertoire du Framework en dehors de la racine web, sinon, d'interdire son accès, parexemple avec un fichier .htaccess.

Comme pour tout Framework, dans un souci de pratique, il faut d'abord ajouter son répertoire à l'include path dePHP. Ceci se fait soit par l'intermédiaire du fichier INI, soit via la fonction set_include_path(). Nous utiliserons endéveloppement une gestion d'erreur la plus large possible (E ALL | E_STRICT). Il est conseillé d'utiliser la méthodeset_include_path(), ainsi chaque application définit son Framework, et les applications ne le nécessitant pas, ne lechargeront pas (comme ce serait le cas via la config de l'include path par le fichier INI).

Page 7: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 7 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

II - #Zend_Loader

La classe Zend_Loader comporte déjà toute une série d'outils très pratiques. Ce ne sont que des méthodes statiques,sans dépendances externes (Elles ne necessitent pas d'autres composants, cependant d'autres composants ontbesoin d'elle). Le composant à inclure est #Zend_Loader, il est donc représenté par le fichier /Zend/Loader.php.Quasiment tous les composants du Framework dépendent de #Zend_Loader, voyez pourquoi :

<?php// ZFHome est le chemin où le contenu de 'library' est placé.error_reporting(E_ALL|E_STRICT); set_include_path('.' . PATH_SEPARATOR . './ZFHome' . PATH_SEPARATOR . get_include_path()); require "Zend/Loader.php"; ?>

ZF utilise sa propre http://fr3.php.net/manual/fr/language.exceptions.php qui n'est autre qu'un alias de la classeException native de PHP.

class Zend_Exception extends Exception{}

Toute exception qui sera levée dans vos applications enverra, au plus bas, une Zend_Exception. Notez queZend_Exception n'étant pas déclarée en 'final', il est possible de l'étendre, ce qu'il est hautement conseillé de faire.

Je ne vais pas faire un tutoriel sur les Exceptions, mais juste rappeler que chaque package, ou chaque entitéélémentaire, doit renvoyer sa propre exception, nommée. Cela facilite grandement le débuguage, notament dans lecadre de projets travaillés en équipe. Si tout le monde envoie des 'Exception', toutes simples, on ne peut absolumentpas savoir d'où viennent les erreurs.

Nous allons poursuivre avec les méthodes 'helpers' du composant #Zend_Loader. Utiliser des helpers, alors quePHP seul peut représenter les mêmes fonctions, est utile si vous chargez des fichiers dont le nom ou le chemind'accès sont variables (des vérifications sont faites sur le nom). Sinon, un require() fait l'affaire.

loadFile() charge un fichier PHP.

<?php// manière classiquerequire_once('example1.php');

// manière ZFrequire('Zend/Loader.php');try { Zend_Loader::loadFile('example2.php');} catch (Zend_Exception $e) { echo $e->getMessage();}?>

La grande différence avec PHP, comme pour tous les outils du Framework Zend, est qu'ils s'appuient sur une gestiond'Exception interne, que vous pouvez contrôler comme vous le souhaitez. Si un fichier n'est pas trouvé, vous pouvezcréer votre gestionnaire d'Exceptions, et l'implémenter. Attention cependant si un fichier inclus comporte une erreurde syntaxe, elle sera dirigée vers le système d'erreur interne à PHP, et ne déclenchera pas d'exception. Vous pouveztoujours utiliser la fonction set_error_handler() à bon escient pour loguer les erreurs, par exemple.

Plus répandu déjà, loadClass() charge une classe en utilisant loadfile(), et comme il est courant d'ajouter à l'includepath, un chemin vers ses classes métiers, on pourra profiter d'un autoload amélioré :

<?php

Page 8: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 8 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

set_include_path('.' . PATH_SEPARATOR . './ZFHome' . PATH_SEPARATOR . . './app/class' . PATH_SEPARATOR . get_include_path()); require('Zend/Loader.php');function __autoload($class){ spl_autoload_register(array('Zend_Loader', 'autoload'));}?>

spl_autoload_register() enregistre notre fonction d'autoload sur la pile des autoloaders. Après que le fichier ait ététrouvé, loadClass() s'assure que la classe a été chargée suivant les conventions de nommage.

De plus, si on respecte les conventions citées auparavant pour nos propres classes, on peut utiliser la classeimmédiatement ; par exemple :

Créer un objet instance de la classe Voiture chargée depuis le script ./app/class/Vehicule/Voiture.php<?php// ...$foo = new Vehicule_Voiture() ; ?>

Et tout ceci, sans la moindre inclusion manuelle.

Il en va de même pour toute classe PEAR (PEAR respectant la même convention de nommage).

Les exemples suivants supposent l'autoload activé, afin d'éviter de les surcharger derequire() et autres 'loads()'.

Important : Les exemples suivants supposent l'autoload activé, afin d'éviter de les surcharger de require() et autres'loads()'.

L'utilisation de l'autoload, ou pas, dans un projet de moyenne à grand envergure, est assujettie à des débats.Autoload est connue pour être gourmande en temps de traitement (ceux qui font du profiling peuvent le constater).

De même, elle fait disparaître tout lien de dépendance, on n'a plus besoin d'inclure ses classes dans ses autresclasses et, si on bosse comme un cochon, on va vite s'y perdre. Je recommande autant que possible d'utilisercorrectement les conventions de nommage que nous avons vues, de manière à pouvoir retrouver ses fichiersfacilement.

Sinon, Loadclass() et Loadfile() acceptent un second paramètre $dirs, chaîne ou tableau représentant un (des)dossier(s) dans lequel (lesquels) rechercher le fichier.

isReadable() est une copie de son homologue PHP, à la seule différence qu'isReadable() parcourt l'include path.

Page 9: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 9 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

III - #Zend_Debug #Zend_Version

#Zend_Debug ne contient actuellement qu'une méthode statique de débbuguage.

dump(): est une amélioration très appréciée de var_dump() qui rajoute des <pre> de formatage pour un confortde lisibilité amélioré. C'est le remplaçant des echo() et autres print_r() var_dump(), extrêmement pratiques en

débuguage. Attention toutefois, si vous utilisez l'extension XDebug, celle-ci vous gênera sur les résultatsretournés par dump(), je pense que c'est en raison de la manipulation du buffer de sortie par Zend_Debug::dump()

#Zend_Version ne contient aussi qu'une méthode statique de comparaison de version.

compare(): compare la version passée en paramètre, avec la version actuelle de Zend_Framework. Elle utiliseversion_compare() de PHP, elle renvoie cependant uniquement un String.

Page 10: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 10 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IV - #Zend_Registry

Ce composant est issu du design pattern Registre. Le Registre est un pattern qui fournit un mécanisme destockage de données, destiné à favoriser le mélange global des objets dans une application.

Le registre de ZF est un Registre Singleton. Le Framework l'utilise lui-même en interne pour son mélange de données.set() et get() en sont les méthodes principales :

<?php$config = new Zend_Config_Ini('./config.ini', 'database'); // $config représente un objet de configuration

Zend_Registry::set('conf', $config);?>

Dans cet exemple, un objet de configuration (que nous verrons juste après) est crée et enregistré dans le registresous le nom de 'conf', qui va nous servir à récupérer l'instance :

<?phpclass Voiture {public $marque;public $couleur;

public function __construct(){ $conf = Zend_Registry::get('conf'); $this->marque = $conf->voiture->marque; $this->couleur = $conf->voiture->couleur; }}?>

Dans cette classe, nous extrayons l'objet config du registre pour définir la couleur et la marque des voitures instancesde Voiture. Ceci est très avantageux, et nous permet d'écrire un code portable, écrit une fois, stocké dans le registre,et utilisé partout où il le faut.

Précisons à nouveau : le registre de ZF renvoie toujours la même instance d'un objet (Singleton). Ainsi, n'importeoù dans un script :

<?php$conf = Zend_Registry::get('conf');$conf->voiture->marque = 'une marque'?>

Ceci applique la modification sur $conf, l'unique instance dans le registre, et modifie donc l'objet partagé 'conf'.Souvenez-vous, le registre est là dans le seul but de partager une info unique, entre tous les scripts.

isRegistered() : Afin d'éviter l'écrasement accidentel d'objets, vous pouvez tester l'appartenance d'un objet auregistre via cette méthode en lui passant directement l'objet en paramètre ; elle retourne TRUE s'il, FALSE sinon.

setInstance() est une méthode qui permet carrément d'implémenter son propre pattern Registre. Si votre applicationdoit se brancher sur une structure comportant déjà un registre, cette méthode permettra de l'utiliser. Si vous n'avezpas de registre, alors le ZendRegistre est utilisé par défaut.

Page 11: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 11 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

V - #Zend_Config

Tout le monde a un jour écrit quelque chose comme cela :

<?php$db_host = 'localhost';$db_name = 'name_of_database';$db_user = 'myname';$db_pass = 'secret';?>

Sur de gros projets, cela ne tient plus la route et il devient difficile d'accéder aux variables de configuration.

<?php$GLOBALS['config']['db_name'] = 'localhost';?>

Pourquoi pas. Mais dans un souci de portabilité, et afin de pouvoir établir plusieurs configs pour plusieurs utilisateurs,par exemple, pourquoi ne pas extraire tout simplement la config dans un fichier de config à part : config.ini ouconfig.xml ?

Nul besoin alors d'écrire du code pour parser ces fichiers. Zend_Config_Ini permet de charger un fichier deconfiguration ini en utilisant la fonction PHP parse_ini_file(). Reportez-vous à ce manuel pour écrire vos fichiers ini,il existe quelques petites subtilités.

Config.ini :[database]database.username = foodatabase.password = bardatabase.hostname = localhost

[voiture]voiture.marque = ma-marque-de-voiturevoiture.couleur = vert

Avec ce fichier de configuration, le script suivant va encapsuler nos données dans un objet et nous les montrer :

<?php$config = new Zend_Config_Ini('./config.ini');

echo $config->database->username . '-' . $config-> database->password . '-' . $config->database->port;?>

Le fichier de config ini est donc transformé en class->propriétés et, mieux encore, le parseur gère aussi l'héritage.Par exemple, un fichier de config unique, mais dont les paramètres sont écrasés, avec une gestion d'utilisateurs :

Config.ini :[database]database.name = databasedatabase.hostname = localhost

[developers : database]database.name = dev-databasedatabase.username = developersdatabase.password = dev-password

Page 12: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 12 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

[teamleaders : database]database.username = team-leadersdatabase.password = tl-password

<?php$config = new Zend_Config_Ini('./config.ini', 'developers');

echo $config->database->username . '-' . $config->database->name ; // developers - dev-database?>

<?php$config = new Zend_Config_Ini('./config.ini', 'teamleaders');

echo $config->database->username . '-' . $config->database->name ; // team-leaders - database?>

Ici, nous passons au constructeur le nom de la section à charger comme 2ème paramètre. "Developers : database"signifie que developers hérite des propriétés de database. Il peut en redéfinir d'autres ou écraser les propriétésparentes (héritage OO avec visibilité protected). En revanche, l'objet $config reste en lecture seule, toute tentatived'affectation renvoie une Zend_Config_Exception. Il n'est donc pas possible de modifier le fichier ini, depuis le

framework par défaut. Ce comportement peut être changé via une 3ème option constructeur :

<?php$config = new Zend_Config_Ini('./config.ini', NULL, TRUE);

$config->database->username = 'myUserName'; // autorisé?>

Notez qu'il n'est toutefois pas possible de sauvegarder l'objet vers le fichier Ini. Le fichier Ini est en lecture seuleforcée, lui.

Page 13: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 13 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VI - #Zend_Filter

La sécurité est un point que tout bon développeur doit avoir en permanence à l'esprit. Je ne vais pas faire un coursde sécurité ici, mais juste vous parler du composant #Zend_Filter contenant une classe par filtre : Zend_Filter_Input,Zend_Filter_Alpha...

Zend_Filter est un conteneur de filtres qui va permettre de créer des chaînes de filtres sur mesure, qui vont noussimplifier la vie face à des situations courantes en développement web.

Je ne vais montrer que quelques exemples, mais l'API en ligne regorge d'autres méthodes sympathiques. Onnotera Zend_Filter_* { Alnum, Alpha, BaseName, Int, Dir (...) }

Nous pouvons créer des instances de chacun de ces filtres et les utiliser individuellement, mais nous pouvons aussiles chaîner dans Zend_Filter :

<?php$alpha = new Zend_Filter_Alpha();echo $alpha->filter('Foo45Bar'); // 'FooBar'

$balise = '<h1>balise</h1>';$pasDeTag = new Zend_Filter_noTags();echo $pasDeTag->filter($balise); // 'balise'?>

<?php// chainage de filtres :

$chaine = new Zend_Filter();$chaine->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_noTags()); $message = $chaine->filter($_POST['message']);?>

En plus des filtres déjà incorporés dans le Framework, vous pouvez écrire vos propres filtres en implémentantl'interface Zend_Filter_Interface. La seule méthode à définir est filter()

Page 14: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 14 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VII - #Zend_Validate

#Zend_Validate est très semblable à #Zend_Filter. Ici on va pouvoir créer des chaînes de validateurs. Un validateurest une fonction qui vérifie si une donnée respecte un schéma. Un filtre (vu précédemment), modifie la donnée selonun schéma.

On aura bien compris qu'un validateur va servir à valider les données reçues par l'utilisateur, un autre composant dela catégorie sécurité des applications web, dont on va pouvoir user et abuser.

Exactement selon le même principe de chaînage des filtres, nous avons toute une série de validateurs individuelsà disposition, que nous ajouterons à un validateur personnalisé. Lors de l'appel à isValid(), tous les validateurs vontpasser en revue la donnée passée en paramètre, puis chacun écrira dans un journal si oui ou non, son test est passé.On pourra récupérer le journal après.

<?php$chaine = new Zend_Validate();$chaine->addValidator(new Zend_Validate_Int()) ->addValidator(new Zend_Validate_GreaterThan(8));

if ($chain->isValid($data)) { // la donnée est validée} else { // itération sur les messages d'erreur foreach ($chaine->getMessages() as $message) { echo "$message\n"; }}?>

Dans notre exemple ci dessus, nous créons un filtre qui vérifie si $data est un entier - supérieur à 8.

Il est de même possible d'écrire ses propres validateurs, en implémentant Zend_Validate_Interface, et enrédéfinissant les méthodes isValid() et getMessages()

Nous allons tout de même dire un petit mot du gros validateur que représente Zend_Validate_EmailAddress

Zend_Validate_EmailAddress utilise Zend_Validate_Hostname pour au final permettre de vérifier si l'adresse emailest bien formée et si la partie pseudonyme respecte la RFC2822. Concernant la partie domaine, il est vérifié si ellerespecte la syntaxe d'un nom DNS du type nomdhote.org.

Il est possible de régler le filtre pour prendre en compte les adresses IP (et donc vérifier leur syntaxe), ou alors lesnoms de domaines locaux.

Une fonction pour vérifier si le domaine accepte les Emails est prévue. Elle vérifie dans l'enregistrement du DNSla présence d'un champ MX signifiant que le domaine est apte à recevoir des emails. Elle est dans la doc mais nesemble pas être implémentée, visiblement à cause de problèmes d'encodage de fichier selon la plateforme.

Page 15: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 15 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

VIII - #Zend_View

#Zend_View constitue la partie vue du MVC. Il n'est absolument pas obligatoire de fonctionner sous MVC pourl'utiliser ;)

En fait, #Zend_View participe à la séparation du code de traitement et de la mise en forme des résultats. Il permetde créer une sortie vers un ou plusieurs fichiers template, un fichier de vue. Cela fait partie intégrante de MVC maisaussi de toute appli bien fondée ^^.

#Zend_View n'est donc pas un moteur de template à proprement parler, car il ne fusionne pas 2 syntaxesdistinctes. Il prépare des données qu'il va envoyer à un ou plusieurs fichiers de vue. Cette vue va s'occuper desdonnées reçues et les présenter. Ici peut alors intervenir un moteur de template, ou PHP lui-même, les choix sonttrès larges.

En pratique, voici un script simple de traitement qui rend une vue :

<?php// configuration #$view = new Zend_View();$view->setScriptPath('./');

$country = "france";$sqlResult = $db->fetchPairs('SELECT id, name FROM members WHERE country = :country',array('country'=>$country));$view->result = $sqlResult;echo $view->render('myview.tpl.php');?>

Nous créons d'abord une instance de Zend_View, puis nous lui spécifions où se trouvent les vues que nous voulonsutiliser. Ici, elles se trouvent dans le même dossier que le script courant mais, généralement, elles sont à part.

setScriptPath() indique à notre instance de vue, où chercher les fichiers vue qu'on va lui faire charger. Cela se faitune fois pour toutes et il est possible de spécifier le chemin via une autre méthode :

addScriptPath() ajoute un dossier dans la liste des dossiers de vue. Notre instance va chercher dans le dossierspécifié par addScriptPath() d'abord puis, si elle ne trouve pas les vues, elle cherchera alors dans le dossier spécifiépar setScriptPath(). C'est intéressant si l'on veut créer plusieurs looks sur notre site et spécifier un des looks viacette méthode.

getScriptPaths() renvoie la liste des dossiers de vues sous la forme d'un tableau.

Pour assigner une variable 'myVar' par exemple, on utilise simplement $view->myVar = 'my data'. Une méthodeassign($myVar,'my data') existe aussi. On ne peut passer à assign() que 2 types : des tableaux de résultats (commec'est le cas dans notre exemple) ou des chaînes de caractères ; du moment que, dans la vue, on les utilise commeil faut.

clearVars() détruit toutes les variables préalablement passées à la vue.

render() enfin, retourne le résultat de la vue, que l'on doit afficher (echo) ou bien capturer dans l'OB.

Du côté du fichier vue myview.tpl.php, maintenant, nous pouvons le présenter comme ceci :

<?php if ($this->result): ?>

Page 16: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 16 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

<!-- Tableau de rendu des membres --><table><?php foreach($this->result as $memberId=>$memberName): ?> <tr> <td><?php echo $memberId?></td> <td><?php echo $this->escape(memberName)?></td> </tr><?php endforeach; ?></table>

<!-- Pas de membres à lister --><?php else : ?>

<p>Pas de résultats</p>

<?php endif; ?>

Ici, j'ai simplement utilisé PHP pour décrire ma vue, mais rien n'empêche d'utiliser un moteur de template quelconque.La doc officielle offre un bon exemple. Nous remarquons que toutes les propriétés envoyées à la vue via assign(),ou en affectation directe, sont disponibles dans le contexte de la vue et sont donc utilisables via la pseudo variable$this :

<?php// script de contrôle$view->someVar = 'someVal'; // ou $view->assign($someVar,'someVal');echo $view->render('myViewFile.tpl.php');?><?php// script de vue myViewFile.tpl.phpecho $this->someVar // affiche someVal;?>

Bien entendu, étant dans la vue, nous avons à disposition une méthode d'échappement, la fonction bas niveauimplémentée par défaut est htmlspecialchars(), avec le paramètre ENT_COMPAT (pas d'échappement desguillemets simples), sur le jeu de caractères ISO-8859-1.

escape() échappe la variable passée en paramètre pour un affichage plus serein.

setEscape() spécifie une fonction d'échappement personnalisée, qui peut être n'importe quoi : une fonction PHP oumême une méthode statique de classe, voire méthode d'un objet :

$view->setEscape('myClass','myEscapeFunction');$view->setEscape($myObj,'myObjEscapeFunction');

En général, on pourra spécifier htmlentities() et, dans le cas d'un fonction telle que celle-ci, qui accepte un paramètrespécifiant l'encodage de caractères, on peut le changer :

setEncoding() spécifie une autre fonction d'encodage pour une escape htmlspecialchars(), ou htmlentities():

$view->setEscape('htmlentities');$view->setEncoding('UTF8');

Ici, l'échappement sera équivalent à htmlentities($var, ENT_COMPAT, UTF-8);

Je rappelle qu'il n'est pas possible de changer le comportement du quote_style.

Zend_View est accompagné de tout un tas d'helpers, notamment concernant la construction de formulaires HTML.

Page 17: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 17 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Je ne vais pas tous les présenter mais juste un exemple.

Script de vue d'édition d'une fiche quelconque :<form action="action.php" method="post"> Nom :<?php echo $this->formText('name', $this->escape($this->name, array('size'=>30, 'maxlength'=>30)) ?> <br />Pays :<?php echo $this->formSelect('pays', 'fr', null, $this->countries) ?> <br />Recevoir la Newsletter?<?php echo $this->formCheckbox('newsletter', 'oui', null, array('oui', 'non')) ?></form>?>

Je ne vais pas tout détailler ici, je vous renvoie à l'API. Dans le cas le plus large, la syntaxe est helperFunction($name,$value, $attribs, $options).

Ces helpers facilitent la mise en forme d'un formulaire, en particulier avec le fameux problème du<select><option></option></select>, avec une boucle dans le <option> pour sélectionner la valeur déjà présente enbase. Ça se fait très simplement ici, avec :

<php// script de contrôle :$view = new Zend_View();$view->setScriptPath('./');$view->countries = array('fr'=>'France','us' => 'United States','de' => 'Germany');defaultCountry = $db->fetchOne('SELECT country FROM test WHERE id = 1');echo $view->render('theView.tpl.php');?>

<?php // script de vue theView?><form action="action.php" method="post"> Pays :<?php echo $this->formSelect('pays', $this->defaultCountry, null, $this->countries);echo $this->formSubmit('Send','Envoyer');?>

Ici, le select est rempli d'options présentes dans le tableau countries, et defaultCountry est en statut selected.

formSubmit a donné naissance à <input type="submit" name="send" id="send" value="envoyer" />

En plus d'éventuellement utiliser un moteur de templates, nous pouvons écrire des helpers personnalisés. Voici toutde suite un exemple, imaginons :

<?php // script de vue echo "Bienvenue, $this->showCart()";?>

La méthode showCart() est une méthode personnalisée qui a pour but d'afficher clairement le nombre d'articles dansun panier. La méthode est issue d'un helper personnalisé qui pourrait ressembler à ceci :

<?phpclass Zend_View_Helper_ShowCart { public function showCart($elements) { $output = "Votre panier contient $elements articles"; return htmlspecialchars($output); }

Page 18: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 18 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

}?>

Une fois encore, on garde les conventions de codage en tête : la classe doit s'appelerZend_View_Helper_MonHelperPerso pour une méthode nommée monHelperPerso(), ceci se trouvant dans un fichierMonHelperPerso.php.

Notez la casse, elle fait partie des --conventions de nommage -- que nous avons rappelées en début de tutoriel.

Avec les helpers personnalisés, on peut "casser" son code et une logique de séparation comme celle-ci peut êtreutilisée en complément avec la méthode addHelperPath().

addHelperPath() ajoute un dossier dans la liste des dossiers des helpers. Notre instance de vue va chercher dansle dossier spécifié ici, sinon dans le dossier par défaut Zend/View/Helper/.

On peut donc ranger ses vues et ses helpers, et ainsi correctement séparer son code si on le souhaite.

Je m'arrête là mais je vais vous donner un complément de Zend_View : Le framework CNZ. Ce Frameworkest uniquement dédié à la présentation des données, notamment à la contruction en full objet d'interfaces HTML,ce qui permet de s'affranchir totalement de tout code HTML. Le Framework CNZ est basé sur ZF, et a besoin delui pour fonctionner.

J'espère pouvoir vous écrire un tutoriel à son sujet prochainement...

Page 19: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 19 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

IX - #Zend_Db

IX-A - Introduction

Ce composant est bien entendu d'une importance extrême. Il régit toute la couche d'abstraction aux bases dedonnées. C'est la partie du tutoriel la plus longue car elle détaille, dans un cas précis mais quelque peu commun(MySQL, via PDO), les différents cheminements des objets dans la jungle que représente #Zend_Db.

Ce composant traite en effet plusieurs classes et plusieurs manières d'aborder la base de données. Il y a les couchesd'accès, les aides aux requêtes, les conteneurs de résultats (Rows), les jeux de résultats (Rowsets) pour le TDG

( Table Data Gateway) et la gestion des relations entre les tables assurant une couche d'ORM (Mapping Objet

Relationnel), dans lequel on retrouve des notions empruntées au design pattern ActiveRecord

Il est donc possible d'exécuter des requêtes simples, manuelles, de bien des façons différentes, ou alors de traiterdes requêtes préparées, des transactions ; si bien qu'on a tendance à être un peu perdu au début et que des coupsd'oeil fréquents à l'API s'imposent.

Je vais donc m'efforcer de détailler le coeur du composant, le parcours des classes et les méthodes résultantes surles objets instanciés.

#Zend_Db est composé d'un Adaptateur qui permet de se connecter à un type de base. Il est possible de passer parPDO, ou non. Je conseille, lorsque c'est possible (PDO est activé dans les dernières distrib de PHP, mais les driversne sont pas forcément présents ou activés sur les serveurs) d'utiliser PDO, car il s'agit de l'interface de branchementde PHP (Php Data Object), et l'extension PDO demeure très puissante pour piloter un SGBD.

Seuls MySQLi, Oracle et DB2 sont disponibles hors PDO pour Zend_Framework, mais il existe des bibliothèques(non officielles) pour d'autres SGBD.

De notre coté, nous parlerons de MySQL via PDO, vous devez donc posséder l'extension PDO activée sur votreserveur, mais c'est la configuration courante de PHP depuis PHP5.1.

Vous devez aussi posséder le driver PDO de votre SGBD, je vous renvoie à la doc sur PDO pour plus d'info : certainsdrivers sont disponibles dans les binaires PHP depuis PHP 5.1, d'autres sont téléchargeables sur PECL. Nous netraiterons donc ici que de MySQL sous PDO ; de ce fait, il faudra activer le driver PDO_MYSQL dans php.ini. Il estconseillé aussi à ceux qui ne sont pas à l'aise avec PDO, de s'y mettre :-) Un petit tour sur la doc officielle, parexemple...

Le système complexe de #Zend_Db est basé sur de multiples héritages de méthodes. Ainsi, lorsqu'on veutse connecter via un driver, cela crée un objet qui hérite de méthodes générales, puis les méthodes propresau driver sont rajoutées ou bien redéfinissent les méthodes générales. Il en résulte donc tout un arsenal deméthodes disponibles, mais elles sont toutes basées sur PDO (dans notre cas). Les résultats, eux, le sont sur desPDOStatements. Les Exceptions envoyées sont des PDOException, mais Zend les intercepte et vous renverra desZend_Db_Adapter_Exception.

Notez qu'un profiler, Zend_Db_Profiler, est aussi de la partie et permet de faire du profiling sur sa base. Le profilingest l'action d'écouter l'état de sa base lors de requêtes et notamment de déterminer le temps d'exécution de chaquerequête, le nombre de requêtes effectuées, et ainsi d'optimiser au mieux l'interfaçage de votre application avec votrebase de données, de manière à faire en sorte que celle-ci ne devienne pas un goulot d'étranglement pour votreapplication. Nous ne détaillerons pas le profiling dans ce tutoriel.

Page 20: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 20 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

#Zend_Db est le composant principal, il est composé de :• Zend_Db

• Zend_Db_Adapter

• (Zend_Db_Profiler) non traité

• Zend_Db_Select

• Zend_Db_Expr

• Zend_Db_Table(_Abstract)

• Zend_Db_Table_Row(_Abstract)

• Zend_Db_Table_Rowset(_Abstract)

Zend_Db ne comporte qu'une méthode : une fabrique d'objets de connexion Factory(). Le design Pattern

AbstractFactory est utilisé, il est très classique et très simple.

<?php$params = array ('host' => '127.0.0.1', 'username' => 'developper', 'password' => 'mypassword', 'dbname' => 'myapp');$db = Zend_Db::factory('PDO_MYSQL', $params);?>

$db est donc votre objet de plus bas niveau d'interfaçage avec votre base. Vous verrez par la suite que nousn'utiliserons quasiment plus que des objets de plus haut niveau, mais il faut aborder les étapes dans l'ordre ;-)

$db est donc un objet qui, au passage, s'est vu doté des méthodes de Zend_Db_Adapter_Abstract, puisZend_Db_Adapter_Pdo_Abstract, pour finir en une instance de la classe Zend_Db_Adapter_Pdo_Mysql. Voyezcomme l'architecture interne de ZF a été développée de manière souple et adaptable : nous passons sous 3 couchespour obtenir un objet connexion de bas niveau. Il faut dire qu'il existe un tas de SGBD différents, et ceux-ci ont lafâcheuse tendance à différer quelque peu au niveau des méthodes des drivers.

ZF fait donc son boulot comme il faut : le développeur n'a que faire de ce qu'il se passe dessous.

Attention toutefois, lors de la création de l'objet $db, la fabrique ne teste pas si la connexion a réussi. La connexionne s'effectue que lors de l'appel d'une requête, ce qui peut être gênant. En général, on aime bien lorsqu'on crée uneconnexion, la tester. Et ne pas attendre de balancer une requête pour s'apercevoir que la base n'est pas disponible,que l'on a mal orthographié ses identifiants, que l'on a pas les bons droits... Autant tout de suite le savoir.

Nous avons pour cela sous la main une méthode héritée de Zend_Db_Adapter_Abstract, getConnection(). Elleeffectue une connexion, puis retourne l'identifiant de connexion PDO (dont nous n'avons pas besoin en réalité)

Rappel de sécurité : il est plus sécurisé de ne pas stocker ses accès aux bases de données dans des fichiers lisiblesdans la racine web. Un bon moyen consiste à les cacher dans des PHP_FLAG en utilisant un fichier .htaccess

<?php// $params = #try { $db = Zend_Db::factory('PDO_MYSQL', $params); $db->getConnection(); } catch (Zend_Db_Adapter_Exception $e){ echo $e->getMessage(); } }?>

Page 21: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 21 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Ici, nous capturons et affichons une éventuelle Exception provenant de l'adaptateur générique. Nous pourrions parexemple voir :

SQLSTATE[28000] [1045] Access denied for user 'developer'@'localhost' (using password: YES)

ou tout autre message nous signalant un problème (driver PDO introuvable, extension PDO non compilée, etc.)

Bien. Notre connecteur étant configuré, exécutons une requête simple :

IX-B - Requêtes simples

query() prépare une requête et l'exécute pour retourner un résultat, dans notre cas un PDOStatement :

<?php// ...$result = $db->query('SELECT id, name FROM members');?>

$result est un objet PDOStatement. Si vous utilisiez PDO auparavant, vous ne serez donc pas déboussolé ; si cen'est pas le cas, je vous conseille quand même un petit tour sur le manuel PHP, rubrique PDO. Ceci au regard de lasuite de ce tutoriel, concernant notamment les différents 'fetch_modes' (modes de captures de résultat) qu'offre PDO.

Dans le cadre de l'utilisation de ZF, il n'est en théorie pas nécessaire de toucher aux fetch_modes dePDO, car c'est ZF qui va s'en charger quand ca sera nécessaire. Vous pouvez toutefois spécifier un modede capture via la méthode setFetchMode() sur l'objet $db. Tous les modes PDO sont acceptés, exceptésPDO::FETCH_{BOUND-COLUMN-CLASS-INFO-FUNC-GROUP-UNIQUE-CLASSTYPE-SERIALIZE}, qui est unchoix de l'équipe de développement car le Framework risque de ne pas être compatible avec. Leur utilisation lèveradonc systématiquement une exception, il est conseillé de ne pas se soucier du tout des fetch_mode bas niveau dePDO, et d'utiliser plutôt les méthodes de capture que Zend Framework propose.

Nous pouvons appliquer la méthode FetchAll() sur le résultat :

<?php$rows = $result->fetchAll();?>

$rows est de la forme :array(2) { [0] => array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" } [1] => array(2) { ["id"] => string(1) "2" ["name"] => string(3) "Bar" }}

Ce genre de requête étant rare, voyons une requête avec un WHERE, échappé comme il se doit :

<?php$name = "foo's name"; // notez la simple quote#$sql = $db->quoteInto('SELECT * FROM members WHERE name = ?',$name);//$sql est la requête échappée, c'est un string, on peut l'echo$result = $db->query($sql);

Page 22: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 22 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

$data = $result->fetchAll();?>

La méthode quoteInto() s'applique sur l'objet de bas niveau $db et retourne la requête (non le résultat) en échappantles caractères avec la méthode propre au SGBD utilisé, nul besoin de s'en soucier.

$sql = "SELECT * FROM members WHERE name = 'foo\'s name'";

Il est de même possible, et c'est plus courant, d'envoyer une requête directement via query(), en échappant plusieursdonnées :

<?php$name = "foo's name";$country = "my country";$replaceArray = array("name"=>$name, "country"=>$country);

$result = $db->query('SELECT * FROM members WHERE name = :name AND country = :country',$replaceArray);

$data = $result->fetchAll();?>

Les données sont automatiquement échappées.

query() prépare la requête puis l'exécute. Dans le cas où l'on souhaite conserver sa requête et profiter pleinementdu mécanisme des requêtes préparées, il est possible de préparer ses requêtes manuellement avec prepare() et sesamies, adeptes de PDO ou de mysqli, c'est le même mécanisme :

Ici la requête est préparée, mais utilisée tout de suite, ceci est donc exactement équivalent à query(), qui prépareses requêtes avant des les envoyer :

<?php$sql = $db->prepare('SELECT * FROM members WHERE country = :country');$sql->bindValue('country', 'france');$sql->execute();

$result = $sql->fetchAll();?>

IX-C - Récupération de résultats

Bon, ceci est un peu long, c'est décomposé en 2/3 étapes : on prépare optionnellement la requête, on l'exécute eton capture le jeu de résultats.

Il est possible de relier ces 3 étapes en 1 seule, et ce via 6 méthodes qui vont toutes préparer, échapper puis exécuterla requête. La seule différence entre elles est la manière de récupérer le jeu de résultat.

Elles exécutent directement une requête et retournent un jeu de résultats formaté de manière concrète. Selon lasituation, on choisira une méthode plutôt que l'autre et elles sont toutes adaptées à des situations courantes dudéveloppement web.

Ces méthodes s'utilisent donc directement avec l'objet $db.

Imaginons une table qui n'aurait que 2 enregistrements. Il est important ici de noter la forme du résultat, le nombrede dimensions des tableaux de retour, les clés et les valeurs :

Page 23: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 23 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

fetchAll() renvoie tous les résultats sous forme d'un tableau à 2 dimensions :

<?php$result = $db->fetchAll('SELECT id, name FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { [0] => array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" } [1] => array(2) { ["id"] => string(1) "2" ["name"] => string(3) "Bar" }}

fetchRow() renvoie le premier résultat trouvé sous forme d'un tableau à 1 dimension :

<?php$result = $db->fetchRow('SELECT id, name FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo"}

fetchOne() renvoie la valeur du premier résultat trouvé :

<?php$result = $db->fetchOne('SELECT id, name FROM members WHERE country = :country',array('country'=>'France');?>

string(1) : 1

1 est le numéro id du premier membre dont le pays est 'France'. Il est donc inutile de sélectionner plusieurs champsavec fetchOne(), seul le premier champ du premier résultat est retourné, il en résulterait un gaspillage de ressources.

fetchCol() renvoie tous les résultats sous forme de tableau à 1 dimension ne comportant que les valeurs de lapremière colonne :

<?php$result = $db->fetchCol('SELECT id, name FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { [0] => string(1) "1" [1] => string(1) "2"}

"1" et "2" sont les id des membres dont le pays est 'France'. Ici aussi, inutile de vouloir sélectionner plusieurs colonnes,seule la première est renvoyée.

fetchAssoc() renvoie tous les résultats sous forme d'un tableau à 2 dimensions dont la clé de dimension 1 est lerésultat du premier champ :

Page 24: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 24 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

<?php$result = $db->fetchAssoc('SELECT id, name FROM members WHERE country = :country',array('country'=>'France'));?>

array(2) { [1] => array(2) { ["id"] => string(1) "1" ["name"] => string(3) "Foo" } [2] => array(2) { ["id"] => string(1) "3" ["name"] => string(3) "Bar" }}

Presque identique à fetchAll(), fetchAssoc() crée un tableau associatif. Changeons un peu la requête :

<?php$result = $db->fetchAssoc('SELECT name, id, country FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { ["Foo"] => array(3) { ["name"] => string(3) "Foo" ["id"] => string(1) "1" ["country"] => string(6) "france" } ["Bar"] => array(3) { ["name"] => string(3) "Bar" ["id"] => string(1) "2" ["country"] => string(6) "france" }}

Enfin, fetchPairs() renvoie tous les résultats sous forme d'un tableau à 1 dimension dont la clé est la donnée de lapremière colonne et la valeur est la donnée de la 2ème colonne :

<?php$result = $db->fetchAssoc('SELECT id, name FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { [1] => string(3) "Foo" [2] => string(3) "Bar"}

Il est inutile de vouloir sélectionner plus de 2 colonnes. La première colonne donnant la clé du tableau dans le résultat,il faut que ca soit une clé primaire de table, sinon le tableau va être écrasé par les données suivantes satisfaisantla requête :

<?php$result = $db->fetchAssoc('SELECT country, name FROM members WHERE country = :country',array('country'=>'France');?>

array(2) { ["France"] => string(3) "Bar" // écrasement du résultat pour name='Foo'}

Page 25: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 25 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Ces 6 méthodes s'adaptent donc à des situations du web et vous permettent de choisir la manière dont le résultatdoit vous être présenté.

Si aucun résultat ne correspond à la requête, le retour est une identité à FALSE, c'est-à-dire qu'en castant le retouren bool, on obtient FALSE. Ainsi, si une chaîne doit être retournée, le booléen FALSE est renvoyé à sa place, mais siun tableau multidimensionnel doit être retourné, un tableau vide à une dimension est retourné (ce qui est équivalenten identité à FALSE).

IX-D - Insert, Update et Delete

Nous allons désormais tenter l'insertion, la mise à jour ou l'effacement de données. Nous allons commencer à écrirede moins en moins de syntaxe SQL et, pour rester clair, les noms des variables sont explicites. De cette manière, jen'écris pas la requête SQL réelle mais elle va se deviner très facilement :

insert() insère des données dans une table, elle prend 2 paramètres :

<?php$rows = array ( 'name' => 'David', 'country' => 'England',);

$table = 'members';

$affectedRows = $db->insert($table, $rows);?>

Les données sont échappées automatiquement. La valeur de retour est le nombre de lignes affectées.

update() met à jour des données dans une table, elle prend 3 paramètres :

<?php$set = array ( 'country' => 'france',);

$table = 'member';

$where = $db->quoteInto('name = ?', 'David');

$affectedRows = $db->update($table, $set, $where);?>

Les données du SET sont échappées automatiquement, mais c'est à vous d'échapper le WHERE si c'est nécessaire.La valeur de retour est le nombre de lignes affectées.

Enfin, delete() supprime des enregistrements dans une table, elle prend 2 paramètres :

<?php$table = 'members';

$where = $db->quoteInto('name = ?', 'Foo');

$deletedRows = $db->delete($table, $where);?>

Page 26: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 26 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Vous devez échapper le WHERE si nécessaire. La valeur de retour est le nombre de lignes affectées (supprimées ici).

IX-E - Transactions

Un petit mot sur la gestion des transactions, tout de même.

D'origine, le mode autocommit() est activé dans l'adaptateur, qui transmet donc cet état à PDO ; cela signifie que touterequête envoyée au SGBD est systématiquement validée. Bien entendu, pour utiliser les transactions, votre SGBDet votre moteur de stockage doivent pouvoir les gérer. C'est le cas d'INNODB pour MySQL et bientôt de MyISAM ;)

beginTransaction() Désactive l'autocommit et démarre une transaction

commit() Valide la transaction courante et réactive l'autocommit

rollback() Annule la transaction courante et réactive l'autocommit

Très simple, un exemple :

<?php$rows = array ( 'name' => 'John', 'country' => 'USA',);

$table = 'members';$db->beginTransaction();try { $db->insert($table, $rows); $db->commit();}catch(Zend_DB_Adapter_Exception $e){ $db->rollback(); echo $e->getMessage();}?>

IX-F - Sélections

Et maintenant, nous allons voir grâce à Zend_Db_Select comment effectuer des requêtes complexes (jointures,prédicats, etc.) sans écrire la moindre syntaxe SQL. Cependant, la rigueur reste de mise. Zend_Db_Select vapermettre d'écrire la syntaxe d'une requête SQL, manière objets, en s'affranchissant du SGBD utilisé en dessous :l'adapter va convertir la syntaxe objet en une syntaxe compréhensible pour le SGBD (car je rappelle que tous lesSGBD ne respectent pas forcément la norme SQL, et une syntaxe SQL [manuelle] peut donner lieu a des erreurssur un SGBD, mais pas sur un autre).

Essayons un "SELECT id, name FROM members WHERE country = 'usa' ORDER BY name ASC LIMIT 2" (syntaxeSQL pour MySQL - notre cas donc -).

select() permet d'écrire une requête de sélection complète, en utilisant un pourcentage infirme de langage SQL. Ellepermet aussi l'échappement automatique des caractères, elle gère tous les SGBD que gère l'Adapter, elle va traduirenotre requête façon objet en requête SQL compatible avec le SGBD interrogé via l'Adapter.

<?php$select = $db->select();$select->from('members',array('id','name'));

Page 27: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 27 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

$select->where('country = ?','usa');$select->order('name ASC');$select->limit(2);

$result = $db->fetchAll($select);?>

Bien entendu, les jointures sont possibles. En voici un exemple très simple (2 tables) :

<?php$select = $db->select();$select->from('messages','message_txt') ->join('members','members.id=messages.memberid','name') ->where('messages.id = :idmess');

$result = $db->fetchAll($select, array('idmess'=>2) );?>

"SELECT message_txt, name FROM messages JOIN members ON members.id=messages.memberid WHEREmessages.id = '2'" C'est la traduction MySQL.

C'est tout simple, j'ai changé aussi la manière d'interroger la base avec un binding, comme nous l'avons vu aupravant(le ':idmess'). C'est le cas le plus pratique, car il permet de passer la valeur lors de l'exécution de la requête et nondans son corps.

On peut effectuer tout type de jointure, joinLeft(), joinRight(), joinFull(), joinCross()(), joinNatural(). Les jointurespar défaut récupèrent *, mais on peut bien entendu les monter comme on le souhaite, de manière très propre. Ladoc officielle vous y aidera.

Les valeurs externes passées dans un select() sont toutes échappées automatiquement, pour éviter l'échappementautomatique, la classe Zend_Db_Expr permet de former une variable de clause non echappée.

La méthode select() crée un objet Zend_Db_Select qui retourne lui-même, à chaque modification, ce qui nous permetd'enchaîner les actions par de multiples -> se succédant.

Zend_Db_Select possède de même une méthode toString(), qui permet d'afficher la requête textuelle traduite parl'Adapter, par un simple <?php echo $select;?>. Utilisez-la pour bien voir comment la requête a été traduite (tout estéchappé, les colonnes sont traduites par 'table.colonne'...). Vous pouvez aussi demander à visualiser un élémentprécis de la requête.

getPart() retourne une partie précise de la requête, demandée via une constante de classe.

<?php$select = $db->select();$select->from('messages') ->order('id');

$orderClause = $select->getPart(Zend_Db_Select::ORDER); // 'id'?>

reset() efface une partie précise de la requête, demandée via une constante de classe, exactement comme la syntaxede getPart()

Un petit mot sur limitPage() : permet d'effectuer une pagination, avec sélection automatique de la tranche de résultat :

<?php

Page 28: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 28 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

$select = $db->select();$select->from('members', '*');$select->order('id DESC');

$select->limitPage(3, 10);$result = $db->fetchCol($select);?>

J'ai utilisé fetchCol() pour vous rappeler que vous pouvez utiliser n'importe quelle méthode de retour de résultat déjàvu. Ici, limitPage() demande sur la liste de tous les membres, organisée par id inverse, et de sélectionner pile labonne partie pour afficher la page 3, en ayant chaque contenant 10 résultats.

Zend_Db_Select possède encore having(), group(), distinct(), forUpdate()...

IX-G - Mapping Objet Relationnel

IX-G-1 - Généralites

Pour terminer, nous allons passer à la gestion de l'ORM (Mapping Objet Relationnel).

La version 0.9.0 a apporté un réel boost à l'ORM. L'utilisation se rapproche de celle de RubyOnRails. L'ORM est unepartie très importante dans la modélisation d'applications n-tiers.

Dans Zend_Framework, une couche d'ORM est prévue par défaut, mais toutes les classes mères sont abstraites.On pourra donc personnaliser entièrement les processus de mapping, si celui par défaut de ZF ne nous convientpas. Celui par défaut est Zend_Db_Table / Zend_Db_Table_Row / Zend_Db_Table_Rowset qui héritent deZend_Db_Table_Abstract / Zend_Db_Table_Row_Abstract / Zend_Db_Table_Rowset_Abstract.

Zend_Db_Table est la classe qui permet de faire de l'ORM : elle configure le mapping et elle effectue les requêtespersonnalisées. Par défaut, si aucune clé primaire n'est spécifiée, 'id' sera utilisée.

Ce schéma est modifiable. Toute table doit obligatoirement posséder une clé primaire sur au moins une colonne detable. En général, une table d'entités comporte une clé primaire, sur une colonne (il est de coutume de l'appeller 'id')qui est auto incrémentée. En revanche, les tables d'association peuvent avoir une une clé primaire sur une colonne,ou sur plusieurs, selon la cardinalité.

Un membre ne peut emprunter un même livre qu'une seule fois : dans la table emprunts, la clé primaire sera composéede la clé de la table membres et de la clé de la table livres. On s'assure ainsi qu'on ne peut enregistrer 2 fois le mêmemembre, empruntant un même livre.

Mais s'il existe plusieurs exemplaires de ce livre, alors on aura une clé primaire dans la table emprunts unique, enplus des 2 clé étrangères membres et livres. Un membre pourra donc emprunter plusieurs fois le même (exemplaire)du livre, chaque emprunts étant distingué par une clé unique sur une colonne.

Zend_Db_Table sert des objets ORM sur des Zend_Db_Table_Row. Ce sont les résultats mappés (propriétés =colonne de table). On les appellera les résultats.

Zend_Db_Table_Rowset est un conteneur de résultats pourvu d'un itérateur, on appellera ca un jeu de résultat(comparable au 'resultset' de java jdbc).

Page 29: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 29 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Un résultat ne comporte pas d'accesseurs : on modifie une propriété directement par affectation. Par contre desméthodes existent pour récupérer des références de tables, lorsque les tables sont liées entre elles par une intégritéréférencielle (clés étrangères).

Voici l'exemple utilisé ici, il est très simple,

IX-G-2 - L'exemple

CREATE TABLE `livres` ( `isbn` varchar(14) NOT NULL, `titre` varchar(70) NOT NULL, `auteur` varchar(70) NOT NULL, PRIMARY KEY (`isbn`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `livres` VALUES ('978-2212116762', 'Best Practices PHP5', 'Guillaume Ponçon');INSERT INTO `livres` VALUES ('978-2212120042', 'PHP5 Avancé', 'Cyril Pierre De Geyer');INSERT INTO `livres` VALUES ('978-2841773381', 'Pratique de MySQL et PHP (Broché) ', 'Philippe Rigaux');

CREATE TABLE `membres` ( `num` smallint(5) NOT NULL auto_increment, `nom` varchar(50) NOT NULL, `date_naissance` date NOT NULL, PRIMARY KEY (`num`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

INSERT INTO `membres` VALUES (1, 'julien', '1982-11-01');INSERT INTO `membres` VALUES (2, 'Benoit', '1984-02-08');INSERT INTO `membres` VALUES (3, 'Estelle', '1977-08-07');

CREATE TABLE `emprunts` ( `membre` smallint(5) NOT NULL, `livre` varchar(14) NOT NULL, `date` date NOT NULL, PRIMARY KEY (`livre`,`membre`), KEY `membre` (`membre`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

INSERT INTO `emprunts` VALUES (1, 1, '2007-03-24');INSERT INTO `emprunts` VALUES (2, 2, '2007-03-08');INSERT INTO `emprunts` VALUES (3, 1, '2007-04-02');

ALTER TABLE `emprunts` ADD CONSTRAINT `emprunts_ibfk_1` FOREIGN KEY (`membre`) REFERENCES `membres` (`num`) ON DELETE CASCADE ON UPDATE CASCADE, ADD CONSTRAINT `emprunts_ibfk_2` FOREIGN KEY (`livre`) REFERENCES `livres` (`isbn`) ON DELETE CASCADE ON UPDATE CASCADE;

Un exemple simple, comme celui décrit juste avant. Membres - Livres - Enprunts. Emprunts possède une clé primairesur 2 colonnes, on peut emprunter plusieurs fois le même exemplaire de livre, mais un même membre ne peutemprunter plusieurs fois un même livre (il ne peut posséder plusieurs exemplaires du même livre).

Page 30: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 30 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

La table emprunts répond donc à la question "qui a emprunté quoi, et quand ?"

Voici les fichiers de mapping des tables Membres et Livres, ils étendent Zend_Db_Table_Abstract. Si nous avionsvoulu retoucher le mécanisme interne du mapping, nous aurions étendu Zend_Db_Table, dans laquelle nous aurionsmodifier la logique (ce qui est très pratique pour personnaliser totallement son ORM).

On placera les fichiers de mapping, qui ne sont autre que notre logique métier, dans un répertoire /modele qui setrouvera hors racine web, car il n'a pas besoin de s'y trouver. On rajoutera simplement son chemin dans l'include_path,au début des scripts.

Comme je vous l'ai dit, je fonctionne dans cet article avec l'autoload activé, pour économiser des lignes. Toutes lesclasses sont supposées incluses et disponibles.

IX-G-3 - Définition du mapping

<?phpclass Membres extends Zend_Db_Table_Abstract{ protected $_name = 'Membres'; protected $_primary = 'num'; protected $_dependentTables = array('Emprunts'); public function findByNom($nom){ $where = $this->getAdapter()->quoteInto('nom = ?',(string)$nom); return $this->fetchRow($where); }}?>

<?php

class Livres extends Zend_Db_Table_Abstract{ protected $_name = 'Livres'; protected $_primary = 'isbn';

protected $_dependentTables = array('Emprunts');}

La variable $_name représente le nom de la table SQL, et la variable $_primary représente la clé primaire (c'estun array si la clé est multi-colonnes).

Ici, je les ai précisés, mais le mécanisme d'ORM de Zend Framework permet de s'en affranchir. Si on ne spécifiepas la clé primaire, ZF va utiliser DESCRIBE TABLE pour se la chercher lui-même. Si le nom de la table n'est pasprécisé, alors le nom de la classe sera utilisé.

Je conseille, ne serait-ce que pour y voir plus clair, de toujours spécifier la config de sa table dans la définition desa classe.

$_sequence est un booléen à true par défaut dans l'abstraction. Il signifie que nos clés primaires sont enauto-incrémentation, on ne le spécifie donc pas. Dans la version finale de ZF, il est prévu que des tables puissentne pas avoir de clé primaire.

Page 31: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 31 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Dans ce cas, la gestion de la clé primaire n'est pas laissée au SGBD mais à l'application. Si $_sequence est rempliavec un string, alors la classe va générer une valeur unique (non numérique) pour la colonne unique, qui s'insèreradans la base en faisant office de clé primaire.

Mettre $_sequence à la valeur false, permet à notre couche d'ORM de nous obliger à spécifier une clé primaire lorsd'une insertion (ce qui nous est interdit dans le cas contraire, par défaut).

Je répète que tout ce qui concerne $_sequence n'est pas encore pris en compte dans laversion actuelle du Framework (0.9.1).

$_dependentTables sert à lier les tables. Que ce soit Membres, ou Livres, elles sont toutes les 2 liées à Emprunts.Attention de bien passer le nom de la classe représentant la table (et non le nom de la table SQL), et de passer cecidans un array, et non un string, même s'il n'y a qu'une table dépendante.

En plus de ceci, les classes de table ont nécessairement besoin de notre adapter, rapellez vous notre objet $db quisert à manipuler la base au plus bas niveau. Forcément, les classes d'ORM en ont besoin, et plutôt que de le passeren paramètre aux objets à chaque fois, vu que nous n'utilisons qu'une seule base, et une seule connexion, nousallons dire à tout l'ORM que l'adapter par défaut est $db.

Dans le script principal, juste après avoir crée notre objet $db, nous le passons en adapter par défaut à l'ORM :

<?php// $params = ...try { $db = Zend_Db::factory('PDO_MYSQL', $params); $db->getConnection(); Zend_Db_Table::setDefaultAdapter($db); } catch (Zend_Db_Adapter_Exception $e){ echo $e->getMessage(); }?>

Zend_Db_Table::setDefaultAdapter($db); ca parle bien. L'adapter étant dirigé sur toutes nos classes ORM,poursuivons :

findByNom() est une méthode que j'ai écrite moi-même, elle va permettre de chercher des membres par leur nom.Regardez comment elle est écrite.

On récupère l'adapter, car c'est lui qui possède la méthode d'échappement quoteInto(). On échappe le paramètre,casté au préalable en string, et on envoie ca à fetchRow(). L'échappement des paramètres n'est pas autommatique,nous devons donc utiliser les méthodes quote(), quoteInto() ou quoteIdentifier(), de l'adapter. Nous les avons déjàvues.

Dans les classes métier, on définira donc toute la logique métier d'accès aux données (findByNom(), mais aussi desméthodes du style findLivreLePlusRecent(), ou encore findPaniersVides()...), et c'est le contrôleur qui accèdera àcette logique.

Outre les méthodes métier que nous pouvons écrire, il y en a déjà pas mal qui existent. Ainsi, sur des instances desclasses Membres ou Livres :

find() recherche des enregistrements par clé primaire. Vous récupérez un jeu de résultats (Rowset) contenant lesenregistrements correspondants. Si on passe à find() un tableau, alors on cherche plusieurs enregistrements :

<?php

Page 32: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 32 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

// ...$membre = new Membres();$membresTrouves = $membre->find(array(1,2));?>

fetchNew() retourne un résultat vide, prêt à etre rempli ou utilisé.

fetchAll() exécute une requête personnalisée, retournant un jeu de résultats (on choisira la méthode fetchAll()lorsqu'on sait que notre requête est susceptible de retourner plusieurs résultats).

fetchRow() exécute une requete personnalisée, retournant un résultat (on choisira la méthode fetchRow() lorsqu'onsait que notre requête ne retourne qu'un seul résultat ; s'il y en a plusieurs, elle ne retournera alors que le premierd'entre eux, attention).

getAdapter() retourne l'objet bas niveau de connexion attribué à la table.

info() retourne toute la configuration du mapping de la table, sur un array (clé primaire, colonnes, types de colonnes,tables dépendantes...)

getDependantTables() nous rapelle les tables dépendantes de l'objet, que nous avons configurées au préalable.

insert() et update, sont identiques à celles déjà vues mais mappées sur la table en cours (on ne spécifie pas latable, juste les paires colonnes->valeur).

<?phpclass Emprunts extends Zend_Db_Table_Abstract{ protected $_name = 'emprunts'; protected $_primary = array('membre','livre'); protected $_dependentTables = array('Membres','Livres'); protected $_referenceMap = array( 'emprunteur' => array( // le rôle UML de Membres vers Emprunts 'columns' => array('membre'),// la colonne de emprunts est membre 'refTableClass' => 'Membres', // la classe des membres est 'Membres' 'refColumns' => 'num' // la clé primaire de membres est num ), 'locations' => array( 'columns' => array('livre'), 'refTableClass' => 'Livres', 'refColumns' => 'isbn' ));}?>

La clé primaire d'emprunts est sur 2 colonnes. C'est spécifié par un array.

Emprunts est dépendante des tables membres et livres, mais je rapelle qu'on ne spécifie pas les tables dans$_dependentTables, mais les classes les représentant. Généralement celles ci commencent par une majuscule.

Vient ensuite la definition des références. C'est très important et indique la logique de notre base au Framework.

Page 33: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 33 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Pour les emprunts, dans la table emprunts, un membre est un emprunteur. C'est en fait le rôle UML qui relie les2 classes dans un Diagrammes de Classes de Conception. On fait référence à la classe Membres, et la colonneest num.

Il est possible qu'il y ait plusieurs colonnes (même si c'est rare). Lorsqu'on a plusieurs rôles, par exemple un membre

est l'emprunteur d'un livre mais il pourrait aussi être son auteur. On aurait alors une 2ème clé de membres dansemprunts, et on aurait par exemple matérialisé le rôle par "Auteur" ; en plus du rôle "emprunteur". Il y a autant derôles UML que de dépendances entre les tables.

Si la clé de référence est une clé sur plusieurs colonnes, on les spécifiera dans un array(), dans le même ordrequ'elles ont été définies dans la classe parent.

Si on ne spécifie pas la clé de la table parente (refColumns), alors la clé primaire déclarée est prise par défaut.Seulement, ce comportement bug actuellement, et j'ai envoyé un rapport de bug, ca sera corrigé dans la versionsuivante.

Je vous conseille quand même de spécifier la refColumns (même quand ca sera debbugué), je sais que lesprogrammeurs sont paresseux (Lazy), mais rien qu'en lisant la définition des références, on a tout de suite le schémade la base et des classes en visuel. C'est très agréable lorsqu'on reprend 1 an après le projet (même si on a commentéson code).

IX-G-4 - Les résultats (Row)

Nous venons de décrire les schémas de mapping de nos tables ainsi que la plupart des méthodes applicables surles classes de définition étendant Zend_Db_Table_Abstract. Lorsque nous cherchons un résultat (fetch***), selon laméthode utilisée, nous nous retrouverons avec soit une instance de Zend_Db_Table_Row (un résultat unique), soitune instance de Zend_Db_Table_Rowset_Abstract (un jeu de résultats uniques Zend_Db_Table_Row).

Par exemple, fetchNew() nous retourne un unique résultat, ce qui est logique ; en revanche, find() peut trouverplusieurs résultats. La méthode find() retourne donc un jeu de résultats, fetchAll() retourne un jeu, tandis quefetchRow() retourne un résultat. C'est très important car selon le type d'objet retourné, nous ne pourrons utiliser lesmêmes méthodes dessus. Si on nous retourne un jeu de résultat, on ne pourra pas appliquer les méthodes d'unrésultat dessus. Faites y attention, cela a tendance à embrouiller au début. Même si la logique est tout à fait de mise,il faut la comprendre, lorsqu'on y est pas habitué.

<?php// ...$tableMembre = new Membres();$julien = $tableMembre->findByNom('julien');$julien->date_naissance = '1982-12-08';$julien->save();?>

Sur un résultat, toutes les colonnes SQL sont mappées en tant que propriétés de l'objet. Attention, en utilisant PDO,le paramètre PDO::CASE_NATURAL lui est passé par Zend_Framework. Cela signifie que les échanges entre leSGBD et l'OS se font en casse naturelle. Ainsi sous Windows, et concernant MySQL (je n'ai pas d'infos pour d'autresSGBDs) la casse n'est pas existante, et une colonne appelé 'MACOLONNE', pourra être appelée via 'macolonne',mais pas sous Linux, qui respecte la casse. Il est conseillé de toujours appeler ses noms de tables/colonnes, enminuscules, pour éviter les ennuis de plateforme. Dans tous les cas, ZF utilise lui-même en interne la casse naturelle,il n'est donc pas possible de changer ce paramètre, et comme je vous l'ai dit, de manière générale, il vaut mieuxlaisser ZF gérer les paramètres PDO pour nous. Nous n'utilisons pas PDO nous programmeurs mais bel et bien leFramework qui, lui, utilise PDO comme il le souhaite.

Page 34: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 34 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Regardez, $julien->date_naissance signifie que j'accède à la colonne date_naissance du membre julien. Etant donnéqu'il n'y a pas d'accesseur (get(), set()), je la modifie directement et je sauvegarde le tout en base via la méthodesave().

Ainsi, sur un résultat, je peux aussi utiliser :

save() sauvegarde le résultat en base. Notez que si celui ci n'existe pas (issu d'un fetchNew(), par exemple) alorsune requête SQL "insert" sera utilisée, sinon "update" sera utilisé.

delete() efface le résultat en cours d'utilisation.

toArray() est très pratique et transforme le résultat en un tableau du type 'nom_de_la_colonne' =>'valeur-correspondante'.

setFromArray() est du même style, elle attribue des valeurs à notre objet suivant un tableau passé en paramètre dutype 'nom_de_la_colonne' => 'valeur-correspondante'. Ceci est très utilisé lors de récupération de formulaires, pourremplir rapidement un résultat et le sauvagarder.

D'autres méthodes find existent, décrites plus bas dans la section gestion des relations.

IX-G-5 - Les jeux de résultats (Rowset)

Certaines méthodes, donc, renvoient un jeu de résultats. Un jeu de résultats (Zend_Db_Table_Rowset) est un simpleconteneur de résultats implémentant les interfaces Iterator et Countable de la SPL. J'aurai aimé seekable aussi,mais ca n'est pas le cas.

Bref il s'agit d'un conteneur de résultats, itérable via un foreach et comportant toutes les méthodes héritées de la SPL(current(), count(), next()). Un genre de ResultSet, pour les habitués de Java ;-)

<?php// ...$tableLivres = new Livres();$deuxLivres = $tableLivres->find(array('978-2212116762','978-2841773381'));foreach ($deuxLivres AS $ceLivre){echo $ceLivre->titre.'<br />';}?>

Ici je récupère les 2 livres par leur clé primaires (Isbn), et j'affiche leur titre. Si je ne veux qu'un enregistrement, jeprocède comme suit :

<?php// ...$tableLivres = new Livres();$leLivre = $tableLivres->find('978-2212116762')->current();$leLivre->titre = 'Best Practices PHP 5';$leLivre->save();?>

Je suis obligé de spécifier que je veux dans le jeu de résultats le premier (et unique) résultat, en l'atteignant parcurrent(). Les autres méthodes d'accès proviennent de la SPL et d'Iterator.

En implémentant aussi Countable, j'ai accès à une méthode count() pour compter le nombre de résultats retournés :

Page 35: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 35 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

<?php// ...$tableLivres = new Livres();$lesLivres = $tableLivres->fetchAll();echo 'il y a actuellement '. $lesLivres->count() .' livres dans ma base de données';?>

Une méthode toArray(), comparable à celle d'un résultat, est disponible sur un jeu de résultats. Elle renvoie untableau multidimensionnel de résultats :

<?php// ...$tableLivres = new Livres();$tabLesLivres = $tableLivres->fetchAll()->toArray();/* $tabLesLivres contient :array(3) { [0] => array(3) { ["isbn"] => string(14) "978-2212116762" ["titre"] => string(20) "Best Practices PHP 5" ["auteur"] => string(16) "Guillaume Ponçon" } [1] => array(3) { ["isbn"] => string(14) "978-2212120042" ["titre"] => string(11) "PHP5 Avanc" ["auteur"] => string(21) "Cyril Pierre De Geyer" } [2] => array(3) { ["isbn"] => string(14) "978-2841773381" ["titre"] => string(34) "Pratique de MySQL et PHP (Broché) " ["auteur"] => string(15) "Philippe Rigaux" }}*/?>

IX-G-6 - Gestion des dépendances

Nous allons nous pencher sur la gestion des dépendances sous ZF. Si les termes 'Lazy mode', et 'full mode' vousdisent quelque chose, sachez que ZF est lazy. Lors de la récupération d'un enregistrement, il est possible de faireréférence à ses parents ou à ses enfants. Ce n'est que lors de l'appel de la référence que le résultat est chargé.

Si par exemple je récupère un membre, je peux facilement afficher les titres des livres qu'il emprunte. Ou encore,si j'ai un enregistrement représentant un 'emprunt', je peux retrouver, grâce à des méthodes spéciales, le membrey faisant référence ou bien le livre.

Zend Framework tire toute sa puissance de PHP5 et, grâce aux méthodes magiques __get, __set et surtout __call,il va intercepter les appels de méthodes pour nous, de manière très intuitive. Je vais vous donner un exemple. Avanttoute chose, sachez que ces méthodes ne s'appliquent que sur un résultat. On ne peut les appliquer sur des instancesde jeu de résultats, ce qui est logique.

Je récupère un membre, et je veux lister tous les livres qu'il a emprunté :

<?php// ...$tblMembres = new Membres();$monMembre = $tblMembres->find(1)->current();$sesLivres = $monMembre->findLivresViaEmprunts();foreach ($sesLivres AS $unDeSesLivres){ echo $unDeSesLivres->titre.'<br />';}

Page 36: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 36 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

?>

J'instancie ma table membres. Je récupère le membre n°=1, n'oubliez pas que le retour de find()est systématiquement un jeu de résultat (Rowset), je dois donc passer par current() (méthode deZend_Db_Table_Rowset_Absract) pour récupérer mon résultat.

Sur un résultat, je peux trouver ses dépendances par rôle. En effet, Zend_Db_Table_Row est doté d'une méthodemagique, qui va intercepter les appels du style find<tableClass>Via<IntersectionTableClass>().

$monMembre->findLivresViaEmprunts retourne donc un jeu de résultats représentant tous les livres - empruntés parmonMembre. Le foreach est un itérateur, n'oubliez pas $sesLivres est un jeu de résultats : en itérant dessus, onrécupère des résultats représentatifs de livres. Sur ces résultats, nous avons accès aux propriétés de l'objet, ici c'esttitre qui nous intéresse.

find<tableClass>Via<IntersectionTableClass>() récupère un jeu de résultats dans un schéma àcardinalités de type 'plusieurs à plusieurs'. C'est un raccourci de commodité de la méthodefindManyToManyRowset('tableClass','tableClass', 'role'). Pensez bien cardinalités dans un modèle conceptuel.Un membre peut emprunter zéro ou plusieurs livres. Un livre peut être emprunté par zéro ou plusieurs membres(on a dit qu'on raisonnait de cette manière, par 'exemplaires'). C'est une association plusieurs vers plusieurs, qui setraduit par une table de liaison, 'emprunts'.

Si maintenant j'ai un livre, et que je veux lister toutes les dates auxquelles il a été emprunté, je procède comme suit :

<?php// ...$tblLivres = new Livres();$monLivre = $tblLivres->find('978-2841773381')->current();$sesEmprunts = $monLivre->findEmprunts();foreach ($sesEmprunts AS $unDeSesEmprunts){ echo $unDeSesEmprunts->date.'<br />';}?>

find<tableClass>() récupère un jeu de résultats d'une table dépendante, dans un schéma '1 à plusieurs'. C'estun raccourci de commodité de la méthode findDependentRowset('tableClass','role'). 1 livre peut avoir plusieursréférences dans la table emprunts, nous récupérons donc un jeu de résultats sur lequel nous itérons.

Agissons enfin dans le dernier sens : nous avons un résultat de type emprunts, et nous voulons connaître le nomdu membre à qui il appartient :

<?php// ...$tblEmprunts = new Emprunts();$monEmprunt = $tblEmprunts->find('2','978-2841773381')->current();echo $monEmprunt->findParentMembres()->nom.'<br />';?>

findParent<tableClass>() récupère un jeu de résultats d'une table parente. C'est un raccourci de commodité de laméthode findParentRow('tableClass','role'). De type '1 à 1' (1 emprunt donné ne fait référence qu'à un membre),nous récupérons un unique résultat, sur un Row donc.

Je n'ai pas parlé des rôles mais il est possible d'y faire référence. Si par exemple un membre emprunteun livre mais peut aussi être son auteur, alors lister les livres écrits par un membre se fera de la manière$leMembre->findLivresViaEmpruntsByAuteur().

Page 37: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 37 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

Tout est automatique, Zend Framework se charge pour nous de faire les jointures nécessaires. Je n'ai pas non plustesté les résultats de mes requêtes : un find(), peut par exemple ne retourner aucun résultat, à vous de le gérer.

Idem pour l'effet de cascade des SGBDs. ZF inclue un système de cascade, qui permet d'agir à la manière d'unSGBD, en actionnant en cascade les résultats (DELETE ou UPDATE) : je n'en parle pas ici, car la gestion de l'intégritéde la base doit être laissée à la charge du SGBDR et non de l'application qui tourne dessus. Le staff de ZF nous leprécise clairement : se reposer sur la gestion de l'intégrité référencielle via ZF n'est pas recommandé et peut mener àdes comportements hasardeux. Mes tables sont au format Innodb, un format de table gérant les relations et l'intégrité,je ne m'occupe en rien de cela dans mon code applicatif.

Page 38: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 38 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/

X - Conclusion - Annexes

X-A - Le mot de la fin

Voilà, cet article d'introduction est terminé, il sera complété par d'autres exemples concrets introduisant notammentla gestion MVC. Notez que j'ai facilité l'accès aux codes d'exemple dans cet article. Je n'ai pas pris en compte lesaspects sécurité, j'ai fait des sous-entendus, je n'ai presque pas utilisé les exceptions, etc. Dans des cas concrets,il y a bien entendu plus de travail à fournir que ce qui est écrit ici.

Ici, c'est un avant-goût, Zend Framework comporte beaucoup d'outils et son développement est en perpétuelleévolution.

J'espère vous avoir un peu éclairé sur ce Framework qui, à ses débuts (à peine 10 packages), était facile à intégrer.À présent, avec 40 packages, il l'est beaucoup moins, mais est destiné d'ores et déjà à un bel avenir dans ledéveloppement méthodique d'applications PHP.

X-A - Annexes : Schémas UML des packages étudiés

Zend_Config

Zend_Db

Zend_Debug

Zend_Filter

Zend_Loader

Zend_Registry

Zend_Validate

Zend_Version

Zend_View

Page 39: Framework - Premiers pas Présentation du Zend · connecteurs vers des bases de données et support de MVC... ... (POO), de bonnes notions ... Zend Framework requiert PHP 5.1.4 minimum,

Présentation du Zend Framework - Premiers pas par Julien Pauli (Tutoriels, conférences PHP) (Blog)

- 39 -Copyright © 2007 - Julien Pauli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 Ede domages et intérêts.

http://julien-pauli.developpez.com/tutoriels/zend-framework/presentation/